From 1ccb6a868b8b759fe0f77ed5eb55f04a1d1163af Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 14 Nov 2023 11:19:38 -0800 Subject: [PATCH 001/127] Remove badly formatted line PiperOrigin-RevId: 582384359 --- doc/g_stands_for.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/g_stands_for.md b/doc/g_stands_for.md index 33267f9a111bc..830257c29cd74 100644 --- a/doc/g_stands_for.md +++ b/doc/g_stands_for.md @@ -61,4 +61,4 @@ - 1.59 'g' stands for ['generative'](https://github.com/grpc/grpc/tree/v1.59.x) - 1.60 'g' stands for ['gjallarhorn'](https://github.com/grpc/grpc/tree/v1.60.x) - 1.61 'g' stands for ['grand'](https://github.com/grpc/grpc/tree/master) -- 1.62 'g' stats for 'guitar' +- 1.62 'g' stands for 'guitar' From e884d6c190773dafda7a0760be2c8020c4e76873 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 14 Nov 2023 12:32:15 -0800 Subject: [PATCH 002/127] Remove test code PiperOrigin-RevId: 582406922 --- doc/g_stands_for.md | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/g_stands_for.md b/doc/g_stands_for.md index 830257c29cd74..6c4ab1010817c 100644 --- a/doc/g_stands_for.md +++ b/doc/g_stands_for.md @@ -61,4 +61,3 @@ - 1.59 'g' stands for ['generative'](https://github.com/grpc/grpc/tree/v1.59.x) - 1.60 'g' stands for ['gjallarhorn'](https://github.com/grpc/grpc/tree/v1.60.x) - 1.61 'g' stands for ['grand'](https://github.com/grpc/grpc/tree/master) -- 1.62 'g' stands for 'guitar' From f11c010e5183125c0cd09e4c12f31222d9bb0fb2 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 14 Nov 2023 14:58:29 -0800 Subject: [PATCH 003/127] [promises] Add awaitable spawn to Party (#34744) Add a variant of `Spawn` that returns a promise that can be awaited by another activity. This allows us to simply implement complex cross-activity synchronization. (necessary building block for #34740) Also adds an inter-activity latch as a building block to test this work. Closes #34744 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/34744 from ctiller:ninteen-ninety-nine 19074b255f335a9b02fc43d469190fa8868af3b4 PiperOrigin-RevId: 582450643 --- CMakeLists.txt | 34 ++++++ build_autogenerated.yaml | 18 ++- src/core/BUILD | 20 ++++ src/core/lib/promise/activity.cc | 19 +++- src/core/lib/promise/activity.h | 9 +- src/core/lib/promise/inter_activity_latch.h | 98 +++++++++++++++++ src/core/lib/promise/latch.h | 7 +- src/core/lib/promise/party.cc | 2 +- src/core/lib/promise/party.h | 103 +++++++++++++++++- src/core/lib/promise/wait_set.h | 6 + test/core/promise/BUILD | 22 ++++ .../core/promise/inter_activity_latch_test.cc | 103 ++++++++++++++++++ test/core/promise/party_test.cc | 26 +++++ tools/run_tests/generated/tests.json | 24 ++++ 14 files changed, 478 insertions(+), 13 deletions(-) create mode 100644 src/core/lib/promise/inter_activity_latch.h create mode 100644 test/core/promise/inter_activity_latch_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index bd6a8691f5626..4c8979a56ec45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1109,6 +1109,7 @@ if(gRPC_BUILD_TESTS) add_dependencies(buildtests_cxx init_test) add_dependencies(buildtests_cxx initial_settings_frame_bad_client_test) add_dependencies(buildtests_cxx insecure_security_connector_test) + add_dependencies(buildtests_cxx inter_activity_latch_test) add_dependencies(buildtests_cxx inter_activity_pipe_test) add_dependencies(buildtests_cxx interceptor_list_test) add_dependencies(buildtests_cxx interop_client) @@ -14936,6 +14937,39 @@ target_link_libraries(insecure_security_connector_test ) +endif() +if(gRPC_BUILD_TESTS) + +add_executable(inter_activity_latch_test + test/core/promise/inter_activity_latch_test.cc +) +target_compile_features(inter_activity_latch_test PUBLIC cxx_std_14) +target_include_directories(inter_activity_latch_test + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + ${_gRPC_RE2_INCLUDE_DIR} + ${_gRPC_SSL_INCLUDE_DIR} + ${_gRPC_UPB_GENERATED_DIR} + ${_gRPC_UPB_GRPC_GENERATED_DIR} + ${_gRPC_UPB_INCLUDE_DIR} + ${_gRPC_XXHASH_INCLUDE_DIR} + ${_gRPC_ZLIB_INCLUDE_DIR} + third_party/googletest/googletest/include + third_party/googletest/googletest + third_party/googletest/googlemock/include + third_party/googletest/googlemock + ${_gRPC_PROTO_GENS_DIR} +) + +target_link_libraries(inter_activity_latch_test + ${_gRPC_ALLTARGETS_LIBRARIES} + gtest + grpc +) + + endif() if(gRPC_BUILD_TESTS) diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index f437de380a704..bd2a9aa0bbd76 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -10835,6 +10835,20 @@ targets: deps: - gtest - grpc_test_util +- name: inter_activity_latch_test + gtest: true + build: test + language: c++ + headers: + - src/core/lib/promise/event_engine_wakeup_scheduler.h + - src/core/lib/promise/inter_activity_latch.h + - src/core/lib/promise/wait_set.h + src: + - test/core/promise/inter_activity_latch_test.cc + deps: + - gtest + - grpc + uses_polling: false - name: inter_activity_pipe_test gtest: true build: test @@ -12434,7 +12448,9 @@ targets: gtest: true build: test language: c++ - headers: [] + headers: + - src/core/lib/promise/inter_activity_latch.h + - src/core/lib/promise/wait_set.h src: - test/core/promise/party_test.cc deps: diff --git a/src/core/BUILD b/src/core/BUILD index 3df1d40375b88..cbf8ed32ea00c 100644 --- a/src/core/BUILD +++ b/src/core/BUILD @@ -478,6 +478,7 @@ grpc_cc_library( "arena", "construct_destruct", "context", + "poll", "promise_factory", "promise_trace", "ref_counted", @@ -874,6 +875,25 @@ grpc_cc_library( ], ) +grpc_cc_library( + name = "inter_activity_latch", + external_deps = [ + "absl/base:core_headers", + "absl/strings", + ], + language = "c++", + public_hdrs = [ + "lib/promise/inter_activity_latch.h", + ], + deps = [ + "activity", + "poll", + "promise_trace", + "wait_set", + "//:gpr", + ], +) + grpc_cc_library( name = "interceptor_list", hdrs = [ diff --git a/src/core/lib/promise/activity.cc b/src/core/lib/promise/activity.cc index 7beaeb1c7040d..60024b536cb67 100644 --- a/src/core/lib/promise/activity.cc +++ b/src/core/lib/promise/activity.cc @@ -25,7 +25,6 @@ #include "absl/strings/str_join.h" #include "src/core/lib/gprpp/atomic_utils.h" -#include "src/core/lib/gprpp/crash.h" namespace grpc_core { @@ -84,7 +83,23 @@ class FreestandingActivity::Handle final : public Wakeable { } void WakeupAsync(WakeupMask) override ABSL_LOCKS_EXCLUDED(mu_) { - Crash("not implemented"); + mu_.Lock(); + // Note that activity refcount can drop to zero, but we could win the lock + // against DropActivity, so we need to only increase activities refcount if + // it is non-zero. + if (activity_ && activity_->RefIfNonzero()) { + FreestandingActivity* activity = activity_; + mu_.Unlock(); + // Activity still exists and we have a reference: wake it up, which will + // drop the ref. + activity->WakeupAsync(0); + } else { + // Could not get the activity - it's either gone or going. No need to wake + // it up! + mu_.Unlock(); + } + // Drop the ref to the handle (we have one ref = one wakeup semantics). + Unref(); } void Drop(WakeupMask) override { Unref(); } diff --git a/src/core/lib/promise/activity.h b/src/core/lib/promise/activity.h index 4325207d93dc7..a05ddab8afb8e 100644 --- a/src/core/lib/promise/activity.h +++ b/src/core/lib/promise/activity.h @@ -32,7 +32,6 @@ #include #include "src/core/lib/gprpp/construct_destruct.h" -#include "src/core/lib/gprpp/crash.h" #include "src/core/lib/gprpp/no_destruct.h" #include "src/core/lib/gprpp/orphanable.h" #include "src/core/lib/gprpp/sync.h" @@ -502,7 +501,7 @@ class PromiseActivity final // the activity to an external threadpool to run. If the activity is already // running on this thread, a note is taken of such and the activity is // repolled if it doesn't complete. - void Wakeup(WakeupMask) final { + void Wakeup(WakeupMask m) final { // If there is an active activity, but hey it's us, flag that and we'll loop // in RunLoop (that's calling from above here!). if (Activity::is_current()) { @@ -511,6 +510,10 @@ class PromiseActivity final WakeupComplete(); return; } + WakeupAsync(m); + } + + void WakeupAsync(WakeupMask) final { if (!wakeup_scheduled_.exchange(true, std::memory_order_acq_rel)) { // Can't safely run, so ask to run later. this->ScheduleWakeup(); @@ -520,8 +523,6 @@ class PromiseActivity final } } - void WakeupAsync(WakeupMask) final { Crash("not implemented"); } - // Drop a wakeup void Drop(WakeupMask) final { this->WakeupComplete(); } diff --git a/src/core/lib/promise/inter_activity_latch.h b/src/core/lib/promise/inter_activity_latch.h new file mode 100644 index 0000000000000..8c31c8a162542 --- /dev/null +++ b/src/core/lib/promise/inter_activity_latch.h @@ -0,0 +1,98 @@ +// Copyright 2021 gRPC authors. +// +// Licensed 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 GRPC_SRC_CORE_LIB_PROMISE_INTER_ACTIVITY_LATCH_H +#define GRPC_SRC_CORE_LIB_PROMISE_INTER_ACTIVITY_LATCH_H + +#include + +#include + +#include + +#include "absl/base/thread_annotations.h" +#include "absl/strings/str_cat.h" + +#include + +#include "src/core/lib/gprpp/sync.h" +#include "src/core/lib/promise/activity.h" +#include "src/core/lib/promise/poll.h" +#include "src/core/lib/promise/trace.h" +#include "src/core/lib/promise/wait_set.h" + +namespace grpc_core { + +// A latch providing true cross activity wakeups +template +class InterActivityLatch; + +template <> +class InterActivityLatch { + public: + InterActivityLatch() = default; + InterActivityLatch(const InterActivityLatch&) = delete; + InterActivityLatch& operator=(const InterActivityLatch&) = delete; + + // Produce a promise to wait for this latch. + auto Wait() { + return [this]() -> Poll { + MutexLock lock(&mu_); + if (grpc_trace_promise_primitives.enabled()) { + gpr_log(GPR_INFO, "%sPollWait %s", DebugTag().c_str(), + StateString().c_str()); + } + if (is_set_) { + return Empty{}; + } else { + return waiters_.AddPending(Activity::current()->MakeNonOwningWaker()); + } + }; + } + + // Set the latch. + void Set() { + MutexLock lock(&mu_); + if (grpc_trace_promise_primitives.enabled()) { + gpr_log(GPR_INFO, "%sSet %s", DebugTag().c_str(), StateString().c_str()); + } + is_set_ = true; + waiters_.WakeupAsync(); + } + + bool IsSet() const ABSL_LOCKS_EXCLUDED(mu_) { + MutexLock lock(&mu_); + return is_set_; + } + + private: + std::string DebugTag() { + return absl::StrCat(Activity::current()->DebugTag(), + " INTER_ACTIVITY_LATCH[0x", + reinterpret_cast(this), "]: "); + } + + std::string StateString() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_) { + return absl::StrCat("is_set:", is_set_); + } + + mutable Mutex mu_; + // True if we have a value set, false otherwise. + bool is_set_ = false; + WaitSet waiters_ ABSL_GUARDED_BY(mu_); +}; + +} // namespace grpc_core + +#endif // GRPC_SRC_CORE_LIB_PROMISE_INTER_ACTIVITY_LATCH_H diff --git a/src/core/lib/promise/latch.h b/src/core/lib/promise/latch.h index a8f911809f5ee..4ade84b893992 100644 --- a/src/core/lib/promise/latch.h +++ b/src/core/lib/promise/latch.h @@ -37,6 +37,7 @@ namespace grpc_core { // Initially the Latch is unset. // It can be waited upon by the Wait method, which produces a Promise that // resolves when the Latch is Set to a value of type T. +// Latches only work correctly within a single activity. template class Latch { public: @@ -204,6 +205,9 @@ class Latch { IntraActivityWaiter waiter_; }; +template +using LatchWaitPromise = decltype(std::declval>().Wait()); + // A Latch that can have its value observed by outside threads, but only waited // upon from inside a single activity. template @@ -268,9 +272,6 @@ class ExternallyObservableLatch { IntraActivityWaiter waiter_; }; -template -using LatchWaitPromise = decltype(std::declval>().Wait()); - } // namespace grpc_core #endif // GRPC_SRC_CORE_LIB_PROMISE_LATCH_H diff --git a/src/core/lib/promise/party.cc b/src/core/lib/promise/party.cc index 040afbfe9a3b2..275d06445a426 100644 --- a/src/core/lib/promise/party.cc +++ b/src/core/lib/promise/party.cc @@ -247,7 +247,7 @@ bool Party::RunParty() { } // Poll the participant. currently_polling_ = i; - bool done = participant->Poll(); + bool done = participant->PollParticipantPromise(); currently_polling_ = kNotPolling; if (done) { if (!name.empty()) { diff --git a/src/core/lib/promise/party.h b/src/core/lib/promise/party.h index 493a00925d1f1..1ff098f3aa309 100644 --- a/src/core/lib/promise/party.h +++ b/src/core/lib/promise/party.h @@ -24,6 +24,7 @@ #include #include +#include "absl/base/attributes.h" #include "absl/base/thread_annotations.h" #include "absl/strings/string_view.h" @@ -38,6 +39,7 @@ #include "src/core/lib/promise/activity.h" #include "src/core/lib/promise/context.h" #include "src/core/lib/promise/detail/promise_factory.h" +#include "src/core/lib/promise/poll.h" #include "src/core/lib/promise/trace.h" #include "src/core/lib/resource_quota/arena.h" @@ -298,7 +300,7 @@ class Party : public Activity, private Wakeable { explicit Participant(absl::string_view name) : name_(name) {} // Poll the participant. Return true if complete. // Participant should take care of its own deallocation in this case. - virtual bool Poll() = 0; + virtual bool PollParticipantPromise() = 0; // Destroy the participant before finishing. virtual void Destroy() = 0; @@ -330,6 +332,9 @@ class Party : public Activity, private Wakeable { void Spawn(absl::string_view name, Factory promise_factory, OnComplete on_complete); + template + auto SpawnWaitable(absl::string_view name, Factory factory); + void Orphan() final { Crash("unused"); } // Activity implementation: not allowed to be overridden by derived types. @@ -414,7 +419,7 @@ class Party : public Activity, private Wakeable { } } - bool Poll() override { + bool PollParticipantPromise() override { if (!started_) { auto p = factory_.Make(); Destruct(&factory_); @@ -441,6 +446,89 @@ class Party : public Activity, private Wakeable { bool started_ = false; }; + template + class PromiseParticipantImpl final + : public RefCounted, + NonPolymorphicRefCount>, + public Participant { + using Factory = promise_detail::OncePromiseFactory; + using Promise = typename Factory::Promise; + using Result = typename Promise::Result; + + public: + PromiseParticipantImpl(absl::string_view name, + SuppliedFactory promise_factory) + : Participant(name) { + Construct(&factory_, std::move(promise_factory)); + } + + ~PromiseParticipantImpl() { + switch (state_.load(std::memory_order_acquire)) { + case State::kFactory: + Destruct(&factory_); + break; + case State::kPromise: + Destruct(&promise_); + break; + case State::kResult: + Destruct(&result_); + break; + } + } + + // Inside party poll: drive from factory -> promise -> result + bool PollParticipantPromise() override { + switch (state_.load(std::memory_order_relaxed)) { + case State::kFactory: { + auto p = factory_.Make(); + Destruct(&factory_); + Construct(&promise_, std::move(p)); + state_.store(State::kPromise, std::memory_order_relaxed); + } + ABSL_FALLTHROUGH_INTENDED; + case State::kPromise: { + auto p = promise_(); + if (auto* r = p.value_if_ready()) { + Destruct(&promise_); + Construct(&result_, std::move(*r)); + state_.store(State::kResult, std::memory_order_release); + waiter_.Wakeup(); + this->Unref(); + return true; + } + return false; + } + case State::kResult: + Crash( + "unreachable: promises should not be repolled after completion"); + } + } + + // Outside party poll: check whether the spawning party has completed this + // promise. + Poll PollCompletion() { + switch (state_.load(std::memory_order_acquire)) { + case State::kFactory: + case State::kPromise: + return Pending{}; + case State::kResult: + return std::move(result_); + } + } + + void Destroy() override { this->Unref(); } + + private: + enum class State : uint8_t { kFactory, kPromise, kResult }; + union { + GPR_NO_UNIQUE_ADDRESS Factory factory_; + GPR_NO_UNIQUE_ADDRESS Promise promise_; + GPR_NO_UNIQUE_ADDRESS Result result_; + }; + Waker waiter_{Activity::current()->MakeOwningWaker()}; + std::atomic state_{State::kFactory}; + }; + // Notification that the party has finished and this instance can be deleted. // Derived types should arrange to call CancelRemainingParticipants during // this sequence. @@ -502,6 +590,17 @@ void Party::Spawn(absl::string_view name, Factory promise_factory, std::move(on_complete)); } +template +auto Party::SpawnWaitable(absl::string_view name, Factory promise_factory) { + auto participant = MakeRefCounted>( + name, std::move(promise_factory)); + Participant* p = participant->Ref().release(); + AddParticipants(&p, 1); + return [participant = std::move(participant)]() mutable { + return participant->PollCompletion(); + }; +} + } // namespace grpc_core #endif // GRPC_SRC_CORE_LIB_PROMISE_PARTY_H diff --git a/src/core/lib/promise/wait_set.h b/src/core/lib/promise/wait_set.h index 2f978e5750ade..bf1adc6c1c299 100644 --- a/src/core/lib/promise/wait_set.h +++ b/src/core/lib/promise/wait_set.h @@ -69,6 +69,12 @@ class WaitSet final { return ret; } + void WakeupAsync() { + while (!pending_.empty()) { + pending_.extract(pending_.begin()).value().WakeupAsync(); + } + } + private: // Handles to activities that need to be awoken. WakerSet pending_; diff --git a/test/core/promise/BUILD b/test/core/promise/BUILD index 5073d060b01d2..2370dfdc4a79b 100644 --- a/test/core/promise/BUILD +++ b/test/core/promise/BUILD @@ -419,6 +419,27 @@ grpc_cc_test( ], ) +grpc_cc_test( + name = "inter_activity_latch_test", + srcs = ["inter_activity_latch_test.cc"], + external_deps = [ + "absl/status", + "gtest", + ], + language = "c++", + tags = ["promise_test"], + uses_event_engine = False, + uses_polling = False, + deps = [ + "//:grpc", + "//src/core:default_event_engine", + "//src/core:event_engine_wakeup_scheduler", + "//src/core:inter_activity_latch", + "//src/core:notification", + "//src/core:seq", + ], +) + grpc_cc_test( name = "mpsc_test", srcs = ["mpsc_test.cc"], @@ -591,6 +612,7 @@ grpc_cc_test( "//src/core:context", "//src/core:default_event_engine", "//src/core:event_engine_memory_allocator", + "//src/core:inter_activity_latch", "//src/core:memory_quota", "//src/core:notification", "//src/core:poll", diff --git a/test/core/promise/inter_activity_latch_test.cc b/test/core/promise/inter_activity_latch_test.cc new file mode 100644 index 0000000000000..087489b240e94 --- /dev/null +++ b/test/core/promise/inter_activity_latch_test.cc @@ -0,0 +1,103 @@ +// Copyright 2023 gRPC authors. +// +// Licensed 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. + +#include "src/core/lib/promise/inter_activity_latch.h" + +#include "absl/status/status.h" +#include "gtest/gtest.h" + +#include + +#include "src/core/lib/event_engine/default_event_engine.h" +#include "src/core/lib/gprpp/notification.h" +#include "src/core/lib/promise/event_engine_wakeup_scheduler.h" +#include "src/core/lib/promise/seq.h" + +using grpc_event_engine::experimental::GetDefaultEventEngine; + +namespace grpc_core { +namespace { + +TEST(InterActivityLatchTest, Works) { + InterActivityLatch latch; + + // Start some waiting activities + Notification n1; + auto a1 = MakeActivity( + [&] { + return Seq(latch.Wait(), [&](Empty) { + n1.Notify(); + return absl::OkStatus(); + }); + }, + EventEngineWakeupScheduler{GetDefaultEventEngine()}, [](absl::Status) {}); + Notification n2; + auto a2 = MakeActivity( + [&] { + return Seq(latch.Wait(), [&](Empty) { + n2.Notify(); + return absl::OkStatus(); + }); + }, + EventEngineWakeupScheduler{GetDefaultEventEngine()}, [](absl::Status) {}); + Notification n3; + auto a3 = MakeActivity( + [&] { + return Seq(latch.Wait(), [&](Empty) { + n3.Notify(); + return absl::OkStatus(); + }); + }, + EventEngineWakeupScheduler{GetDefaultEventEngine()}, [](absl::Status) {}); + + ASSERT_FALSE(n1.HasBeenNotified()); + ASSERT_FALSE(n2.HasBeenNotified()); + ASSERT_FALSE(n3.HasBeenNotified()); + + // Start a setting activity + auto kicker = MakeActivity( + [&] { + latch.Set(); + return absl::OkStatus(); + }, + EventEngineWakeupScheduler{GetDefaultEventEngine()}, [](absl::Status) {}); + + // Start another waiting activity + Notification n4; + auto a4 = MakeActivity( + [&] { + return Seq(latch.Wait(), [&](Empty) { + n4.Notify(); + return absl::OkStatus(); + }); + }, + EventEngineWakeupScheduler{GetDefaultEventEngine()}, [](absl::Status) {}); + + // Everything should finish + n1.WaitForNotification(); + n2.WaitForNotification(); + n3.WaitForNotification(); + n4.WaitForNotification(); +} + +} // namespace +} // namespace grpc_core + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + grpc_init(); // for GetDefaultEventEngine + int r = RUN_ALL_TESTS(); + grpc_shutdown(); + return r; +} diff --git a/test/core/promise/party_test.cc b/test/core/promise/party_test.cc index a15b10a985b1c..551443ac4d5e7 100644 --- a/test/core/promise/party_test.cc +++ b/test/core/promise/party_test.cc @@ -36,6 +36,7 @@ #include "src/core/lib/gprpp/time.h" #include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/promise/context.h" +#include "src/core/lib/promise/inter_activity_latch.h" #include "src/core/lib/promise/poll.h" #include "src/core/lib/promise/seq.h" #include "src/core/lib/promise/sleep.h" @@ -298,6 +299,31 @@ TEST_F(PartyTest, CanSpawnAndRun) { n.WaitForNotification(); } +TEST_F(PartyTest, CanSpawnWaitableAndRun) { + auto party1 = MakeRefCounted(); + auto party2 = MakeRefCounted(); + Notification n; + InterActivityLatch done; + // Spawn a task on party1 that will wait for a task on party2. + // The party2 task will wait on the latch `done`. + party1->Spawn( + "party1_main", + [&party2, &done]() { + return party2->SpawnWaitable("party2_main", + [&done]() { return done.Wait(); }); + }, + [&n](Empty) { n.Notify(); }); + ASSERT_FALSE(n.HasBeenNotified()); + party1->Spawn( + "party1_notify_latch", + [&done]() { + done.Set(); + return Empty{}; + }, + [](Empty) {}); + n.WaitForNotification(); +} + TEST_F(PartyTest, CanSpawnFromSpawn) { auto party = MakeRefCounted(); Notification n1; diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index f84a171ea9f97..35bdddc0eb0b4 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -4987,6 +4987,30 @@ ], "uses_polling": true }, + { + "args": [], + "benchmark": false, + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": true, + "language": "c++", + "name": "inter_activity_latch_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "uses_polling": false + }, { "args": [], "benchmark": false, From cb21299ea33644370c300145e192d8ac8a26015d Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 14 Nov 2023 21:37:39 -0800 Subject: [PATCH 004/127] Internal change PiperOrigin-RevId: 582536567 --- OWNERS | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 OWNERS diff --git a/OWNERS b/OWNERS deleted file mode 100644 index cdbc4bec0edb1..0000000000000 --- a/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -# Top level ownership -@markdroth **/OWNERS -@a11r **/OWNERS From bb7be1967f00d68bb0ede2cbb29a5e8beb1f1151 Mon Sep 17 00:00:00 2001 From: Esun Kim Date: Wed, 15 Nov 2023 11:41:41 -0800 Subject: [PATCH 005/127] Internal change PiperOrigin-RevId: 582751142 --- .../windows/pull_request/grpc_distribtests_cpp_dll.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/internal_ci/windows/pull_request/grpc_distribtests_cpp_dll.cfg b/tools/internal_ci/windows/pull_request/grpc_distribtests_cpp_dll.cfg index b673e13ba11f5..32cb3c2544d16 100644 --- a/tools/internal_ci/windows/pull_request/grpc_distribtests_cpp_dll.cfg +++ b/tools/internal_ci/windows/pull_request/grpc_distribtests_cpp_dll.cfg @@ -15,7 +15,7 @@ # Config file for the internal CI (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc/tools/internal_ci/windows/grpc_distribtests_standalone.bat" +build_file: "grpc/tools/internal_ci/windows/grpc_distribtests_cpp_dll.bat" timeout_mins: 120 action { define_artifacts { From 59408f12857c269b6a28ce863ac7086f8ce5b4a6 Mon Sep 17 00:00:00 2001 From: AJ Heller Date: Wed, 15 Nov 2023 13:03:54 -0800 Subject: [PATCH 006/127] [EventEngine] Use EventEngine::Run for TimerManager's MainLoop (#34705) Closes #34705 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/34705 from drfloob:timer-mgr-on-ee-alt 070118e3f1ae42e5ec9933d327ab170653f65594 PiperOrigin-RevId: 582778797 --- .../posix_engine/timer_manager.cc | 44 +++++++------------ .../event_engine/posix_engine/timer_manager.h | 3 -- 2 files changed, 17 insertions(+), 30 deletions(-) diff --git a/src/core/lib/event_engine/posix_engine/timer_manager.cc b/src/core/lib/event_engine/posix_engine/timer_manager.cc index 2962f7a2eb990..4df2dc7ba2803 100644 --- a/src/core/lib/event_engine/posix_engine/timer_manager.cc +++ b/src/core/lib/event_engine/posix_engine/timer_manager.cc @@ -30,7 +30,6 @@ #include #include "src/core/lib/debug/trace.h" -#include "src/core/lib/gprpp/thd.h" static thread_local bool g_timer_thread; @@ -67,41 +66,32 @@ bool TimerManager::WaitUntil(grpc_core::Timestamp next) { } void TimerManager::MainLoop() { - for (;;) { - grpc_core::Timestamp next = grpc_core::Timestamp::InfFuture(); - absl::optional> - check_result = timer_list_->TimerCheck(&next); - GPR_ASSERT(check_result.has_value() && - "ERROR: More than one MainLoop is running."); - if (!check_result->empty()) { - RunSomeTimers(std::move(*check_result)); - continue; - } - if (!WaitUntil(next)) break; + grpc_core::Timestamp next = grpc_core::Timestamp::InfFuture(); + absl::optional> + check_result = timer_list_->TimerCheck(&next); + GPR_ASSERT(check_result.has_value() && + "ERROR: More than one MainLoop is running."); + bool timers_found = !check_result->empty(); + if (timers_found) { + RunSomeTimers(std::move(*check_result)); } - main_loop_exit_signal_->Notify(); + thread_pool_->Run([this, next, timers_found]() { + if (!timers_found && !WaitUntil(next)) { + main_loop_exit_signal_->Notify(); + return; + } + MainLoop(); + }); } bool TimerManager::IsTimerManagerThread() { return g_timer_thread; } -void TimerManager::StartMainLoopThread() { - main_thread_ = grpc_core::Thread( - "timer_manager", - [](void* arg) { - auto self = static_cast(arg); - self->MainLoop(); - }, - this, nullptr, - grpc_core::Thread::Options().set_tracked(false).set_joinable(false)); - main_thread_.Start(); -} - TimerManager::TimerManager( std::shared_ptr thread_pool) : host_(this), thread_pool_(std::move(thread_pool)) { timer_list_ = std::make_unique(&host_); main_loop_exit_signal_.emplace(); - StartMainLoopThread(); + thread_pool_->Run([this]() { MainLoop(); }); } grpc_core::Timestamp TimerManager::Host::Now() { @@ -162,7 +152,7 @@ void TimerManager::RestartPostFork() { } shutdown_ = false; main_loop_exit_signal_.emplace(); - StartMainLoopThread(); + thread_pool_->Run([this]() { MainLoop(); }); } void TimerManager::PrepareFork() { Shutdown(); } diff --git a/src/core/lib/event_engine/posix_engine/timer_manager.h b/src/core/lib/event_engine/posix_engine/timer_manager.h index 89d547a5ce7a0..5cd634c51b09f 100644 --- a/src/core/lib/event_engine/posix_engine/timer_manager.h +++ b/src/core/lib/event_engine/posix_engine/timer_manager.h @@ -36,7 +36,6 @@ #include "src/core/lib/event_engine/thread_pool/thread_pool.h" #include "src/core/lib/gprpp/notification.h" #include "src/core/lib/gprpp/sync.h" -#include "src/core/lib/gprpp/thd.h" #include "src/core/lib/gprpp/time.h" namespace grpc_event_engine { @@ -80,7 +79,6 @@ class TimerManager final : public grpc_event_engine::experimental::Forkable { TimerManager* const timer_manager_; }; - void StartMainLoopThread(); void RestartPostFork(); void MainLoop(); void RunSomeTimers(std::vector timers); @@ -103,7 +101,6 @@ class TimerManager final : public grpc_event_engine::experimental::Forkable { uint64_t wakeups_ ABSL_GUARDED_BY(mu_) = false; // actual timer implementation std::unique_ptr timer_list_; - grpc_core::Thread main_thread_; std::shared_ptr thread_pool_; absl::optional main_loop_exit_signal_; }; From 5f41fde4f2d2a1158f76ab7224a91bebcdcbd161 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Wed, 15 Nov 2023 16:12:48 -0800 Subject: [PATCH 007/127] [xDS] add test for mTLS for aggregate clusters (#34927) Closes #34927 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/34927 from markdroth:xds_mtls_aggregate_cluster_fix 6aa956997fa6b2ae75af6038f8a5089f22c17702 PiperOrigin-RevId: 582838553 --- .../client_channel/lb_policy/xds/cds.cc | 16 +++ test/cpp/end2end/xds/xds_end2end_test.cc | 125 +++++++++++++----- 2 files changed, 111 insertions(+), 30 deletions(-) diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/cds.cc b/src/core/ext/filters/client_channel/lb_policy/xds/cds.cc index f1278b98ae420..7e42338d70d86 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/cds.cc +++ b/src/core/ext/filters/client_channel/lb_policy/xds/cds.cc @@ -199,8 +199,24 @@ class CdsLb : public LoadBalancingPolicy { // The root of the tree is config_->cluster(). std::map watchers_; + // TODO(roth, yashkt): These are here because we need to handle + // pollset_set linkage as clusters are added or removed from the + // XdsCertificateProvider. However, in the aggregate cluster case, + // there may be multiple clusters in the same cert provider, and we're + // only tracking the cert providers for the most recent underlying + // cluster here. I think this is a bug that could cause us to starve + // the underlying cert providers of polling. However, it is not + // actually causing any problem in practice today, because (a) we have + // no cert provider impl that relies on gRPC's polling and (b) + // probably no one is actually configuring an aggregate cluster with + // different cert providers in different underlying clusters. + // Hopefully, this problem won't be an issue in practice until after + // the EventEngine migration is done, at which point the need for + // handling pollset_set linkage will go away, and these fields can + // simply be removed. RefCountedPtr root_certificate_provider_; RefCountedPtr identity_certificate_provider_; + RefCountedPtr xds_certificate_provider_; // Child LB policy. diff --git a/test/cpp/end2end/xds/xds_end2end_test.cc b/test/cpp/end2end/xds/xds_end2end_test.cc index f4e6e1cdbf873..b66416061d7ca 100644 --- a/test/cpp/end2end/xds/xds_end2end_test.cc +++ b/test/cpp/end2end/xds/xds_end2end_test.cc @@ -13,13 +13,10 @@ // limitations under the License. // -// TODO(roth): Split this file up into a common test framework and a set -// of test files that use that framework. Need to figure out the best -// way to split up the tests. One option would be to split it up by xDS -// resource type; another approach would be to have all of the "core" -// xDS functionality in one file and then move specific features to -// their own files (e.g., mTLS security, fault injection, circuit -// breaking, etc). +// TODO(yashkt): Split this file up into (at least) the following pieces: +// - xDS-enabled server functionality +// - mTLS functionality on both client and server +// - RBAC #include #include @@ -324,34 +321,14 @@ class XdsSecurityTest : public XdsEnd2endTest { balancer_->ads_service()->SetEdsResource(BuildEdsResource(args)); } - // Sends CDS updates with the new security configuration and verifies that - // after propagation, this new configuration is used for connections. If \a - // identity_instance_name and \a root_instance_name are both empty, - // connections are expected to use fallback credentials. - void UpdateAndVerifyXdsSecurityConfiguration( + void MaybeSetUpstreamTlsContextOnCluster( absl::string_view root_instance_name, absl::string_view root_certificate_name, absl::string_view identity_instance_name, absl::string_view identity_certificate_name, - const std::vector& san_matchers, - const std::vector& expected_authenticated_identity, - bool test_expects_failure = false) { - // Change the backend and use a unique service name to use so that we know - // that the CDS update was applied. - std::string service_name = absl::StrCat( - "eds_service_name", - absl::FormatTime("%H%M%E3S", absl::Now(), absl::LocalTimeZone())); - backend_index_ = (backend_index_ + 1) % 2; - EdsResourceArgs args({ - {"locality0", - CreateEndpointsForBackends(backend_index_, backend_index_ + 1)}, - }); - balancer_->ads_service()->SetEdsResource( - BuildEdsResource(args, service_name.c_str())); - auto cluster = default_cluster_; - cluster.mutable_eds_cluster_config()->set_service_name(service_name); + const std::vector& san_matchers, Cluster* cluster) { if (!identity_instance_name.empty() || !root_instance_name.empty()) { - auto* transport_socket = cluster.mutable_transport_socket(); + auto* transport_socket = cluster->mutable_transport_socket(); transport_socket->set_name("envoy.transport_sockets.tls"); UpstreamTlsContext upstream_tls_context; if (!identity_instance_name.empty()) { @@ -382,6 +359,37 @@ class XdsSecurityTest : public XdsEnd2endTest { } transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context); } + } + + // Sends CDS updates with the new security configuration and verifies that + // after propagation, this new configuration is used for connections. If \a + // identity_instance_name and \a root_instance_name are both empty, + // connections are expected to use fallback credentials. + void UpdateAndVerifyXdsSecurityConfiguration( + absl::string_view root_instance_name, + absl::string_view root_certificate_name, + absl::string_view identity_instance_name, + absl::string_view identity_certificate_name, + const std::vector& san_matchers, + const std::vector& expected_authenticated_identity, + bool test_expects_failure = false) { + // Change the backend and use a unique service name to use so that we know + // that the CDS update was applied. + std::string service_name = absl::StrCat( + "eds_service_name", + absl::FormatTime("%H%M%E3S", absl::Now(), absl::LocalTimeZone())); + backend_index_ = (backend_index_ + 1) % 2; + EdsResourceArgs args({ + {"locality0", + CreateEndpointsForBackends(backend_index_, backend_index_ + 1)}, + }); + balancer_->ads_service()->SetEdsResource( + BuildEdsResource(args, service_name.c_str())); + auto cluster = default_cluster_; + cluster.mutable_eds_cluster_config()->set_service_name(service_name); + MaybeSetUpstreamTlsContextOnCluster( + root_instance_name, root_certificate_name, identity_instance_name, + identity_certificate_name, san_matchers, &cluster); balancer_->ads_service()->SetCdsResource(cluster); // The updates might take time to have an effect, so use a retry loop. if (test_expects_failure) { @@ -730,6 +738,63 @@ TEST_P(XdsSecurityTest, TestFileWatcherCertificateProvider) { authenticated_identity_); } +TEST_P(XdsSecurityTest, MtlsWithAggregateCluster) { + g_fake1_cert_data_map->Set({{"", {root_cert_, identity_pair_}}}); + g_fake2_cert_data_map->Set({{"", {root_cert_, fallback_identity_pair_}}}); + // Set up aggregate cluster. + const char* kNewCluster1Name = "new_cluster_1"; + const char* kNewEdsService1Name = "new_eds_service_name_1"; + const char* kNewCluster2Name = "new_cluster_2"; + const char* kNewEdsService2Name = "new_eds_service_name_2"; + // Populate new EDS resources. + EdsResourceArgs args1({ + {"locality0", CreateEndpointsForBackends(0, 1)}, + }); + EdsResourceArgs args2({ + {"locality0", CreateEndpointsForBackends(1, 2)}, + }); + balancer_->ads_service()->SetEdsResource( + BuildEdsResource(args1, kNewEdsService1Name)); + balancer_->ads_service()->SetEdsResource( + BuildEdsResource(args2, kNewEdsService2Name)); + // Populate new CDS resources. + Cluster new_cluster1 = default_cluster_; + new_cluster1.set_name(kNewCluster1Name); + new_cluster1.mutable_eds_cluster_config()->set_service_name( + kNewEdsService1Name); + MaybeSetUpstreamTlsContextOnCluster("fake_plugin1", "", "fake_plugin1", "", + {}, &new_cluster1); + balancer_->ads_service()->SetCdsResource(new_cluster1); + Cluster new_cluster2 = default_cluster_; + new_cluster2.set_name(kNewCluster2Name); + new_cluster2.mutable_eds_cluster_config()->set_service_name( + kNewEdsService2Name); + MaybeSetUpstreamTlsContextOnCluster("fake_plugin1", "", "fake_plugin2", "", + {}, &new_cluster2); + balancer_->ads_service()->SetCdsResource(new_cluster2); + // Create Aggregate Cluster + auto cluster = default_cluster_; + auto* custom_cluster = cluster.mutable_cluster_type(); + custom_cluster->set_name("envoy.clusters.aggregate"); + envoy::extensions::clusters::aggregate::v3::ClusterConfig cluster_config; + cluster_config.add_clusters(kNewCluster1Name); + cluster_config.add_clusters(kNewCluster2Name); + custom_cluster->mutable_typed_config()->PackFrom(cluster_config); + balancer_->ads_service()->SetCdsResource(cluster); + // RPC should go to backend 0. + CheckRpcSendOk(DEBUG_LOCATION); + EXPECT_EQ(backends_[0]->backend_service()->request_count(), 1); + // Make sure the backend saw the right client identity. + EXPECT_EQ(backends_[0]->backend_service()->last_peer_identity(), + authenticated_identity_); + // Now stop backend 0 and wait for backend 1. + ShutdownBackend(0); + WaitForBackend(DEBUG_LOCATION, 1); + // Make sure the backend saw the right client identity. + EXPECT_EQ(backends_[1]->backend_service()->last_peer_identity(), + fallback_authenticated_identity_); +} + class XdsEnabledServerTest : public XdsEnd2endTest { protected: void SetUp() override {} // No-op -- individual tests do this themselves. From fcdc9b4d2975e29a4db1306ef02083c0d9c8c7c5 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Wed, 15 Nov 2023 20:19:47 -0800 Subject: [PATCH 008/127] [LB policy API] pass address lists down via an iterator interface (#34753) This avoids storing unnecessary copies of the address list in each node of the LB policy tree. Closes #34753 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/34753 from markdroth:lb_address_list_iterator 1d39465fbc3761193902c1d283c17f84e0a3b6f1 PiperOrigin-RevId: 582891475 --- BUILD | 1 + src/core/BUILD | 9 +- .../filters/client_channel/client_channel.cc | 7 +- .../lb_policy/address_filtering.cc | 75 +++++-- .../lb_policy/address_filtering.h | 5 +- .../client_channel/lb_policy/endpoint_list.cc | 17 +- .../client_channel/lb_policy/endpoint_list.h | 8 +- .../client_channel/lb_policy/grpclb/grpclb.cc | 195 +++++++++++------- .../outlier_detection/outlier_detection.cc | 5 +- .../lb_policy/pick_first/pick_first.cc | 167 ++++++++------- .../lb_policy/priority/priority.cc | 3 +- .../lb_policy/ring_hash/ring_hash.cc | 18 +- .../client_channel/lb_policy/rls/rls.cc | 27 ++- .../lb_policy/round_robin/round_robin.cc | 29 ++- .../lb_policy/subchannel_list.h | 20 +- .../weighted_round_robin.cc | 44 ++-- .../weighted_target/weighted_target.cc | 15 +- .../lb_policy/xds/xds_cluster_impl.cc | 4 +- .../lb_policy/xds/xds_cluster_manager.cc | 5 +- .../lb_policy/xds/xds_cluster_resolver.cc | 109 +++++++--- .../lb_policy/xds/xds_override_host.cc | 85 +++++--- .../lb_policy/xds/xds_wrr_locality.cc | 9 +- src/core/lib/gprpp/ref_counted_string.h | 13 ++ src/core/lib/load_balancing/lb_policy.h | 2 +- src/core/lib/resolver/endpoint_addresses.cc | 1 - src/core/lib/resolver/endpoint_addresses.h | 48 +++++ .../lb_policy/lb_policy_test_lib.h | 3 +- .../lb_policy/xds_override_host_test.cc | 6 +- test/core/util/test_lb_policies.cc | 6 +- 29 files changed, 588 insertions(+), 348 deletions(-) diff --git a/BUILD b/BUILD index a83ccf8d7d4c9..6e02ac04d5297 100644 --- a/BUILD +++ b/BUILD @@ -2941,6 +2941,7 @@ grpc_cc_library( "//src/core:lib/resolver/endpoint_addresses.h", ], external_deps = [ + "absl/functional:function_ref", "absl/status", "absl/status:statusor", "absl/strings", diff --git a/src/core/BUILD b/src/core/BUILD index cbf8ed32ea00c..351f101b81968 100644 --- a/src/core/BUILD +++ b/src/core/BUILD @@ -4140,6 +4140,7 @@ grpc_cc_library( external_deps = [ "absl/base:core_headers", "absl/container:inlined_vector", + "absl/functional:function_ref", "absl/status", "absl/status:statusor", "absl/strings", @@ -4667,6 +4668,7 @@ grpc_cc_library( "ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc", ], external_deps = [ + "absl/functional:function_ref", "absl/status", "absl/status:statusor", "absl/strings", @@ -4689,6 +4691,7 @@ grpc_cc_library( "no_destruct", "pollset_set", "ref_counted_string", + "resolved_address", "validation_errors", "//:channel_arg_names", "//:config", @@ -4837,6 +4840,7 @@ grpc_cc_library( "ext/filters/client_channel/lb_policy/address_filtering.h", ], external_deps = [ + "absl/functional:function_ref", "absl/status:statusor", "absl/strings", ], @@ -4845,6 +4849,7 @@ grpc_cc_library( "channel_args", "ref_counted", "ref_counted_string", + "resolved_address", "//:endpoint_addresses", "//:gpr_platform", "//:ref_counted_ptr", @@ -4914,6 +4919,7 @@ grpc_cc_library( "lb_policy", "subchannel_interface", "//:debug_location", + "//:endpoint_addresses", "//:gpr", "//:grpc_base", "//:ref_counted_ptr", @@ -4931,7 +4937,7 @@ grpc_cc_library( "ext/filters/client_channel/lb_policy/endpoint_list.h", ], external_deps = [ - "absl/functional:any_invocable", + "absl/functional:function_ref", "absl/status", "absl/status:statusor", "absl/types:optional", @@ -5325,6 +5331,7 @@ grpc_cc_library( ], external_deps = [ "absl/base:core_headers", + "absl/functional:function_ref", "absl/status", "absl/status:statusor", "absl/strings", diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc index 991cbee4fc872..b5064ceb20fd9 100644 --- a/src/core/ext/filters/client_channel/client_channel.cc +++ b/src/core/ext/filters/client_channel/client_channel.cc @@ -1599,7 +1599,12 @@ absl::Status ClientChannel::CreateOrUpdateLbPolicyLocked( Resolver::Result result) { // Construct update. LoadBalancingPolicy::UpdateArgs update_args; - update_args.addresses = std::move(result.addresses); + if (!result.addresses.ok()) { + update_args.addresses = result.addresses.status(); + } else { + update_args.addresses = std::make_shared( + std::move(*result.addresses)); + } update_args.config = std::move(lb_policy_config); update_args.resolution_note = std::move(result.resolution_note); // Remove the config selector from channel args so that we're not holding diff --git a/src/core/ext/filters/client_channel/lb_policy/address_filtering.cc b/src/core/ext/filters/client_channel/lb_policy/address_filtering.cc index b6e8396b95e23..bac15550d2d6d 100644 --- a/src/core/ext/filters/client_channel/lb_policy/address_filtering.cc +++ b/src/core/ext/filters/client_channel/lb_policy/address_filtering.cc @@ -20,11 +20,13 @@ #include -#include #include +#include "absl/functional/function_ref.h" + #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" +#include "src/core/lib/iomgr/resolved_address.h" namespace grpc_core { @@ -43,32 +45,63 @@ int HierarchicalPathArg::ChannelArgsCompare(const HierarchicalPathArg* a, return 0; } +namespace { + +class HierarchicalAddressIterator : public EndpointAddressesIterator { + public: + HierarchicalAddressIterator( + std::shared_ptr parent_it, + RefCountedStringValue child_name) + : parent_it_(std::move(parent_it)), child_name_(std::move(child_name)) {} + + void ForEach(absl::FunctionRef callback) + const override { + RefCountedPtr remaining_path_attr; + parent_it_->ForEach([&](const EndpointAddresses& endpoint) { + const auto* path_arg = endpoint.args().GetObject(); + if (path_arg == nullptr) return; + const std::vector& path = path_arg->path(); + auto it = path.begin(); + if (it == path.end()) return; + if (*it != child_name_) return; + ChannelArgs args = endpoint.args(); + ++it; + if (it != path.end()) { + std::vector remaining_path(it, path.end()); + if (remaining_path_attr == nullptr || + remaining_path_attr->path() != remaining_path) { + remaining_path_attr = + MakeRefCounted(std::move(remaining_path)); + } + args = args.SetObject(remaining_path_attr); + } + callback(EndpointAddresses(endpoint.addresses(), args)); + }); + } + + private: + std::shared_ptr parent_it_; + RefCountedStringValue child_name_; +}; + +} // namespace + absl::StatusOr MakeHierarchicalAddressMap( - const absl::StatusOr& addresses) { + absl::StatusOr> addresses) { if (!addresses.ok()) return addresses.status(); HierarchicalAddressMap result; - RefCountedPtr remaining_path_attr; - for (const EndpointAddresses& endpoint_addresses : *addresses) { - const auto* path_arg = - endpoint_addresses.args().GetObject(); - if (path_arg == nullptr) continue; + (*addresses)->ForEach([&](const EndpointAddresses& endpoint) { + const auto* path_arg = endpoint.args().GetObject(); + if (path_arg == nullptr) return; const std::vector& path = path_arg->path(); auto it = path.begin(); - if (it == path.end()) continue; - EndpointAddressesList& target_list = result[*it]; - ChannelArgs args = endpoint_addresses.args(); - ++it; - if (it != path.end()) { - std::vector remaining_path(it, path.end()); - if (remaining_path_attr == nullptr || - remaining_path_attr->path() != remaining_path) { - remaining_path_attr = - MakeRefCounted(std::move(remaining_path)); - } - args = args.SetObject(remaining_path_attr); + if (it == path.end()) return; + auto& target_list = result[*it]; + if (target_list == nullptr) { + target_list = + std::make_shared(*addresses, *it); } - target_list.emplace_back(endpoint_addresses.addresses(), args); - } + }); return result; } diff --git a/src/core/ext/filters/client_channel/lb_policy/address_filtering.h b/src/core/ext/filters/client_channel/lb_policy/address_filtering.h index d0e2faae29451..924261669bd87 100644 --- a/src/core/ext/filters/client_channel/lb_policy/address_filtering.h +++ b/src/core/ext/filters/client_channel/lb_policy/address_filtering.h @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -105,12 +106,12 @@ class HierarchicalPathArg : public RefCounted { // A map from the next path element to the endpoint addresses that fall // under that path element. using HierarchicalAddressMap = - std::map, RefCountedStringValueLessThan>; // Splits up the addresses into a separate list for each child. absl::StatusOr MakeHierarchicalAddressMap( - const absl::StatusOr& addresses); + absl::StatusOr> addresses); } // namespace grpc_core diff --git a/src/core/ext/filters/client_channel/lb_policy/endpoint_list.cc b/src/core/ext/filters/client_channel/lb_policy/endpoint_list.cc index 2c878bb2db098..7f2ecdd69f024 100644 --- a/src/core/ext/filters/client_channel/lb_policy/endpoint_list.cc +++ b/src/core/ext/filters/client_channel/lb_policy/endpoint_list.cc @@ -118,7 +118,7 @@ void EndpointList::Endpoint::Init( GPR_ASSERT(config.ok()); // Update child policy. LoadBalancingPolicy::UpdateArgs update_args; - update_args.addresses.emplace().emplace_back(addresses); + update_args.addresses = std::make_shared(addresses); update_args.args = child_args; update_args.config = std::move(*config); // TODO(roth): If the child reports a non-OK status with the update, @@ -163,15 +163,16 @@ RefCountedPtr EndpointList::Endpoint::CreateSubchannel( // void EndpointList::Init( - const EndpointAddressesList& endpoints, const ChannelArgs& args, - absl::AnyInvocable(RefCountedPtr, - const EndpointAddresses&, - const ChannelArgs&)> + EndpointAddressesIterator* endpoints, const ChannelArgs& args, + absl::FunctionRef(RefCountedPtr, + const EndpointAddresses&, + const ChannelArgs&)> create_endpoint) { - for (const EndpointAddresses& addresses : endpoints) { + if (endpoints == nullptr) return; + endpoints->ForEach([&](const EndpointAddresses& endpoint) { endpoints_.push_back( - create_endpoint(Ref(DEBUG_LOCATION, "Endpoint"), addresses, args)); - } + create_endpoint(Ref(DEBUG_LOCATION, "Endpoint"), endpoint, args)); + }); } void EndpointList::ResetBackoffLocked() { diff --git a/src/core/ext/filters/client_channel/lb_policy/endpoint_list.h b/src/core/ext/filters/client_channel/lb_policy/endpoint_list.h index df31bc39c0e83..c814d9f50eb99 100644 --- a/src/core/ext/filters/client_channel/lb_policy/endpoint_list.h +++ b/src/core/ext/filters/client_channel/lb_policy/endpoint_list.h @@ -25,7 +25,7 @@ #include #include -#include "absl/functional/any_invocable.h" +#include "absl/functional/function_ref.h" #include "absl/status/status.h" #include "absl/types/optional.h" @@ -53,7 +53,7 @@ namespace grpc_core { class MyEndpointList : public EndpointList { public: MyEndpointList(RefCountedPtr lb_policy, - const EndpointAddressesList& endpoints, + EndpointAddressesIterator* endpoints, const ChannelArgs& args) : EndpointList(std::move(lb_policy), GRPC_TRACE_FLAG_ENABLED(grpc_my_tracer) @@ -184,8 +184,8 @@ class EndpointList : public InternallyRefCounted { EndpointList(RefCountedPtr policy, const char* tracer) : policy_(std::move(policy)), tracer_(tracer) {} - void Init(const EndpointAddressesList& endpoints, const ChannelArgs& args, - absl::AnyInvocable( + void Init(EndpointAddressesIterator* endpoints, const ChannelArgs& args, + absl::FunctionRef( RefCountedPtr, const EndpointAddresses&, const ChannelArgs&)> create_endpoint); diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc index 4d3ebc1455d5d..0f4c7675f8983 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc @@ -72,6 +72,7 @@ #include #include "absl/container/inlined_vector.h" +#include "absl/functional/function_ref.h" #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/str_cat.h" @@ -384,9 +385,9 @@ class GrpcLb : public LoadBalancingPolicy { // Returns a text representation suitable for logging. std::string AsText() const; - // Extracts all non-drop entries into an EndpointAddressesList. - EndpointAddressesList GetServerAddressList( - GrpcLbClientStats* client_stats) const; + // Extracts all non-drop entries into an EndpointAddressesIterator. + std::shared_ptr GetServerAddressList( + GrpcLbClientStats* client_stats); // Returns true if the serverlist contains at least one drop entry and // no backend address entries. @@ -400,6 +401,8 @@ class GrpcLb : public LoadBalancingPolicy { const char* ShouldDrop(); private: + class AddressIterator; + std::vector serverlist_; // Accessed from the picker, so needs synchronization. @@ -504,6 +507,8 @@ class GrpcLb : public LoadBalancingPolicy { RefCountedPtr parent_; }; + class NullLbTokenEndpointIterator; + void ShutdownLocked() override; // Helper functions used in UpdateLocked(). @@ -569,7 +574,8 @@ class GrpcLb : public LoadBalancingPolicy { // Whether we're in fallback mode. bool fallback_mode_ = false; // The backend addresses from the resolver. - absl::StatusOr fallback_backend_addresses_; + absl::StatusOr> + fallback_backend_addresses_; // The last resolution note from our parent. // To be passed to child policy when fallback_backend_addresses_ is empty. std::string resolution_note_; @@ -594,11 +600,30 @@ class GrpcLb : public LoadBalancingPolicy { }; // -// GrpcLb::Serverlist +// GrpcLb::Serverlist::AddressIterator // -bool GrpcLb::Serverlist::operator==(const Serverlist& other) const { - return serverlist_ == other.serverlist_; +bool IsServerValid(const GrpcLbServer& server, size_t idx, bool log) { + if (server.drop) return false; + if (GPR_UNLIKELY(server.port >> 16 != 0)) { + if (log) { + gpr_log(GPR_ERROR, + "Invalid port '%d' at index %" PRIuPTR + " of serverlist. Ignoring.", + server.port, idx); + } + return false; + } + if (GPR_UNLIKELY(server.ip_size != 4 && server.ip_size != 16)) { + if (log) { + gpr_log(GPR_ERROR, + "Expected IP to be 4 or 16 bytes, got %d at index %" PRIuPTR + " of serverlist. Ignoring", + server.ip_size, idx); + } + return false; + } + return true; } void ParseServer(const GrpcLbServer& server, grpc_resolved_address* addr) { @@ -623,6 +648,53 @@ void ParseServer(const GrpcLbServer& server, grpc_resolved_address* addr) { } } +class GrpcLb::Serverlist::AddressIterator : public EndpointAddressesIterator { + public: + AddressIterator(RefCountedPtr serverlist, + RefCountedPtr client_stats) + : serverlist_(std::move(serverlist)), + client_stats_(std::move(client_stats)) {} + + void ForEach(absl::FunctionRef callback) + const override { + for (size_t i = 0; i < serverlist_->serverlist_.size(); ++i) { + const GrpcLbServer& server = serverlist_->serverlist_[i]; + if (!IsServerValid(server, i, false)) continue; + // Address processing. + grpc_resolved_address addr; + ParseServer(server, &addr); + // LB token processing. + const size_t lb_token_length = strnlen( + server.load_balance_token, GPR_ARRAY_SIZE(server.load_balance_token)); + std::string lb_token(server.load_balance_token, lb_token_length); + if (lb_token.empty()) { + auto addr_uri = grpc_sockaddr_to_uri(&addr); + gpr_log(GPR_INFO, + "Missing LB token for backend address '%s'. The empty token " + "will be used instead", + addr_uri.ok() ? addr_uri->c_str() + : addr_uri.status().ToString().c_str()); + } + // Return address with a channel arg containing LB token and stats object. + callback(EndpointAddresses( + addr, ChannelArgs().SetObject(MakeRefCounted( + std::move(lb_token), client_stats_)))); + } + } + + private: + RefCountedPtr serverlist_; + RefCountedPtr client_stats_; +}; + +// +// GrpcLb::Serverlist +// + +bool GrpcLb::Serverlist::operator==(const Serverlist& other) const { + return serverlist_ == other.serverlist_; +} + std::string GrpcLb::Serverlist::AsText() const { std::vector entries; for (size_t i = 0; i < serverlist_.size(); ++i) { @@ -642,59 +714,12 @@ std::string GrpcLb::Serverlist::AsText() const { return absl::StrJoin(entries, ""); } -bool IsServerValid(const GrpcLbServer& server, size_t idx, bool log) { - if (server.drop) return false; - if (GPR_UNLIKELY(server.port >> 16 != 0)) { - if (log) { - gpr_log(GPR_ERROR, - "Invalid port '%d' at index %" PRIuPTR - " of serverlist. Ignoring.", - server.port, idx); - } - return false; - } - if (GPR_UNLIKELY(server.ip_size != 4 && server.ip_size != 16)) { - if (log) { - gpr_log(GPR_ERROR, - "Expected IP to be 4 or 16 bytes, got %d at index %" PRIuPTR - " of serverlist. Ignoring", - server.ip_size, idx); - } - return false; - } - return true; -} - // Returns addresses extracted from the serverlist. -EndpointAddressesList GrpcLb::Serverlist::GetServerAddressList( - GrpcLbClientStats* client_stats) const { +std::shared_ptr +GrpcLb::Serverlist::GetServerAddressList(GrpcLbClientStats* client_stats) { RefCountedPtr stats; if (client_stats != nullptr) stats = client_stats->Ref(); - EndpointAddressesList endpoints; - for (size_t i = 0; i < serverlist_.size(); ++i) { - const GrpcLbServer& server = serverlist_[i]; - if (!IsServerValid(server, i, false)) continue; - // Address processing. - grpc_resolved_address addr; - ParseServer(server, &addr); - // LB token processing. - const size_t lb_token_length = strnlen( - server.load_balance_token, GPR_ARRAY_SIZE(server.load_balance_token)); - std::string lb_token(server.load_balance_token, lb_token_length); - if (lb_token.empty()) { - auto addr_uri = grpc_sockaddr_to_uri(&addr); - gpr_log(GPR_INFO, - "Missing LB token for backend address '%s'. The empty token will " - "be used instead", - addr_uri.ok() ? addr_uri->c_str() - : addr_uri.status().ToString().c_str()); - } - // Add address with a channel arg containing LB token and stats object. - endpoints.emplace_back( - addr, ChannelArgs().SetObject(MakeRefCounted( - std::move(lb_token), stats))); - } - return endpoints; + return std::make_shared(Ref(), std::move(stats)); } bool GrpcLb::Serverlist::ContainsAllDropEntries() const { @@ -1503,6 +1528,31 @@ void GrpcLb::ResetBackoffLocked() { } } +// Endpoint iterator wrapper to add null LB token attribute. +class GrpcLb::NullLbTokenEndpointIterator : public EndpointAddressesIterator { + public: + explicit NullLbTokenEndpointIterator( + std::shared_ptr parent_it) + : parent_it_(std::move(parent_it)) {} + + void ForEach(absl::FunctionRef callback) + const override { + parent_it_->ForEach([&](const EndpointAddresses& endpoint) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_glb_trace)) { + gpr_log(GPR_INFO, "[grpclb %p] fallback address: %s", this, + endpoint.ToString().c_str()); + } + callback(EndpointAddresses(endpoint.addresses(), + endpoint.args().SetObject(empty_token_))); + }); + } + + private: + std::shared_ptr parent_it_; + RefCountedPtr empty_token_ = + MakeRefCounted("", nullptr); +}; + absl::Status GrpcLb::UpdateLocked(UpdateArgs args) { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_glb_trace)) { gpr_log(GPR_INFO, "[grpclb %p] received update", this); @@ -1512,19 +1562,11 @@ absl::Status GrpcLb::UpdateLocked(UpdateArgs args) { GPR_ASSERT(config_ != nullptr); args_ = std::move(args.args); // Update fallback address list. - fallback_backend_addresses_ = std::move(args.addresses); - if (fallback_backend_addresses_.ok()) { - // Add null LB token attributes. - for (EndpointAddresses& endpoint : *fallback_backend_addresses_) { - endpoint = EndpointAddresses( - endpoint.addresses(), - endpoint.args().SetObject( - MakeRefCounted("", nullptr))); - if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_glb_trace)) { - gpr_log(GPR_INFO, "[grpclb %p] fallback address: %s", this, - endpoint.ToString().c_str()); - } - } + if (!args.addresses.ok()) { + fallback_backend_addresses_ = args.addresses.status(); + } else { + fallback_backend_addresses_ = std::make_shared( + std::move(*args.addresses)); } resolution_note_ = std::move(args.resolution_note); // Update balancer channel. @@ -1756,6 +1798,12 @@ OrphanablePtr GrpcLb::CreateChildPolicyLocked( return lb_policy; } +bool EndpointIteratorIsEmpty(const EndpointAddressesIterator& endpoints) { + bool empty = true; + endpoints.ForEach([&](const EndpointAddresses&) { empty = false; }); + return empty; +} + void GrpcLb::CreateOrUpdateChildPolicyLocked() { if (shutting_down_) return; // Construct update args. @@ -1769,16 +1817,17 @@ void GrpcLb::CreateOrUpdateChildPolicyLocked() { // picks. update_args.addresses = fallback_backend_addresses_; if (fallback_backend_addresses_.ok() && - fallback_backend_addresses_->empty()) { + EndpointIteratorIsEmpty(**fallback_backend_addresses_)) { update_args.resolution_note = absl::StrCat( - "grpclb in fallback mode without any balancer addresses: ", + "grpclb in fallback mode without any fallback addresses: ", resolution_note_); } } else { update_args.addresses = serverlist_->GetServerAddressList( lb_calld_ == nullptr ? nullptr : lb_calld_->client_stats()); is_backend_from_grpclb_load_balancer = true; - if (update_args.addresses.ok() && update_args.addresses->empty()) { + if (update_args.addresses.ok() && + EndpointIteratorIsEmpty(**update_args.addresses)) { update_args.resolution_note = "empty serverlist from grpclb balancer"; } } diff --git a/src/core/ext/filters/client_channel/lb_policy/outlier_detection/outlier_detection.cc b/src/core/ext/filters/client_channel/lb_policy/outlier_detection/outlier_detection.cc index 8569f24019d65..656332b21286c 100644 --- a/src/core/ext/filters/client_channel/lb_policy/outlier_detection/outlier_detection.cc +++ b/src/core/ext/filters/client_channel/lb_policy/outlier_detection/outlier_detection.cc @@ -661,7 +661,7 @@ absl::Status OutlierDetectionLb::UpdateLocked(UpdateArgs args) { if (args.addresses.ok()) { std::set current_endpoints; std::set current_addresses; - for (const EndpointAddresses& endpoint : *args.addresses) { + (*args.addresses)->ForEach([&](const EndpointAddresses& endpoint) { EndpointAddressSet key(endpoint.addresses()); current_endpoints.emplace(key); for (const grpc_resolved_address& address : endpoint.addresses()) { @@ -708,7 +708,7 @@ absl::Status OutlierDetectionLb::UpdateLocked(UpdateArgs args) { } it->second->DisableEjection(); } - } + }); // Remove any entries we no longer need in the subchannel map. for (auto it = subchannel_state_map_.begin(); it != subchannel_state_map_.end();) { @@ -753,7 +753,6 @@ absl::Status OutlierDetectionLb::UpdateLocked(UpdateArgs args) { update_args.addresses = std::move(args.addresses); update_args.resolution_note = std::move(args.resolution_note); update_args.config = config_->child_policy(); - // Update the policy. update_args.args = std::move(args.args); if (GRPC_TRACE_FLAG_ENABLED(grpc_outlier_detection_lb_trace)) { gpr_log(GPR_INFO, diff --git a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc index 577744a3ffff9..e51248faa9caf 100644 --- a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc +++ b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc @@ -21,7 +21,6 @@ #include #include -#include #include #include #include @@ -114,7 +113,7 @@ class PickFirst : public LoadBalancingPolicy { public: class SubchannelData { public: - SubchannelData(SubchannelList* subchannel_list, + SubchannelData(SubchannelList* subchannel_list, size_t index, RefCountedPtr subchannel); SubchannelInterface* subchannel() const { return subchannel_.get(); } @@ -125,12 +124,6 @@ class PickFirst : public LoadBalancingPolicy { return connectivity_status_; } - // Returns the index into the subchannel list of this object. - size_t Index() const { - return static_cast(this - - &subchannel_list_->subchannels_.front()); - } - // Resets the connection backoff. void ResetBackoffLocked() { if (subchannel_ != nullptr) subchannel_->ResetBackoff(); @@ -153,10 +146,8 @@ class PickFirst : public LoadBalancingPolicy { class Watcher : public SubchannelInterface::ConnectivityStateWatcherInterface { public: - Watcher(SubchannelData* subchannel_data, - RefCountedPtr subchannel_list) - : subchannel_data_(subchannel_data), - subchannel_list_(std::move(subchannel_list)) {} + Watcher(RefCountedPtr subchannel_list, size_t index) + : subchannel_list_(std::move(subchannel_list)), index_(index) {} ~Watcher() override { subchannel_list_.reset(DEBUG_LOCATION, "Watcher dtor"); @@ -164,8 +155,8 @@ class PickFirst : public LoadBalancingPolicy { void OnConnectivityStateChange(grpc_connectivity_state new_state, absl::Status status) override { - subchannel_data_->OnConnectivityStateChange(new_state, - std::move(status)); + subchannel_list_->subchannels_[index_].OnConnectivityStateChange( + new_state, std::move(status)); } grpc_pollset_set* interested_parties() override { @@ -173,8 +164,8 @@ class PickFirst : public LoadBalancingPolicy { } private: - SubchannelData* subchannel_data_; RefCountedPtr subchannel_list_; + const size_t index_; }; // This method will be invoked once soon after instantiation to report @@ -193,6 +184,7 @@ class PickFirst : public LoadBalancingPolicy { // Backpointer to owning subchannel list. Not owned. SubchannelList* subchannel_list_; + const size_t index_; // The subchannel. RefCountedPtr subchannel_; // Will be non-null when the subchannel's state is being watched. @@ -205,7 +197,8 @@ class PickFirst : public LoadBalancingPolicy { }; SubchannelList(RefCountedPtr policy, - EndpointAddressesList addresses, const ChannelArgs& args); + EndpointAddressesIterator* addresses, + const ChannelArgs& args); ~SubchannelList() override; @@ -413,9 +406,9 @@ void PickFirst::ResetBackoffLocked() { void PickFirst::AttemptToConnectUsingLatestUpdateArgsLocked() { // Create a subchannel list from latest_update_args_. - EndpointAddressesList addresses; + EndpointAddressesIterator* addresses = nullptr; if (latest_update_args_.addresses.ok()) { - addresses = *latest_update_args_.addresses; + addresses = latest_update_args_.addresses->get(); } // Replace latest_pending_subchannel_list_. if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace) && @@ -425,7 +418,7 @@ void PickFirst::AttemptToConnectUsingLatestUpdateArgsLocked() { latest_pending_subchannel_list_.get()); } latest_pending_subchannel_list_ = MakeOrphanable( - Ref(), std::move(addresses), latest_update_args_.args); + Ref(), addresses, latest_update_args_.args); // Empty update or no valid subchannels. Put the channel in // TRANSIENT_FAILURE and request re-resolution. if (latest_pending_subchannel_list_->size() == 0) { @@ -483,9 +476,7 @@ class AddressFamilyIterator { absl::Status PickFirst::UpdateLocked(UpdateArgs args) { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) { if (args.addresses.ok()) { - gpr_log(GPR_INFO, - "Pick First %p received update with %" PRIuPTR " addresses", this, - args.addresses->size()); + gpr_log(GPR_INFO, "Pick First %p received update", this); } else { gpr_log(GPR_INFO, "Pick First %p received update with address error: %s", this, args.addresses.status().ToString().c_str()); @@ -495,51 +486,59 @@ absl::Status PickFirst::UpdateLocked(UpdateArgs args) { absl::Status status; if (!args.addresses.ok()) { status = args.addresses.status(); - } else if (args.addresses->empty()) { - status = absl::UnavailableError("address list must not be empty"); } else { - // Shuffle the list if needed. - auto config = static_cast(args.config.get()); - if (config->shuffle_addresses()) { - absl::c_shuffle(*args.addresses, bit_gen_); - } - // Flatten the list so that we have one address per endpoint. - // While we're iterating, also determine the desired address family - // order and the index of the first element of each family, for use in - // the interleaving below. - std::set address_families; - std::vector address_family_order; EndpointAddressesList endpoints; - for (const auto& endpoint : *args.addresses) { - for (const auto& address : endpoint.addresses()) { - endpoints.emplace_back(address, endpoint.args()); - if (IsPickFirstHappyEyeballsEnabled()) { - absl::string_view scheme = GetAddressFamily(address); - bool inserted = address_families.insert(scheme).second; - if (inserted) { - address_family_order.emplace_back(scheme, endpoints.size() - 1); + (*args.addresses)->ForEach([&](const EndpointAddresses& endpoint) { + endpoints.push_back(endpoint); + }); + if (endpoints.empty()) { + status = absl::UnavailableError("address list must not be empty"); + } else { + // Shuffle the list if needed. + auto config = static_cast(args.config.get()); + if (config->shuffle_addresses()) { + absl::c_shuffle(endpoints, bit_gen_); + } + // Flatten the list so that we have one address per endpoint. + // While we're iterating, also determine the desired address family + // order and the index of the first element of each family, for use in + // the interleaving below. + std::set address_families; + std::vector address_family_order; + EndpointAddressesList flattened_endpoints; + for (const auto& endpoint : endpoints) { + for (const auto& address : endpoint.addresses()) { + flattened_endpoints.emplace_back(address, endpoint.args()); + if (IsPickFirstHappyEyeballsEnabled()) { + absl::string_view scheme = GetAddressFamily(address); + bool inserted = address_families.insert(scheme).second; + if (inserted) { + address_family_order.emplace_back(scheme, + flattened_endpoints.size() - 1); + } } } } - } - // Interleave addresses as per RFC-8305 section 4. - if (IsPickFirstHappyEyeballsEnabled()) { - EndpointAddressesList interleaved_endpoints; - interleaved_endpoints.reserve(endpoints.size()); - std::vector endpoints_moved(endpoints.size()); - size_t scheme_index = 0; - for (size_t i = 0; i < endpoints.size(); ++i) { - EndpointAddresses* endpoint; - do { - auto& iterator = address_family_order[scheme_index++ % - address_family_order.size()]; - endpoint = iterator.Next(endpoints, &endpoints_moved); - } while (endpoint == nullptr); - interleaved_endpoints.emplace_back(std::move(*endpoint)); + endpoints = std::move(flattened_endpoints); + // Interleave addresses as per RFC-8305 section 4. + if (IsPickFirstHappyEyeballsEnabled()) { + EndpointAddressesList interleaved_endpoints; + interleaved_endpoints.reserve(endpoints.size()); + std::vector endpoints_moved(endpoints.size()); + size_t scheme_index = 0; + for (size_t i = 0; i < endpoints.size(); ++i) { + EndpointAddresses* endpoint; + do { + auto& iterator = address_family_order[scheme_index++ % + address_family_order.size()]; + endpoint = iterator.Next(endpoints, &endpoints_moved); + } while (endpoint == nullptr); + interleaved_endpoints.emplace_back(std::move(*endpoint)); + } + endpoints = std::move(interleaved_endpoints); } - args.addresses = std::move(interleaved_endpoints); - } else { - args.addresses = std::move(endpoints); + args.addresses = + std::make_shared(std::move(endpoints)); } } // If the update contains a resolver error and we have a previous update @@ -617,18 +616,20 @@ void PickFirst::HealthWatcher::OnConnectivityStateChange( // PickFirst::SubchannelList::SubchannelData::SubchannelData( - SubchannelList* subchannel_list, + SubchannelList* subchannel_list, size_t index, RefCountedPtr subchannel) - : subchannel_list_(subchannel_list), subchannel_(std::move(subchannel)) { + : subchannel_list_(subchannel_list), + index_(index), + subchannel_(std::move(subchannel)) { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) { gpr_log(GPR_INFO, "[PF %p] subchannel list %p index %" PRIuPTR " (subchannel %p): starting watch", - subchannel_list_->policy_.get(), subchannel_list_, - subchannel_list_->size(), subchannel_.get()); + subchannel_list_->policy_.get(), subchannel_list_, index_, + subchannel_.get()); } auto watcher = std::make_unique( - this, subchannel_list_->Ref(DEBUG_LOCATION, "Watcher")); + subchannel_list_->Ref(DEBUG_LOCATION, "Watcher"), index_); pending_watcher_ = watcher.get(); subchannel_->WatchConnectivityState(std::move(watcher)); } @@ -639,7 +640,7 @@ void PickFirst::SubchannelList::SubchannelData::ShutdownLocked() { gpr_log(GPR_INFO, "[PF %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR " (subchannel %p): cancelling watch and unreffing subchannel", - subchannel_list_->policy_.get(), subchannel_list_, Index(), + subchannel_list_->policy_.get(), subchannel_list_, index_, subchannel_list_->size(), subchannel_.get()); } subchannel_->CancelConnectivityStateWatch(pending_watcher_); @@ -659,7 +660,7 @@ void PickFirst::SubchannelList::SubchannelData::OnConnectivityStateChange( "status=%s, shutting_down=%d, pending_watcher=%p, " "seen_transient_failure=%d, p->selected_=%p, " "p->subchannel_list_=%p, p->latest_pending_subchannel_list_=%p", - p, subchannel_list_, Index(), subchannel_list_->size(), + p, subchannel_list_, index_, subchannel_list_->size(), subchannel_.get(), (connectivity_state_.has_value() ? ConnectivityStateName(*connectivity_state_) @@ -771,7 +772,7 @@ void PickFirst::SubchannelList::SubchannelData::OnConnectivityStateChange( if (!IsPickFirstHappyEyeballsEnabled()) { // Ignore any other updates for subchannels we're not currently trying to // connect to. - if (Index() != subchannel_list_->attempting_index_) return; + if (index_ != subchannel_list_->attempting_index_) return; // React to the connectivity state. ReactToConnectivityStateLocked(); return; @@ -784,7 +785,7 @@ void PickFirst::SubchannelList::SubchannelData::OnConnectivityStateChange( if (!prev_seen_transient_failure && seen_transient_failure_) { // If a connection attempt fails before the timer fires, then // cancel the timer and start connecting on the next subchannel. - if (Index() == subchannel_list_->attempting_index_) { + if (index_ == subchannel_list_->attempting_index_) { if (subchannel_list_->timer_handle_.has_value()) { p->channel_control_helper()->GetEventEngine()->Cancel( *subchannel_list_->timer_handle_); @@ -858,7 +859,7 @@ void PickFirst::SubchannelList::SubchannelData:: // We skip subchannels in state TRANSIENT_FAILURE to avoid a // large recursion that could overflow the stack. SubchannelData* found_subchannel = nullptr; - for (size_t next_index = Index() + 1; + for (size_t next_index = index_ + 1; next_index < subchannel_list_->size(); ++next_index) { SubchannelData* sc = &subchannel_list_->subchannels_[next_index]; GPR_ASSERT(sc->connectivity_state_.has_value()); @@ -946,14 +947,14 @@ void PickFirst::SubchannelList::SubchannelData::RequestConnectionWithTimer() { GPR_ASSERT(connectivity_state_ == GRPC_CHANNEL_CONNECTING); } // If this is not the last subchannel in the list, start the timer. - if (Index() != subchannel_list_->size() - 1) { + if (index_ != subchannel_list_->size() - 1) { PickFirst* p = subchannel_list_->policy_.get(); if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) { gpr_log(GPR_INFO, "Pick First %p subchannel list %p: starting Connection " "Attempt Delay timer for %" PRId64 "ms for index %" PRIuPTR, p, subchannel_list_, p->connection_attempt_delay_.millis(), - Index()); + index_); } subchannel_list_->timer_handle_ = p->channel_control_helper()->GetEventEngine()->RunAfter( @@ -1041,7 +1042,7 @@ void PickFirst::SubchannelList::SubchannelData::ProcessUnselectedReadyLocked() { } // Unref all other subchannels in the list. for (size_t i = 0; i < subchannel_list_->size(); ++i) { - if (i != Index()) { + if (i != index_) { subchannel_list_->subchannels_[i].ShutdownLocked(); } } @@ -1052,7 +1053,7 @@ void PickFirst::SubchannelList::SubchannelData::ProcessUnselectedReadyLocked() { // PickFirst::SubchannelList::SubchannelList(RefCountedPtr policy, - EndpointAddressesList addresses, + EndpointAddressesIterator* addresses, const ChannelArgs& args) : InternallyRefCounted( GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace) ? "SubchannelList" @@ -1062,14 +1063,12 @@ PickFirst::SubchannelList::SubchannelList(RefCountedPtr policy, .Remove( GRPC_ARG_INTERNAL_PICK_FIRST_OMIT_STATUS_MESSAGE_PREFIX)) { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) { - gpr_log(GPR_INFO, - "[PF %p] Creating subchannel list %p for %" PRIuPTR - " subchannels - channel args: %s", - policy_.get(), this, addresses.size(), args_.ToString().c_str()); + gpr_log(GPR_INFO, "[PF %p] Creating subchannel list %p - channel args: %s", + policy_.get(), this, args_.ToString().c_str()); } - subchannels_.reserve(addresses.size()); + if (addresses == nullptr) return; // Create a subchannel for each address. - for (const EndpointAddresses& address : addresses) { + addresses->ForEach([&](const EndpointAddresses& address) { GPR_ASSERT(address.addresses().size() == 1); RefCountedPtr subchannel = policy_->channel_control_helper()->CreateSubchannel( @@ -1081,7 +1080,7 @@ PickFirst::SubchannelList::SubchannelList(RefCountedPtr policy, "[PF %p] could not create subchannel for address %s, ignoring", policy_.get(), address.ToString().c_str()); } - continue; + return; } if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) { gpr_log(GPR_INFO, @@ -1090,8 +1089,8 @@ PickFirst::SubchannelList::SubchannelList(RefCountedPtr policy, policy_.get(), this, subchannels_.size(), subchannel.get(), address.ToString().c_str()); } - subchannels_.emplace_back(this, std::move(subchannel)); - } + subchannels_.emplace_back(this, subchannels_.size(), std::move(subchannel)); + }); } PickFirst::SubchannelList::~SubchannelList() { diff --git a/src/core/ext/filters/client_channel/lb_policy/priority/priority.cc b/src/core/ext/filters/client_channel/lb_policy/priority/priority.cc index e1e21072bc066..cdfe6adceafd2 100644 --- a/src/core/ext/filters/client_channel/lb_policy/priority/priority.cc +++ b/src/core/ext/filters/client_channel/lb_policy/priority/priority.cc @@ -684,7 +684,8 @@ absl::Status PriorityLb::ChildPriority::UpdateLocked( if (priority_policy_->addresses_.ok()) { auto it = priority_policy_->addresses_->find(name_); if (it == priority_policy_->addresses_->end()) { - update_args.addresses.emplace(); + update_args.addresses = std::make_shared( + EndpointAddressesList()); } else { update_args.addresses = it->second; } diff --git a/src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc b/src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc index 5881f168c8630..c1c52c7de5f4a 100644 --- a/src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc +++ b/src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc @@ -554,7 +554,8 @@ void RingHash::RingHashEndpoint::UpdateChildPolicyLocked() { GPR_ASSERT(config.ok()); // Update child policy. LoadBalancingPolicy::UpdateArgs update_args; - update_args.addresses.emplace().emplace_back(ring_hash_->endpoints_[index_]); + update_args.addresses = + std::make_shared(ring_hash_->endpoints_[index_]); update_args.args = ring_hash_->args_; update_args.config = std::move(*config); // TODO(roth): If the child reports a non-OK status with the update, @@ -622,18 +623,14 @@ absl::Status RingHash::UpdateLocked(UpdateArgs args) { // Check address list. if (args.addresses.ok()) { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_ring_hash_trace)) { - gpr_log(GPR_INFO, "[RH %p] received update with %" PRIuPTR " addresses", - this, args.addresses->size()); + gpr_log(GPR_INFO, "[RH %p] received update", this); } // De-dup endpoints, taking weight into account. endpoints_.clear(); - endpoints_.reserve(args.addresses->size()); std::map endpoint_indices; - size_t num_skipped = 0; - for (size_t i = 0; i < args.addresses->size(); ++i) { - EndpointAddresses& endpoint = (*args.addresses)[i]; + (*args.addresses)->ForEach([&](const EndpointAddresses& endpoint) { const EndpointAddressSet key(endpoint.addresses()); - auto p = endpoint_indices.emplace(key, i - num_skipped); + auto p = endpoint_indices.emplace(key, endpoints_.size()); if (!p.second) { // Duplicate endpoint. Combine weights and skip the dup. EndpointAddresses& prev_endpoint = endpoints_[p.first->second]; @@ -651,11 +648,10 @@ absl::Status RingHash::UpdateLocked(UpdateArgs args) { prev_endpoint.addresses(), prev_endpoint.args().Set(GRPC_ARG_ADDRESS_WEIGHT, weight_arg + prev_weight_arg)); - ++num_skipped; } else { - endpoints_.push_back(std::move(endpoint)); + endpoints_.push_back(endpoint); } - } + }); } else { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_ring_hash_trace)) { gpr_log(GPR_INFO, "[RH %p] received update with addresses error: %s", diff --git a/src/core/ext/filters/client_channel/lb_policy/rls/rls.cc b/src/core/ext/filters/client_channel/lb_policy/rls/rls.cc index f51ef89a0bedb..1521fafcfc4f4 100644 --- a/src/core/ext/filters/client_channel/lb_policy/rls/rls.cc +++ b/src/core/ext/filters/client_channel/lb_policy/rls/rls.cc @@ -707,7 +707,7 @@ class RlsLb : public LoadBalancingPolicy { OrphanablePtr rls_channel_ ABSL_GUARDED_BY(mu_); // Accessed only from within WorkSerializer. - absl::StatusOr addresses_; + absl::StatusOr> addresses_; ChannelArgs channel_args_; RefCountedPtr config_; RefCountedPtr default_child_policy_; @@ -1858,6 +1858,27 @@ RlsLb::RlsLb(Args args) : LoadBalancingPolicy(std::move(args)), cache_(this) { } } +bool EndpointsEqual( + const absl::StatusOr> endpoints1, + const absl::StatusOr> + endpoints2) { + if (endpoints1.status() != endpoints2.status()) return false; + if (endpoints1.ok()) { + std::vector e1_list; + (*endpoints1)->ForEach([&](const EndpointAddresses& endpoint) { + e1_list.push_back(endpoint); + }); + size_t i = 0; + bool different = false; + (*endpoints2)->ForEach([&](const EndpointAddresses& endpoint) { + if (endpoint != e1_list[i++]) different = true; + }); + if (different) return false; + if (i != e1_list.size()) return false; + } + return true; +} + absl::Status RlsLb::UpdateLocked(UpdateArgs args) { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_rls_trace)) { gpr_log(GPR_INFO, "[rlslb %p] policy updated", this); @@ -1875,7 +1896,7 @@ absl::Status RlsLb::UpdateLocked(UpdateArgs args) { // Swap out addresses. // If the new address list is an error and we have an existing address list, // stick with the existing addresses. - absl::StatusOr old_addresses; + absl::StatusOr> old_addresses; if (args.addresses.ok()) { old_addresses = std::move(addresses_); addresses_ = std::move(args.addresses); @@ -1888,7 +1909,7 @@ absl::Status RlsLb::UpdateLocked(UpdateArgs args) { bool update_child_policies = old_config == nullptr || old_config->child_policy_config() != config_->child_policy_config() || - old_addresses != addresses_ || args.args != channel_args_; + !EndpointsEqual(old_addresses, addresses_) || args.args != channel_args_; // If default target changes, swap out child policy. bool created_default_child = false; if (old_config == nullptr || diff --git a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc index 51e89c8e5b377..1c893fb1dcbda 100644 --- a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc +++ b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc @@ -125,14 +125,14 @@ class OldRoundRobin : public LoadBalancingPolicy { : public SubchannelList { public: - RoundRobinSubchannelList(OldRoundRobin* policy, ServerAddressList addresses, + RoundRobinSubchannelList(OldRoundRobin* policy, + EndpointAddressesIterator* addresses, const ChannelArgs& args) : SubchannelList(policy, (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace) ? "RoundRobinSubchannelList" : nullptr), - std::move(addresses), policy->channel_control_helper(), - args) { + addresses, policy->channel_control_helper(), args) { // Need to maintain a ref to the LB policy as long as we maintain // any references to subchannels, since the subchannels' // pollset_sets will include the LB policy's pollset_set. @@ -277,13 +277,12 @@ void OldRoundRobin::ResetBackoffLocked() { } absl::Status OldRoundRobin::UpdateLocked(UpdateArgs args) { - ServerAddressList addresses; + EndpointAddressesIterator* addresses = nullptr; if (args.addresses.ok()) { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) { - gpr_log(GPR_INFO, "[RR %p] received update with %" PRIuPTR " addresses", - this, args.addresses->size()); + gpr_log(GPR_INFO, "[RR %p] received update", this); } - addresses = std::move(*args.addresses); + addresses = args.addresses->get(); } else { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) { gpr_log(GPR_INFO, "[RR %p] received update with address error: %s", this, @@ -299,8 +298,8 @@ absl::Status OldRoundRobin::UpdateLocked(UpdateArgs args) { gpr_log(GPR_INFO, "[RR %p] replacing previous pending subchannel list %p", this, latest_pending_subchannel_list_.get()); } - latest_pending_subchannel_list_ = MakeRefCounted( - this, std::move(addresses), args.args); + latest_pending_subchannel_list_ = + MakeRefCounted(this, addresses, args.args); latest_pending_subchannel_list_->StartWatchingLocked(args.args); // If the new list is empty, immediately promote it to // subchannel_list_ and report TRANSIENT_FAILURE. @@ -524,7 +523,7 @@ class RoundRobin : public LoadBalancingPolicy { class RoundRobinEndpointList : public EndpointList { public: RoundRobinEndpointList(RefCountedPtr round_robin, - const EndpointAddressesList& endpoints, + EndpointAddressesIterator* endpoints, const ChannelArgs& args) : EndpointList(std::move(round_robin), GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace) @@ -687,13 +686,12 @@ void RoundRobin::ResetBackoffLocked() { } absl::Status RoundRobin::UpdateLocked(UpdateArgs args) { - EndpointAddressesList addresses; + EndpointAddressesIterator* addresses = nullptr; if (args.addresses.ok()) { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) { - gpr_log(GPR_INFO, "[RR %p] received update with %" PRIuPTR " endpoints", - this, args.addresses->size()); + gpr_log(GPR_INFO, "[RR %p] received update", this); } - addresses = std::move(*args.addresses); + addresses = args.addresses->get(); } else { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) { gpr_log(GPR_INFO, "[RR %p] received update with address error: %s", this, @@ -710,8 +708,7 @@ absl::Status RoundRobin::UpdateLocked(UpdateArgs args) { latest_pending_endpoint_list_.get()); } latest_pending_endpoint_list_ = MakeOrphanable( - Ref(DEBUG_LOCATION, "RoundRobinEndpointList"), std::move(addresses), - args.args); + Ref(DEBUG_LOCATION, "RoundRobinEndpointList"), addresses, args.args); // If the new list is empty, immediately promote it to // endpoint_list_ and report TRANSIENT_FAILURE. if (latest_pending_endpoint_list_->size() == 0) { diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h index cb52ad92daaa4..b5076a9f492bd 100644 --- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h @@ -42,6 +42,7 @@ #include "src/core/lib/iomgr/iomgr_fwd.h" #include "src/core/lib/load_balancing/lb_policy.h" #include "src/core/lib/load_balancing/subchannel_interface.h" +#include "src/core/lib/resolver/endpoint_addresses.h" #include "src/core/lib/resolver/server_address.h" #include "src/core/lib/transport/connectivity_state.h" @@ -208,7 +209,7 @@ class SubchannelList : public DualRefCounted { protected: SubchannelList(LoadBalancingPolicy* policy, const char* tracer, - ServerAddressList addresses, + EndpointAddressesIterator* addresses, LoadBalancingPolicy::ChannelControlHelper* helper, const ChannelArgs& args); @@ -365,19 +366,18 @@ void SubchannelData::ShutdownLocked() { template SubchannelList::SubchannelList( LoadBalancingPolicy* policy, const char* tracer, - ServerAddressList addresses, + EndpointAddressesIterator* addresses, LoadBalancingPolicy::ChannelControlHelper* helper, const ChannelArgs& args) : DualRefCounted(tracer), policy_(policy), tracer_(tracer) { if (GPR_UNLIKELY(tracer_ != nullptr)) { - gpr_log(GPR_INFO, - "[%s %p] Creating subchannel list %p for %" PRIuPTR " subchannels", - tracer_, policy, this, addresses.size()); + gpr_log(GPR_INFO, "[%s %p] Creating subchannel list %p", tracer_, policy, + this); } - subchannels_.reserve(addresses.size()); + if (addresses == nullptr) return; // Create a subchannel for each address. - for (ServerAddress address : addresses) { + addresses->ForEach([&](const EndpointAddresses& address) { RefCountedPtr subchannel = helper->CreateSubchannel(address.address(), address.args(), args); if (subchannel == nullptr) { @@ -387,7 +387,7 @@ SubchannelList::SubchannelList( "[%s %p] could not create subchannel for address %s, ignoring", tracer_, policy_, address.ToString().c_str()); } - continue; + return; } if (GPR_UNLIKELY(tracer_ != nullptr)) { gpr_log(GPR_INFO, @@ -397,8 +397,8 @@ SubchannelList::SubchannelList( address.ToString().c_str()); } subchannels_.emplace_back(); - subchannels_.back().Init(this, std::move(address), std::move(subchannel)); - } + subchannels_.back().Init(this, address, std::move(subchannel)); + }); } template diff --git a/src/core/ext/filters/client_channel/lb_policy/weighted_round_robin/weighted_round_robin.cc b/src/core/ext/filters/client_channel/lb_policy/weighted_round_robin/weighted_round_robin.cc index 102cd6aa7cf37..aa2c6f5bb66b5 100644 --- a/src/core/ext/filters/client_channel/lb_policy/weighted_round_robin/weighted_round_robin.cc +++ b/src/core/ext/filters/client_channel/lb_policy/weighted_round_robin/weighted_round_robin.cc @@ -247,14 +247,13 @@ class OldWeightedRoundRobin : public LoadBalancingPolicy { WeightedRoundRobinSubchannelData> { public: WeightedRoundRobinSubchannelList(OldWeightedRoundRobin* policy, - ServerAddressList addresses, + EndpointAddressesIterator* addresses, const ChannelArgs& args) : SubchannelList(policy, (GRPC_TRACE_FLAG_ENABLED(grpc_lb_wrr_trace) ? "WeightedRoundRobinSubchannelList" : nullptr), - std::move(addresses), policy->channel_control_helper(), - args) { + addresses, policy->channel_control_helper(), args) { // Need to maintain a ref to the LB policy as long as we maintain // any references to subchannels, since the subchannels' // pollset_sets will include the LB policy's pollset_set. @@ -675,11 +674,10 @@ void OldWeightedRoundRobin::ResetBackoffLocked() { absl::Status OldWeightedRoundRobin::UpdateLocked(UpdateArgs args) { global_stats().IncrementWrrUpdates(); config_ = std::move(args.config); - ServerAddressList addresses; + std::shared_ptr addresses; if (args.addresses.ok()) { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_wrr_trace)) { - gpr_log(GPR_INFO, "[WRR %p] received update with %" PRIuPTR " addresses", - this, args.addresses->size()); + gpr_log(GPR_INFO, "[WRR %p] received update", this); } // Weed out duplicate addresses. Also sort the addresses so that if // the set of the addresses don't change, their indexes in the @@ -698,10 +696,12 @@ absl::Status OldWeightedRoundRobin::UpdateLocked(UpdateArgs args) { return memcmp(addr1.addr, addr2.addr, addr1.len) < 0; } }; - std::set ordered_addresses( - args.addresses->begin(), args.addresses->end()); - addresses = - ServerAddressList(ordered_addresses.begin(), ordered_addresses.end()); + std::set ordered_addresses; + (*args.addresses)->ForEach([&](const EndpointAddresses& endpoint) { + ordered_addresses.insert(endpoint); + }); + addresses = std::make_shared( + ServerAddressList(ordered_addresses.begin(), ordered_addresses.end())); } else { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_wrr_trace)) { gpr_log(GPR_INFO, "[WRR %p] received update with address error: %s", this, @@ -718,8 +718,8 @@ absl::Status OldWeightedRoundRobin::UpdateLocked(UpdateArgs args) { this, latest_pending_subchannel_list_.get()); } latest_pending_subchannel_list_ = - MakeRefCounted( - this, std::move(addresses), args.args); + MakeRefCounted(this, addresses.get(), + args.args); latest_pending_subchannel_list_->StartWatchingLocked(args.args); // If the new list is empty, immediately promote it to // subchannel_list_ and report TRANSIENT_FAILURE. @@ -1079,7 +1079,7 @@ class WeightedRoundRobin : public LoadBalancingPolicy { }; WrrEndpointList(RefCountedPtr wrr, - const EndpointAddressesList& endpoints, + EndpointAddressesIterator* endpoints, const ChannelArgs& args) : EndpointList(std::move(wrr), GRPC_TRACE_FLAG_ENABLED(grpc_lb_wrr_trace) @@ -1516,11 +1516,10 @@ void WeightedRoundRobin::ResetBackoffLocked() { absl::Status WeightedRoundRobin::UpdateLocked(UpdateArgs args) { global_stats().IncrementWrrUpdates(); config_ = std::move(args.config); - EndpointAddressesList addresses; + std::shared_ptr addresses; if (args.addresses.ok()) { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_wrr_trace)) { - gpr_log(GPR_INFO, "[WRR %p] received update with %" PRIuPTR " addresses", - this, args.addresses->size()); + gpr_log(GPR_INFO, "[WRR %p] received update", this); } // Weed out duplicate endpoints. Also sort the endpoints so that if // the set of endpoints doesn't change, their indexes in the endpoint @@ -1539,10 +1538,13 @@ absl::Status WeightedRoundRobin::UpdateLocked(UpdateArgs args) { return e1 < e2; } }; - std::set ordered_addresses( - args.addresses->begin(), args.addresses->end()); - addresses = EndpointAddressesList(ordered_addresses.begin(), - ordered_addresses.end()); + std::set ordered_addresses; + (*args.addresses)->ForEach([&](const EndpointAddresses& endpoint) { + ordered_addresses.insert(endpoint); + }); + addresses = + std::make_shared(EndpointAddressesList( + ordered_addresses.begin(), ordered_addresses.end())); } else { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_wrr_trace)) { gpr_log(GPR_INFO, "[WRR %p] received update with address error: %s", this, @@ -1559,7 +1561,7 @@ absl::Status WeightedRoundRobin::UpdateLocked(UpdateArgs args) { this, latest_pending_endpoint_list_.get()); } latest_pending_endpoint_list_ = - MakeOrphanable(Ref(), std::move(addresses), args.args); + MakeOrphanable(Ref(), addresses.get(), args.args); // If the new list is empty, immediately promote it to // endpoint_list_ and report TRANSIENT_FAILURE. if (latest_pending_endpoint_list_->size() == 0) { diff --git a/src/core/ext/filters/client_channel/lb_policy/weighted_target/weighted_target.cc b/src/core/ext/filters/client_channel/lb_policy/weighted_target/weighted_target.cc index eecd112445ab0..0639ce9b0946a 100644 --- a/src/core/ext/filters/client_channel/lb_policy/weighted_target/weighted_target.cc +++ b/src/core/ext/filters/client_channel/lb_policy/weighted_target/weighted_target.cc @@ -157,10 +157,10 @@ class WeightedTargetLb : public LoadBalancingPolicy { void Orphan() override; - absl::Status UpdateLocked(const WeightedTargetLbConfig::ChildConfig& config, - absl::StatusOr addresses, - const std::string& resolution_note, - const ChannelArgs& args); + absl::Status UpdateLocked( + const WeightedTargetLbConfig::ChildConfig& config, + absl::StatusOr> addresses, + const std::string& resolution_note, const ChannelArgs& args); void ResetBackoffLocked(); void DeactivateLocked(); @@ -338,11 +338,12 @@ absl::Status WeightedTargetLb::UpdateLocked(UpdateArgs args) { target = MakeOrphanable( Ref(DEBUG_LOCATION, "WeightedChild"), name); } - absl::StatusOr addresses; + absl::StatusOr> addresses; if (address_map.ok()) { auto it = address_map->find(name); if (it == address_map->end()) { - addresses.emplace(); + addresses = std::make_shared( + EndpointAddressesList()); } else { addresses = std::move(it->second); } @@ -589,7 +590,7 @@ WeightedTargetLb::WeightedChild::CreateChildPolicyLocked( absl::Status WeightedTargetLb::WeightedChild::UpdateLocked( const WeightedTargetLbConfig::ChildConfig& config, - absl::StatusOr addresses, + absl::StatusOr> addresses, const std::string& resolution_note, const ChannelArgs& args) { if (weighted_target_policy_->shutting_down_) return absl::OkStatus(); // Update child weight. diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc index 50740151c9d93..8548de565d643 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc @@ -250,7 +250,7 @@ class XdsClusterImplLb : public LoadBalancingPolicy { OrphanablePtr CreateChildPolicyLocked( const ChannelArgs& args); absl::Status UpdateChildPolicyLocked( - absl::StatusOr addresses, + absl::StatusOr> addresses, std::string resolution_note, const ChannelArgs& args); void MaybeUpdatePickerLocked(); @@ -569,7 +569,7 @@ OrphanablePtr XdsClusterImplLb::CreateChildPolicyLocked( } absl::Status XdsClusterImplLb::UpdateChildPolicyLocked( - absl::StatusOr addresses, + absl::StatusOr> addresses, std::string resolution_note, const ChannelArgs& args) { // Create policy if needed. if (child_policy_ == nullptr) { diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc index 4f6e8611b5a08..e613b3eb0d221 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc @@ -149,7 +149,8 @@ class XdsClusterManagerLb : public LoadBalancingPolicy { absl::Status UpdateLocked( RefCountedPtr config, - const absl::StatusOr& addresses, + const absl::StatusOr>& + addresses, const ChannelArgs& args); void ExitIdleLocked(); void ResetBackoffLocked(); @@ -482,7 +483,7 @@ XdsClusterManagerLb::ClusterChild::CreateChildPolicyLocked( absl::Status XdsClusterManagerLb::ClusterChild::UpdateLocked( RefCountedPtr config, - const absl::StatusOr& addresses, + const absl::StatusOr>& addresses, const ChannelArgs& args) { if (xds_cluster_manager_policy_->shutting_down_) return absl::OkStatus(); // Update child weight. diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc index 42f8673e724a2..6a58213347a1d 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc @@ -28,6 +28,7 @@ #include #include +#include "absl/functional/function_ref.h" #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/str_cat.h" @@ -61,6 +62,7 @@ #include "src/core/lib/gprpp/validation_errors.h" #include "src/core/lib/gprpp/work_serializer.h" #include "src/core/lib/iomgr/pollset_set.h" +#include "src/core/lib/iomgr/resolved_address.h" #include "src/core/lib/json/json.h" #include "src/core/lib/json/json_args.h" #include "src/core/lib/json/json_object_loader.h" @@ -390,7 +392,7 @@ class XdsClusterResolverLb : public LoadBalancingPolicy { absl::Status UpdateChildPolicyLocked(); OrphanablePtr CreateChildPolicyLocked( const ChannelArgs& args); - EndpointAddressesList CreateChildPolicyAddressesLocked(); + std::shared_ptr CreateChildPolicyAddressesLocked(); std::string CreateChildPolicyResolutionNoteLocked(); RefCountedPtr CreateChildPolicyConfigLocked(); ChannelArgs CreateChildPolicyArgsLocked(const ChannelArgs& args_in); @@ -529,10 +531,16 @@ XdsClusterResolverLb::DiscoveryMechanismEntry::config() const { ->config_->discovery_mechanisms()[discovery_mechanism->index()]; } +std::string MakeChildPolicyName(absl::string_view cluster_name, + size_t child_number) { + return absl::StrCat("{cluster=", cluster_name, + ", child_number=", child_number, "}"); +} + std::string XdsClusterResolverLb::DiscoveryMechanismEntry::GetChildPolicyName( size_t priority) const { - return absl::StrCat("{cluster=", config().cluster_name, - ", child_number=", priority_child_numbers[priority], "}"); + return MakeChildPolicyName(config().cluster_name, + priority_child_numbers[priority]); } // @@ -768,39 +776,76 @@ void XdsClusterResolverLb::OnResourceDoesNotExist(size_t index, // child policy-related methods // -EndpointAddressesList XdsClusterResolverLb::CreateChildPolicyAddressesLocked() { - EndpointAddressesList addresses; - for (const auto& discovery_entry : discovery_mechanisms_) { - const auto& priority_list = - GetUpdatePriorityList(*discovery_entry.latest_update); - for (size_t priority = 0; priority < priority_list.size(); ++priority) { - const auto& priority_entry = priority_list[priority]; - std::string priority_child_name = - discovery_entry.GetChildPolicyName(priority); - for (const auto& p : priority_entry.localities) { - const auto& locality_name = p.first; - const auto& locality = p.second; - std::vector hierarchical_path = { - RefCountedStringValue(priority_child_name), - RefCountedStringValue(locality_name->AsHumanReadableString())}; - auto hierarchical_path_attr = - MakeRefCounted(std::move(hierarchical_path)); - for (const auto& endpoint : locality.endpoints) { - uint32_t endpoint_weight = - locality.lb_weight * - endpoint.args().GetInt(GRPC_ARG_ADDRESS_WEIGHT).value_or(1); - addresses.emplace_back( - endpoint.addresses(), - endpoint.args() - .SetObject(hierarchical_path_attr) - .Set(GRPC_ARG_ADDRESS_WEIGHT, endpoint_weight) - .SetObject(locality_name->Ref()) - .Set(GRPC_ARG_XDS_LOCALITY_WEIGHT, locality.lb_weight)); +class PriorityEndpointIterator : public EndpointAddressesIterator { + public: + struct DiscoveryMechanismResult { + std::shared_ptr update; + std::string cluster_name; + std::vector priority_child_numbers; + + DiscoveryMechanismResult( + std::shared_ptr resource, + std::string cluster, std::vector child_numbers) + : update(std::move(resource)), + cluster_name(std::move(cluster)), + priority_child_numbers(std::move(child_numbers)) {} + + std::string GetChildPolicyName(size_t priority) const { + return MakeChildPolicyName(cluster_name, + priority_child_numbers[priority]); + } + }; + + explicit PriorityEndpointIterator( + std::vector results) + : results_(std::move(results)) {} + + void ForEach(absl::FunctionRef callback) + const override { + for (const auto& entry : results_) { + const auto& priority_list = GetUpdatePriorityList(*entry.update); + for (size_t priority = 0; priority < priority_list.size(); ++priority) { + const auto& priority_entry = priority_list[priority]; + std::string priority_child_name = entry.GetChildPolicyName(priority); + for (const auto& p : priority_entry.localities) { + const auto& locality_name = p.first; + const auto& locality = p.second; + std::vector hierarchical_path = { + RefCountedStringValue(priority_child_name), + RefCountedStringValue(locality_name->AsHumanReadableString())}; + auto hierarchical_path_attr = + MakeRefCounted(std::move(hierarchical_path)); + for (const auto& endpoint : locality.endpoints) { + uint32_t endpoint_weight = + locality.lb_weight * + endpoint.args().GetInt(GRPC_ARG_ADDRESS_WEIGHT).value_or(1); + callback(EndpointAddresses( + endpoint.addresses(), + endpoint.args() + .SetObject(hierarchical_path_attr) + .Set(GRPC_ARG_ADDRESS_WEIGHT, endpoint_weight) + .SetObject(locality_name->Ref()) + .Set(GRPC_ARG_XDS_LOCALITY_WEIGHT, locality.lb_weight))); + } } } } } - return addresses; + + private: + std::vector results_; +}; + +std::shared_ptr +XdsClusterResolverLb::CreateChildPolicyAddressesLocked() { + std::vector entries; + entries.reserve(discovery_mechanisms_.size()); + for (const auto& discovery_entry : discovery_mechanisms_) { + entries.emplace_back(discovery_entry.latest_update, + discovery_entry.config().cluster_name, + discovery_entry.priority_child_numbers); + } + return std::make_shared(std::move(entries)); } std::string XdsClusterResolverLb::CreateChildPolicyResolutionNoteLocked() { diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc index 7a1c6792a6c9f..c42219b4c42a8 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc @@ -18,7 +18,6 @@ #include "src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.h" -#include #include #include @@ -34,6 +33,7 @@ #include #include "absl/base/thread_annotations.h" +#include "absl/functional/function_ref.h" #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/str_cat.h" @@ -300,8 +300,7 @@ class XdsOverrideHostLb : public LoadBalancingPolicy { void MaybeUpdatePickerLocked(); - absl::StatusOr UpdateAddressMap( - absl::StatusOr endpoints); + void UpdateAddressMap(const EndpointAddressesIterator& endpoints); RefCountedPtr AdoptSubchannel( const grpc_resolved_address& address, @@ -508,12 +507,36 @@ void XdsOverrideHostLb::ResetBackoffLocked() { if (child_policy_ != nullptr) child_policy_->ResetBackoffLocked(); } +// Wraps the endpoint iterator and filters out endpoints in state DRAINING. +class ChildEndpointIterator : public EndpointAddressesIterator { + public: + explicit ChildEndpointIterator( + std::shared_ptr parent_it) + : parent_it_(std::move(parent_it)) {} + + void ForEach(absl::FunctionRef callback) + const override { + parent_it_->ForEach([&](const EndpointAddresses& endpoint) { + XdsHealthStatus status = GetEndpointHealthStatus(endpoint); + if (status.status() != XdsHealthStatus::kDraining) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) { + gpr_log(GPR_INFO, + "[xds_override_host_lb %p] endpoint %s: not draining, " + "passing to child", + this, endpoint.ToString().c_str()); + } + callback(endpoint); + } + }); + } + + private: + std::shared_ptr parent_it_; +}; + absl::Status XdsOverrideHostLb::UpdateLocked(UpdateArgs args) { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) { - gpr_log(GPR_INFO, - "[xds_override_host_lb %p] Received update with %" PRIuPTR - " addresses", - this, args.addresses.ok() ? args.addresses->size() : 0); + gpr_log(GPR_INFO, "[xds_override_host_lb %p] Received update", this); } auto old_config = std::move(config_); // Update config. @@ -521,13 +544,24 @@ absl::Status XdsOverrideHostLb::UpdateLocked(UpdateArgs args) { if (config_ == nullptr) { return absl::InvalidArgumentError("Missing policy config"); } + // Update address map and wrap endpoint iterator for child policy. + if (args.addresses.ok()) { + UpdateAddressMap(**args.addresses); + args.addresses = + std::make_shared(std::move(*args.addresses)); + } else { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) { + gpr_log(GPR_INFO, "[xds_override_host_lb %p] address error: %s", this, + args.addresses.status().ToString().c_str()); + } + } // Create child policy if needed. if (child_policy_ == nullptr) { child_policy_ = CreateChildPolicyLocked(args.args); } // Update child policy. UpdateArgs update_args; - update_args.addresses = UpdateAddressMap(std::move(args.addresses)); + update_args.addresses = std::move(args.addresses); update_args.resolution_note = std::move(args.resolution_note); update_args.config = config_->child_config(); update_args.args = std::move(args.args); @@ -578,18 +612,9 @@ OrphanablePtr XdsOverrideHostLb::CreateChildPolicyLocked( return lb_policy; } -absl::StatusOr XdsOverrideHostLb::UpdateAddressMap( - absl::StatusOr endpoints) { - if (!endpoints.ok()) { - if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) { - gpr_log(GPR_INFO, "[xds_override_host_lb %p] address error: %s", this, - endpoints.status().ToString().c_str()); - } - return endpoints; - } - // Construct the list of addresses to pass to the child policy and a - // map of address info from which to update subchannel_map_. - EndpointAddressesList child_addresses; +void XdsOverrideHostLb::UpdateAddressMap( + const EndpointAddressesIterator& endpoints) { + // Construct a map of address info from which to update subchannel_map_. struct AddressInfo { XdsHealthStatus eds_health_status; RefCountedStringValue address_list; @@ -597,25 +622,18 @@ absl::StatusOr XdsOverrideHostLb::UpdateAddressMap( : eds_health_status(status), address_list(std::move(addresses)) {} }; std::map addresses_for_map; - for (const auto& endpoint : *endpoints) { + endpoints.ForEach([&](const EndpointAddresses& endpoint) { XdsHealthStatus status = GetEndpointHealthStatus(endpoint); - if (status.status() != XdsHealthStatus::kDraining) { - if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) { - gpr_log(GPR_INFO, - "[xds_override_host_lb %p] endpoint %s: not draining, " - "passing to child", - this, endpoint.ToString().c_str()); - } - child_addresses.push_back(endpoint); - } else if (!config_->override_host_status_set().Contains(status)) { - // Skip draining hosts if not in the override status set. + // Skip draining hosts if not in the override status set. + if (status.status() == XdsHealthStatus::kDraining && + !config_->override_host_status_set().Contains(status)) { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) { gpr_log(GPR_INFO, "[xds_override_host_lb %p] endpoint %s: draining but not in " "override_host_status set -- ignoring", this, endpoint.ToString().c_str()); } - continue; + return; } std::vector addresses; addresses.reserve(endpoint.addresses().size()); @@ -641,7 +659,7 @@ absl::StatusOr XdsOverrideHostLb::UpdateAddressMap( std::piecewise_construct, std::forward_as_tuple(addresses[i]), std::forward_as_tuple(status, std::move(address_list))); } - } + }); // Now grab the lock and update subchannel_map_ from addresses_for_map. { MutexLock lock(&subchannel_map_mu_); @@ -688,7 +706,6 @@ absl::StatusOr XdsOverrideHostLb::UpdateAddressMap( it->second.set_address_list(std::move(address_info.address_list)); } } - return child_addresses; } RefCountedPtr diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc index 26f0ec9084a28..2d346217e47bb 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc @@ -21,7 +21,6 @@ #include #include #include -#include #include "absl/status/status.h" #include "absl/status/statusor.h" @@ -170,10 +169,10 @@ absl::Status XdsWrrLocalityLb::UpdateLocked(UpdateArgs args) { // Scan the addresses to find the weight for each locality. std::map locality_weights; if (args.addresses.ok()) { - for (const auto& address : *args.addresses) { - auto* locality_name = address.args().GetObject(); + (*args.addresses)->ForEach([&](const EndpointAddresses& endpoint) { + auto* locality_name = endpoint.args().GetObject(); uint32_t weight = - address.args().GetInt(GRPC_ARG_XDS_LOCALITY_WEIGHT).value_or(0); + endpoint.args().GetInt(GRPC_ARG_XDS_LOCALITY_WEIGHT).value_or(0); if (locality_name != nullptr && weight > 0) { auto p = locality_weights.emplace( locality_name->AsHumanReadableString(), weight); @@ -184,7 +183,7 @@ absl::Status XdsWrrLocalityLb::UpdateLocked(UpdateArgs args) { p.first->first.c_str(), p.first->second, weight); } } - } + }); } // Construct the config for the weighted_target policy. Json::Object weighted_targets; diff --git a/src/core/lib/gprpp/ref_counted_string.h b/src/core/lib/gprpp/ref_counted_string.h index 62fb15ded9815..dbe32b113da01 100644 --- a/src/core/lib/gprpp/ref_counted_string.h +++ b/src/core/lib/gprpp/ref_counted_string.h @@ -104,6 +104,19 @@ inline bool operator==(const RefCountedStringValue& lhs, return lhs.as_string_view() == rhs.as_string_view(); } +inline bool operator!=(const RefCountedStringValue& lhs, + absl::string_view rhs) { + return lhs.as_string_view() != rhs; +} +inline bool operator!=(absl::string_view lhs, + const RefCountedStringValue& rhs) { + return lhs != rhs.as_string_view(); +} +inline bool operator!=(const RefCountedStringValue& lhs, + const RefCountedStringValue& rhs) { + return lhs.as_string_view() != rhs.as_string_view(); +} + inline bool operator<(const RefCountedStringValue& lhs, absl::string_view rhs) { return lhs.as_string_view() < rhs; } diff --git a/src/core/lib/load_balancing/lb_policy.h b/src/core/lib/load_balancing/lb_policy.h index 2422339274e97..a36280c163b24 100644 --- a/src/core/lib/load_balancing/lb_policy.h +++ b/src/core/lib/load_balancing/lb_policy.h @@ -346,7 +346,7 @@ class LoadBalancingPolicy : public InternallyRefCounted { struct UpdateArgs { /// A list of endpoints, each with one or more address, or an error /// indicating a failure to obtain the list of addresses. - absl::StatusOr addresses; + absl::StatusOr> addresses; /// The LB policy config. RefCountedPtr config; /// A human-readable note providing context about the name resolution that diff --git a/src/core/lib/resolver/endpoint_addresses.cc b/src/core/lib/resolver/endpoint_addresses.cc index 7995163ad5d8f..7b5f4c0a329a8 100644 --- a/src/core/lib/resolver/endpoint_addresses.cc +++ b/src/core/lib/resolver/endpoint_addresses.cc @@ -22,7 +22,6 @@ #include -#include #include #include #include diff --git a/src/core/lib/resolver/endpoint_addresses.h b/src/core/lib/resolver/endpoint_addresses.h index 9d0d7c6edb8c4..5746df19c5b43 100644 --- a/src/core/lib/resolver/endpoint_addresses.h +++ b/src/core/lib/resolver/endpoint_addresses.h @@ -23,8 +23,11 @@ #include #include +#include #include +#include "absl/functional/function_ref.h" + #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/iomgr/resolved_address.h" @@ -64,6 +67,9 @@ class EndpointAddresses { bool operator==(const EndpointAddresses& other) const { return Cmp(other) == 0; } + bool operator!=(const EndpointAddresses& other) const { + return Cmp(other) != 0; + } bool operator<(const EndpointAddresses& other) const { return Cmp(other) < 0; } @@ -111,6 +117,48 @@ class EndpointAddressSet { std::set addresses_; }; +// An iterator interface for endpoints. +class EndpointAddressesIterator { + public: + virtual ~EndpointAddressesIterator() = default; + + // Invokes callback once for each endpoint. + virtual void ForEach( + absl::FunctionRef callback) const = 0; +}; + +// Iterator over a fixed list of endpoints. +class EndpointAddressesListIterator : public EndpointAddressesIterator { + public: + explicit EndpointAddressesListIterator(EndpointAddressesList endpoints) + : endpoints_(std::move(endpoints)) {} + + void ForEach(absl::FunctionRef callback) + const override { + for (const auto& endpoint : endpoints_) { + callback(endpoint); + } + } + + private: + EndpointAddressesList endpoints_; +}; + +// Iterator that returns only a single endpoint. +class SingleEndpointIterator : public EndpointAddressesIterator { + public: + explicit SingleEndpointIterator(EndpointAddresses endpoint) + : endpoint_(std::move(endpoint)) {} + + void ForEach(absl::FunctionRef callback) + const override { + callback(endpoint_); + } + + private: + EndpointAddresses endpoint_; +}; + } // namespace grpc_core #endif // GRPC_SRC_CORE_LIB_RESOLVER_ENDPOINT_ADDRESSES_H diff --git a/test/core/client_channel/lb_policy/lb_policy_test_lib.h b/test/core/client_channel/lb_policy/lb_policy_test_lib.h index 81365410c483b..27d7f38285bcb 100644 --- a/test/core/client_channel/lb_policy/lb_policy_test_lib.h +++ b/test/core/client_channel/lb_policy/lb_policy_test_lib.h @@ -773,7 +773,8 @@ class LoadBalancingPolicyTest : public ::testing::Test { absl::Span endpoints, RefCountedPtr config) { LoadBalancingPolicy::UpdateArgs update; - update.addresses.emplace(endpoints.begin(), endpoints.end()); + update.addresses = std::make_shared( + EndpointAddressesList(endpoints.begin(), endpoints.end())); update.config = std::move(config); return update; } diff --git a/test/core/client_channel/lb_policy/xds_override_host_test.cc b/test/core/client_channel/lb_policy/xds_override_host_test.cc index f3bf82fc6becc..7e9d45d7f6316 100644 --- a/test/core/client_channel/lb_policy/xds_override_host_test.cc +++ b/test/core/client_channel/lb_policy/xds_override_host_test.cc @@ -99,11 +99,13 @@ class XdsOverrideHostTest : public LoadBalancingPolicyTest { "HEALTHY"}) { LoadBalancingPolicy::UpdateArgs update; update.config = MakeXdsOverrideHostConfig(override_host_status); - update.addresses.emplace(); + EndpointAddressesList endpoints; for (auto address_and_status : addresses_and_statuses) { - update.addresses->push_back(MakeAddressWithHealthStatus( + endpoints.push_back(MakeAddressWithHealthStatus( address_and_status.first, address_and_status.second)); } + update.addresses = + std::make_shared(std::move(endpoints)); EXPECT_EQ(ApplyUpdate(update, lb_policy()), absl::OkStatus()); } diff --git a/test/core/util/test_lb_policies.cc b/test/core/util/test_lb_policies.cc index 8fb255d65edc2..f7e5abe6e2ce2 100644 --- a/test/core/util/test_lb_policies.cc +++ b/test/core/util/test_lb_policies.cc @@ -414,17 +414,19 @@ class FixedAddressLoadBalancingPolicy : public ForwardingLoadBalancingPolicy { config->address().c_str()); auto uri = URI::Parse(config->address()); args.config.reset(); - args.addresses = EndpointAddressesList(); + EndpointAddressesList addresses; if (uri.ok()) { grpc_resolved_address address; GPR_ASSERT(grpc_parse_uri(*uri, &address)); - args.addresses->emplace_back(address, ChannelArgs()); + addresses.emplace_back(address, ChannelArgs()); } else { gpr_log(GPR_ERROR, "%s: could not parse URI (%s), using empty address list", kFixedAddressLbPolicyName, uri.status().ToString().c_str()); args.resolution_note = "no address in fixed_address_lb policy"; } + args.addresses = + std::make_shared(std::move(addresses)); return ForwardingLoadBalancingPolicy::UpdateLocked(std::move(args)); } From b644164988db284014aeca97e5864e06582618f7 Mon Sep 17 00:00:00 2001 From: Tanvi Jagtap Date: Thu, 16 Nov 2023 01:07:05 -0800 Subject: [PATCH 009/127] Internal change. PiperOrigin-RevId: 582945647 --- src/objective-c/tests/Common/GRPCBlockCallbackResponseHandler.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objective-c/tests/Common/GRPCBlockCallbackResponseHandler.m b/src/objective-c/tests/Common/GRPCBlockCallbackResponseHandler.m index 39ceabad907e9..c797b0e91bc73 100644 --- a/src/objective-c/tests/Common/GRPCBlockCallbackResponseHandler.m +++ b/src/objective-c/tests/Common/GRPCBlockCallbackResponseHandler.m @@ -14,7 +14,7 @@ * limitations under the License. */ -#import +#import "GRPCBlockCallbackResponseHandler.h" @implementation GRPCBlockCallbackResponseHandler { void (^_initialMetadataCallback)(NSDictionary *); From 399fded21323b56fa155f94b2b44b8c031210854 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 16 Nov 2023 11:30:07 -0800 Subject: [PATCH 010/127] Reapply "[experiments] Explicit requirement check" (#34911) (#34915) This reverts commit b0e0659bab1555d9ff763b01ed5e138032d55c74. Closes #34915 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/34915 from ctiller:requires2 8e4f033317d67c88ddca520510be01f56f72a141 PiperOrigin-RevId: 583110606 --- bazel/experiments.bzl | 51 ++ bazel/grpc_build_system.bzl | 7 +- bazel/test_experiments.bzl | 7 + src/core/lib/experiments/config.cc | 13 + src/core/lib/experiments/config.h | 3 + src/core/lib/experiments/experiments.cc | 449 ++++++++++-------- src/core/lib/experiments/experiments.h | 66 +-- src/core/lib/experiments/experiments.yaml | 8 + src/core/lib/experiments/rollouts.yaml | 4 + test/core/experiments/fixtures/experiments.cc | 29 +- tools/codegen/core/experiments_compiler.py | 72 ++- 11 files changed, 473 insertions(+), 236 deletions(-) diff --git a/bazel/experiments.bzl b/bazel/experiments.bzl index 753a7955c6614..6e0200f2fd988 100644 --- a/bazel/experiments.bzl +++ b/bazel/experiments.bzl @@ -16,6 +16,57 @@ """Dictionary of tags to experiments so we know when to test different experiments.""" +EXPERIMENT_ENABLES = { + "block_excessive_requests_before_settings_ack": "block_excessive_requests_before_settings_ack", + "call_status_override_on_cancellation": "call_status_override_on_cancellation", + "canary_client_privacy": "canary_client_privacy", + "client_idleness": "client_idleness", + "client_privacy": "client_privacy", + "combiner_offload_to_event_engine": "combiner_offload_to_event_engine", + "chttp2_batch_requests": "chttp2_batch_requests,combiner_offload_to_event_engine", + "chttp2_offload_on_rst_stream": "chttp2_offload_on_rst_stream,combiner_offload_to_event_engine", + "event_engine_client": "event_engine_client", + "event_engine_dns": "event_engine_dns", + "event_engine_listener": "event_engine_listener", + "free_large_allocator": "free_large_allocator", + "http2_stats_fix": "http2_stats_fix", + "keepalive_fix": "keepalive_fix", + "keepalive_server_fix": "keepalive_server_fix", + "lazier_stream_updates": "lazier_stream_updates", + "memory_pressure_controller": "memory_pressure_controller", + "monitoring_experiment": "monitoring_experiment", + "multiping": "multiping", + "overload_protection": "overload_protection", + "peer_state_based_framing": "peer_state_based_framing", + "pending_queue_cap": "pending_queue_cap", + "pick_first_happy_eyeballs": "pick_first_happy_eyeballs", + "ping_on_rst_stream": "ping_on_rst_stream", + "promise_based_client_call": "promise_based_client_call", + "promise_based_inproc_transport": "promise_based_inproc_transport", + "promise_based_server_call": "lazier_stream_updates,promise_based_server_call", + "red_max_concurrent_streams": "red_max_concurrent_streams", + "registered_method_lookup_in_transport": "registered_method_lookup_in_transport", + "registered_methods_map": "registered_methods_map", + "rfc_max_concurrent_streams": "rfc_max_concurrent_streams", + "round_robin_delegate_to_pick_first": "round_robin_delegate_to_pick_first", + "rstpit": "rstpit", + "schedule_cancellation_over_write": "schedule_cancellation_over_write", + "separate_ping_from_keepalive": "separate_ping_from_keepalive", + "server_privacy": "server_privacy", + "settings_timeout": "settings_timeout", + "tarpit": "tarpit", + "tcp_frame_size_tuning": "tcp_frame_size_tuning", + "tcp_rcv_lowat": "tcp_rcv_lowat", + "trace_record_callops": "trace_record_callops", + "unconstrained_max_quota_buffer_size": "unconstrained_max_quota_buffer_size", + "uniquely_unowned": "uniquely_unowned", + "work_serializer_clears_time_cache": "work_serializer_clears_time_cache", + "work_serializer_dispatch": "work_serializer_dispatch", + "write_size_policy": "write_size_policy", + "write_size_cap": "write_size_cap,write_size_policy", + "wrr_delegate_to_pick_first": "wrr_delegate_to_pick_first", +} + EXPERIMENTS = { "windows": { "dbg": { diff --git a/bazel/grpc_build_system.bzl b/bazel/grpc_build_system.bzl index f4d131006bab8..abff3d2adc2ca 100644 --- a/bazel/grpc_build_system.bzl +++ b/bazel/grpc_build_system.bzl @@ -29,8 +29,8 @@ Contains macros used throughout the repo. load("//bazel:cc_grpc_library.bzl", "cc_grpc_library") load("//bazel:copts.bzl", "GRPC_DEFAULT_COPTS") -load("//bazel:experiments.bzl", "EXPERIMENTS") -load("//bazel:test_experiments.bzl", "TEST_EXPERIMENTS") +load("//bazel:experiments.bzl", "EXPERIMENTS", "EXPERIMENT_ENABLES") +load("//bazel:test_experiments.bzl", "TEST_EXPERIMENTS", "TEST_EXPERIMENT_ENABLES") load("@build_bazel_rules_apple//apple:ios.bzl", "ios_unit_test") load("@build_bazel_rules_apple//apple/testing/default_runner:ios_test_runner.bzl", "ios_test_runner") load("@com_google_protobuf//bazel:upb_proto_library.bzl", "upb_proto_library", "upb_proto_reflection_library") @@ -418,6 +418,7 @@ def expand_tests(name, srcs, deps, tags, args, exclude_pollers, uses_polling, us return tags experiment_config = list(poller_config) + experiment_enables = {k: v for k, v in EXPERIMENT_ENABLES.items() + TEST_EXPERIMENT_ENABLES.items()} for mode, config in mode_config.items(): enabled_tags, disabled_tags = config if enabled_tags != None: @@ -426,7 +427,7 @@ def expand_tests(name, srcs, deps, tags, args, exclude_pollers, uses_polling, us config = dict(config) config["name"] = config["name"] + "@experiment=" + experiment env = dict(config["env"]) - env["GRPC_EXPERIMENTS"] = experiment + env["GRPC_EXPERIMENTS"] = experiment_enables[experiment] env["GRPC_CI_EXPERIMENTS"] = "1" config["env"] = env tags = config["tags"] + ["experiment_variation"] diff --git a/bazel/test_experiments.bzl b/bazel/test_experiments.bzl index 21c52e747ad60..593d2dc468306 100644 --- a/bazel/test_experiments.bzl +++ b/bazel/test_experiments.bzl @@ -16,6 +16,13 @@ """Dictionary of tags to experiments so we know when to test different experiments.""" +TEST_EXPERIMENT_ENABLES = { + "test_experiment_1": "test_experiment_1", + "test_experiment_2": "test_experiment_2", + "test_experiment_3": "test_experiment_3", + "test_experiment_4": "test_experiment_4", +} + TEST_EXPERIMENTS = { "windows": { "dbg": { diff --git a/src/core/lib/experiments/config.cc b/src/core/lib/experiments/config.cc index 28cec78598e43..29964bb7575a4 100644 --- a/src/core/lib/experiments/config.cc +++ b/src/core/lib/experiments/config.cc @@ -135,6 +135,19 @@ GPR_ATTRIBUTE_NOINLINE Experiments LoadExperimentsFromConfigVariable() { std::string(experiment).c_str()); } } + for (size_t i = 0; i < kNumExperiments; i++) { + // If required experiments are not enabled, disable this one too. + for (size_t j = 0; j < g_experiment_metadata[i].num_required_experiments; + j++) { + // Require that we can check dependent requirements with a linear sweep + // (implies the experiments generator must DAG sort the experiments) + GPR_ASSERT(g_experiment_metadata[i].required_experiments[j] < i); + if (!experiments + .enabled[g_experiment_metadata[i].required_experiments[j]]) { + experiments.enabled[i] = false; + } + } + } return experiments; } diff --git a/src/core/lib/experiments/config.h b/src/core/lib/experiments/config.h index e93382634b709..a36083cbcc3e5 100644 --- a/src/core/lib/experiments/config.h +++ b/src/core/lib/experiments/config.h @@ -18,6 +18,7 @@ #include #include +#include #include "absl/functional/any_invocable.h" #include "absl/strings/string_view.h" @@ -30,6 +31,8 @@ struct ExperimentMetadata { const char* name; const char* description; const char* additional_constaints; + const uint8_t* required_experiments; + uint8_t num_required_experiments; bool default_value; bool allow_in_fuzzing_config; }; diff --git a/src/core/lib/experiments/experiments.cc b/src/core/lib/experiments/experiments.cc index a0fe5bab251d5..1e8c852545dda 100644 --- a/src/core/lib/experiments/experiments.cc +++ b/src/core/lib/experiments/experiments.cc @@ -18,6 +18,8 @@ #include "src/core/lib/experiments/experiments.h" +#include + #ifndef GRPC_EXPERIMENTS_ARE_FINAL #if defined(GRPC_CFSTREAM) @@ -34,13 +36,6 @@ const char* const additional_constraints_call_status_override_on_cancellation = const char* const description_canary_client_privacy = "If set, canary client privacy"; const char* const additional_constraints_canary_client_privacy = "{}"; -const char* const description_chttp2_batch_requests = - "Cap the number of requests received by one transport read prior to " - "offload."; -const char* const additional_constraints_chttp2_batch_requests = "{}"; -const char* const description_chttp2_offload_on_rst_stream = - "Offload work on RST_STREAM."; -const char* const additional_constraints_chttp2_offload_on_rst_stream = "{}"; const char* const description_client_idleness = "If enabled, client channel idleness is enabled by default."; const char* const additional_constraints_client_idleness = "{}"; @@ -50,6 +45,17 @@ const char* const description_combiner_offload_to_event_engine = "Offload Combiner work onto the EventEngine instead of the Executor."; const char* const additional_constraints_combiner_offload_to_event_engine = "{}"; +const char* const description_chttp2_batch_requests = + "Cap the number of requests received by one transport read prior to " + "offload."; +const char* const additional_constraints_chttp2_batch_requests = "{}"; +const uint8_t required_experiments_chttp2_batch_requests[] = { + static_cast(grpc_core::kExperimentIdCombinerOffloadToEventEngine)}; +const char* const description_chttp2_offload_on_rst_stream = + "Offload work on RST_STREAM."; +const char* const additional_constraints_chttp2_offload_on_rst_stream = "{}"; +const uint8_t required_experiments_chttp2_offload_on_rst_stream[] = { + static_cast(grpc_core::kExperimentIdCombinerOffloadToEventEngine)}; const char* const description_event_engine_client = "Use EventEngine clients instead of iomgr's grpc_tcp_client"; const char* const additional_constraints_event_engine_client = "{}"; @@ -121,6 +127,8 @@ const char* const description_promise_based_server_call = "If set, use the new gRPC promise based call code when it's appropriate " "(ie when all filters in a stack are promise based)"; const char* const additional_constraints_promise_based_server_call = "{}"; +const uint8_t required_experiments_promise_based_server_call[] = { + static_cast(grpc_core::kExperimentIdLazierStreamUpdates)}; const char* const description_red_max_concurrent_streams = "Perform random early rejection of requests that would exceed a newly " "reduced MAX_CONCURRENT_STREAMS but are allowed by the current."; @@ -193,12 +201,14 @@ const char* const description_work_serializer_dispatch = "callback, instead of running things inline in the first thread that " "successfully enqueues work."; const char* const additional_constraints_work_serializer_dispatch = "{}"; -const char* const description_write_size_cap = - "Limit outgoing writes proportional to the target write size"; -const char* const additional_constraints_write_size_cap = "{}"; const char* const description_write_size_policy = "Try to size writes such that they don't create too large of a backlog"; const char* const additional_constraints_write_size_policy = "{}"; +const char* const description_write_size_cap = + "Limit outgoing writes proportional to the target write size"; +const char* const additional_constraints_write_size_cap = "{}"; +const uint8_t required_experiments_write_size_cap[] = { + static_cast(grpc_core::kExperimentIdWriteSizePolicy)}; const char* const description_wrr_delegate_to_pick_first = "Change WRR code to delegate to pick_first as per dualstack backend " "design."; @@ -215,109 +225,126 @@ namespace grpc_core { const ExperimentMetadata g_experiment_metadata[] = { {"block_excessive_requests_before_settings_ack", description_block_excessive_requests_before_settings_ack, - additional_constraints_block_excessive_requests_before_settings_ack, true, - true}, + additional_constraints_block_excessive_requests_before_settings_ack, + nullptr, 0, true, true}, {"call_status_override_on_cancellation", description_call_status_override_on_cancellation, - additional_constraints_call_status_override_on_cancellation, + additional_constraints_call_status_override_on_cancellation, nullptr, 0, kDefaultForDebugOnly, true}, {"canary_client_privacy", description_canary_client_privacy, - additional_constraints_canary_client_privacy, false, false}, - {"chttp2_batch_requests", description_chttp2_batch_requests, - additional_constraints_chttp2_batch_requests, true, true}, - {"chttp2_offload_on_rst_stream", description_chttp2_offload_on_rst_stream, - additional_constraints_chttp2_offload_on_rst_stream, true, true}, + additional_constraints_canary_client_privacy, nullptr, 0, false, false}, {"client_idleness", description_client_idleness, - additional_constraints_client_idleness, true, true}, + additional_constraints_client_idleness, nullptr, 0, true, true}, {"client_privacy", description_client_privacy, - additional_constraints_client_privacy, false, false}, + additional_constraints_client_privacy, nullptr, 0, false, false}, {"combiner_offload_to_event_engine", description_combiner_offload_to_event_engine, - additional_constraints_combiner_offload_to_event_engine, true, true}, + additional_constraints_combiner_offload_to_event_engine, nullptr, 0, true, + true}, + {"chttp2_batch_requests", description_chttp2_batch_requests, + additional_constraints_chttp2_batch_requests, + required_experiments_chttp2_batch_requests, 1, true, true}, + {"chttp2_offload_on_rst_stream", description_chttp2_offload_on_rst_stream, + additional_constraints_chttp2_offload_on_rst_stream, + required_experiments_chttp2_offload_on_rst_stream, 1, true, true}, {"event_engine_client", description_event_engine_client, - additional_constraints_event_engine_client, false, true}, + additional_constraints_event_engine_client, nullptr, 0, false, true}, {"event_engine_dns", description_event_engine_dns, - additional_constraints_event_engine_dns, false, false}, + additional_constraints_event_engine_dns, nullptr, 0, false, false}, {"event_engine_listener", description_event_engine_listener, - additional_constraints_event_engine_listener, false, true}, + additional_constraints_event_engine_listener, nullptr, 0, false, true}, {"free_large_allocator", description_free_large_allocator, - additional_constraints_free_large_allocator, false, true}, + additional_constraints_free_large_allocator, nullptr, 0, false, true}, {"http2_stats_fix", description_http2_stats_fix, - additional_constraints_http2_stats_fix, true, true}, + additional_constraints_http2_stats_fix, nullptr, 0, true, true}, {"keepalive_fix", description_keepalive_fix, - additional_constraints_keepalive_fix, false, false}, + additional_constraints_keepalive_fix, nullptr, 0, false, false}, {"keepalive_server_fix", description_keepalive_server_fix, - additional_constraints_keepalive_server_fix, false, false}, + additional_constraints_keepalive_server_fix, nullptr, 0, false, false}, {"lazier_stream_updates", description_lazier_stream_updates, - additional_constraints_lazier_stream_updates, true, true}, + additional_constraints_lazier_stream_updates, nullptr, 0, true, true}, {"memory_pressure_controller", description_memory_pressure_controller, - additional_constraints_memory_pressure_controller, false, true}, + additional_constraints_memory_pressure_controller, nullptr, 0, false, + true}, {"monitoring_experiment", description_monitoring_experiment, - additional_constraints_monitoring_experiment, true, true}, + additional_constraints_monitoring_experiment, nullptr, 0, true, true}, {"multiping", description_multiping, additional_constraints_multiping, - false, true}, + nullptr, 0, false, true}, {"overload_protection", description_overload_protection, - additional_constraints_overload_protection, true, true}, + additional_constraints_overload_protection, nullptr, 0, true, true}, {"peer_state_based_framing", description_peer_state_based_framing, - additional_constraints_peer_state_based_framing, false, true}, + additional_constraints_peer_state_based_framing, nullptr, 0, false, true}, {"pending_queue_cap", description_pending_queue_cap, - additional_constraints_pending_queue_cap, true, true}, + additional_constraints_pending_queue_cap, nullptr, 0, true, true}, {"pick_first_happy_eyeballs", description_pick_first_happy_eyeballs, - additional_constraints_pick_first_happy_eyeballs, true, true}, + additional_constraints_pick_first_happy_eyeballs, nullptr, 0, true, true}, {"ping_on_rst_stream", description_ping_on_rst_stream, - additional_constraints_ping_on_rst_stream, true, true}, + additional_constraints_ping_on_rst_stream, nullptr, 0, true, true}, {"promise_based_client_call", description_promise_based_client_call, - additional_constraints_promise_based_client_call, false, true}, + additional_constraints_promise_based_client_call, nullptr, 0, false, true}, {"promise_based_inproc_transport", description_promise_based_inproc_transport, - additional_constraints_promise_based_inproc_transport, false, false}, + additional_constraints_promise_based_inproc_transport, nullptr, 0, false, + false}, {"promise_based_server_call", description_promise_based_server_call, - additional_constraints_promise_based_server_call, false, true}, + additional_constraints_promise_based_server_call, + required_experiments_promise_based_server_call, 1, false, true}, {"red_max_concurrent_streams", description_red_max_concurrent_streams, - additional_constraints_red_max_concurrent_streams, false, true}, + additional_constraints_red_max_concurrent_streams, nullptr, 0, false, + true}, {"registered_method_lookup_in_transport", description_registered_method_lookup_in_transport, - additional_constraints_registered_method_lookup_in_transport, true, true}, + additional_constraints_registered_method_lookup_in_transport, nullptr, 0, + true, true}, {"registered_methods_map", description_registered_methods_map, - additional_constraints_registered_methods_map, false, true}, + additional_constraints_registered_methods_map, nullptr, 0, false, true}, {"rfc_max_concurrent_streams", description_rfc_max_concurrent_streams, - additional_constraints_rfc_max_concurrent_streams, false, true}, + additional_constraints_rfc_max_concurrent_streams, nullptr, 0, false, + true}, {"round_robin_delegate_to_pick_first", description_round_robin_delegate_to_pick_first, - additional_constraints_round_robin_delegate_to_pick_first, true, true}, - {"rstpit", description_rstpit, additional_constraints_rstpit, false, true}, + additional_constraints_round_robin_delegate_to_pick_first, nullptr, 0, + true, true}, + {"rstpit", description_rstpit, additional_constraints_rstpit, nullptr, 0, + false, true}, {"schedule_cancellation_over_write", description_schedule_cancellation_over_write, - additional_constraints_schedule_cancellation_over_write, false, true}, + additional_constraints_schedule_cancellation_over_write, nullptr, 0, false, + true}, {"separate_ping_from_keepalive", description_separate_ping_from_keepalive, - additional_constraints_separate_ping_from_keepalive, true, true}, + additional_constraints_separate_ping_from_keepalive, nullptr, 0, true, + true}, {"server_privacy", description_server_privacy, - additional_constraints_server_privacy, false, false}, + additional_constraints_server_privacy, nullptr, 0, false, false}, {"settings_timeout", description_settings_timeout, - additional_constraints_settings_timeout, true, true}, - {"tarpit", description_tarpit, additional_constraints_tarpit, true, true}, + additional_constraints_settings_timeout, nullptr, 0, true, true}, + {"tarpit", description_tarpit, additional_constraints_tarpit, nullptr, 0, + true, true}, {"tcp_frame_size_tuning", description_tcp_frame_size_tuning, - additional_constraints_tcp_frame_size_tuning, false, true}, + additional_constraints_tcp_frame_size_tuning, nullptr, 0, false, true}, {"tcp_rcv_lowat", description_tcp_rcv_lowat, - additional_constraints_tcp_rcv_lowat, false, true}, + additional_constraints_tcp_rcv_lowat, nullptr, 0, false, true}, {"trace_record_callops", description_trace_record_callops, - additional_constraints_trace_record_callops, false, true}, + additional_constraints_trace_record_callops, nullptr, 0, false, true}, {"unconstrained_max_quota_buffer_size", description_unconstrained_max_quota_buffer_size, - additional_constraints_unconstrained_max_quota_buffer_size, false, true}, + additional_constraints_unconstrained_max_quota_buffer_size, nullptr, 0, + false, true}, {"uniquely_unowned", description_uniquely_unowned, - additional_constraints_uniquely_unowned, true, true}, + additional_constraints_uniquely_unowned, nullptr, 0, true, true}, {"work_serializer_clears_time_cache", description_work_serializer_clears_time_cache, - additional_constraints_work_serializer_clears_time_cache, true, true}, + additional_constraints_work_serializer_clears_time_cache, nullptr, 0, true, + true}, {"work_serializer_dispatch", description_work_serializer_dispatch, - additional_constraints_work_serializer_dispatch, false, true}, - {"write_size_cap", description_write_size_cap, - additional_constraints_write_size_cap, true, true}, + additional_constraints_work_serializer_dispatch, nullptr, 0, false, true}, {"write_size_policy", description_write_size_policy, - additional_constraints_write_size_policy, true, true}, + additional_constraints_write_size_policy, nullptr, 0, true, true}, + {"write_size_cap", description_write_size_cap, + additional_constraints_write_size_cap, required_experiments_write_size_cap, + 1, true, true}, {"wrr_delegate_to_pick_first", description_wrr_delegate_to_pick_first, - additional_constraints_wrr_delegate_to_pick_first, true, true}, + additional_constraints_wrr_delegate_to_pick_first, nullptr, 0, true, true}, }; } // namespace grpc_core @@ -336,13 +363,6 @@ const char* const additional_constraints_call_status_override_on_cancellation = const char* const description_canary_client_privacy = "If set, canary client privacy"; const char* const additional_constraints_canary_client_privacy = "{}"; -const char* const description_chttp2_batch_requests = - "Cap the number of requests received by one transport read prior to " - "offload."; -const char* const additional_constraints_chttp2_batch_requests = "{}"; -const char* const description_chttp2_offload_on_rst_stream = - "Offload work on RST_STREAM."; -const char* const additional_constraints_chttp2_offload_on_rst_stream = "{}"; const char* const description_client_idleness = "If enabled, client channel idleness is enabled by default."; const char* const additional_constraints_client_idleness = "{}"; @@ -352,6 +372,17 @@ const char* const description_combiner_offload_to_event_engine = "Offload Combiner work onto the EventEngine instead of the Executor."; const char* const additional_constraints_combiner_offload_to_event_engine = "{}"; +const char* const description_chttp2_batch_requests = + "Cap the number of requests received by one transport read prior to " + "offload."; +const char* const additional_constraints_chttp2_batch_requests = "{}"; +const uint8_t required_experiments_chttp2_batch_requests[] = { + static_cast(grpc_core::kExperimentIdCombinerOffloadToEventEngine)}; +const char* const description_chttp2_offload_on_rst_stream = + "Offload work on RST_STREAM."; +const char* const additional_constraints_chttp2_offload_on_rst_stream = "{}"; +const uint8_t required_experiments_chttp2_offload_on_rst_stream[] = { + static_cast(grpc_core::kExperimentIdCombinerOffloadToEventEngine)}; const char* const description_event_engine_client = "Use EventEngine clients instead of iomgr's grpc_tcp_client"; const char* const additional_constraints_event_engine_client = "{}"; @@ -423,6 +454,8 @@ const char* const description_promise_based_server_call = "If set, use the new gRPC promise based call code when it's appropriate " "(ie when all filters in a stack are promise based)"; const char* const additional_constraints_promise_based_server_call = "{}"; +const uint8_t required_experiments_promise_based_server_call[] = { + static_cast(grpc_core::kExperimentIdLazierStreamUpdates)}; const char* const description_red_max_concurrent_streams = "Perform random early rejection of requests that would exceed a newly " "reduced MAX_CONCURRENT_STREAMS but are allowed by the current."; @@ -495,12 +528,14 @@ const char* const description_work_serializer_dispatch = "callback, instead of running things inline in the first thread that " "successfully enqueues work."; const char* const additional_constraints_work_serializer_dispatch = "{}"; -const char* const description_write_size_cap = - "Limit outgoing writes proportional to the target write size"; -const char* const additional_constraints_write_size_cap = "{}"; const char* const description_write_size_policy = "Try to size writes such that they don't create too large of a backlog"; const char* const additional_constraints_write_size_policy = "{}"; +const char* const description_write_size_cap = + "Limit outgoing writes proportional to the target write size"; +const char* const additional_constraints_write_size_cap = "{}"; +const uint8_t required_experiments_write_size_cap[] = { + static_cast(grpc_core::kExperimentIdWriteSizePolicy)}; const char* const description_wrr_delegate_to_pick_first = "Change WRR code to delegate to pick_first as per dualstack backend " "design."; @@ -517,109 +552,126 @@ namespace grpc_core { const ExperimentMetadata g_experiment_metadata[] = { {"block_excessive_requests_before_settings_ack", description_block_excessive_requests_before_settings_ack, - additional_constraints_block_excessive_requests_before_settings_ack, true, - true}, + additional_constraints_block_excessive_requests_before_settings_ack, + nullptr, 0, true, true}, {"call_status_override_on_cancellation", description_call_status_override_on_cancellation, - additional_constraints_call_status_override_on_cancellation, + additional_constraints_call_status_override_on_cancellation, nullptr, 0, kDefaultForDebugOnly, true}, {"canary_client_privacy", description_canary_client_privacy, - additional_constraints_canary_client_privacy, false, false}, - {"chttp2_batch_requests", description_chttp2_batch_requests, - additional_constraints_chttp2_batch_requests, true, true}, - {"chttp2_offload_on_rst_stream", description_chttp2_offload_on_rst_stream, - additional_constraints_chttp2_offload_on_rst_stream, true, true}, + additional_constraints_canary_client_privacy, nullptr, 0, false, false}, {"client_idleness", description_client_idleness, - additional_constraints_client_idleness, true, true}, + additional_constraints_client_idleness, nullptr, 0, true, true}, {"client_privacy", description_client_privacy, - additional_constraints_client_privacy, false, false}, + additional_constraints_client_privacy, nullptr, 0, false, false}, {"combiner_offload_to_event_engine", description_combiner_offload_to_event_engine, - additional_constraints_combiner_offload_to_event_engine, true, true}, + additional_constraints_combiner_offload_to_event_engine, nullptr, 0, true, + true}, + {"chttp2_batch_requests", description_chttp2_batch_requests, + additional_constraints_chttp2_batch_requests, + required_experiments_chttp2_batch_requests, 1, true, true}, + {"chttp2_offload_on_rst_stream", description_chttp2_offload_on_rst_stream, + additional_constraints_chttp2_offload_on_rst_stream, + required_experiments_chttp2_offload_on_rst_stream, 1, true, true}, {"event_engine_client", description_event_engine_client, - additional_constraints_event_engine_client, false, true}, + additional_constraints_event_engine_client, nullptr, 0, false, true}, {"event_engine_dns", description_event_engine_dns, - additional_constraints_event_engine_dns, false, false}, + additional_constraints_event_engine_dns, nullptr, 0, false, false}, {"event_engine_listener", description_event_engine_listener, - additional_constraints_event_engine_listener, true, true}, + additional_constraints_event_engine_listener, nullptr, 0, true, true}, {"free_large_allocator", description_free_large_allocator, - additional_constraints_free_large_allocator, false, true}, + additional_constraints_free_large_allocator, nullptr, 0, false, true}, {"http2_stats_fix", description_http2_stats_fix, - additional_constraints_http2_stats_fix, true, true}, + additional_constraints_http2_stats_fix, nullptr, 0, true, true}, {"keepalive_fix", description_keepalive_fix, - additional_constraints_keepalive_fix, false, false}, + additional_constraints_keepalive_fix, nullptr, 0, false, false}, {"keepalive_server_fix", description_keepalive_server_fix, - additional_constraints_keepalive_server_fix, false, false}, + additional_constraints_keepalive_server_fix, nullptr, 0, false, false}, {"lazier_stream_updates", description_lazier_stream_updates, - additional_constraints_lazier_stream_updates, true, true}, + additional_constraints_lazier_stream_updates, nullptr, 0, true, true}, {"memory_pressure_controller", description_memory_pressure_controller, - additional_constraints_memory_pressure_controller, false, true}, + additional_constraints_memory_pressure_controller, nullptr, 0, false, + true}, {"monitoring_experiment", description_monitoring_experiment, - additional_constraints_monitoring_experiment, true, true}, + additional_constraints_monitoring_experiment, nullptr, 0, true, true}, {"multiping", description_multiping, additional_constraints_multiping, - false, true}, + nullptr, 0, false, true}, {"overload_protection", description_overload_protection, - additional_constraints_overload_protection, true, true}, + additional_constraints_overload_protection, nullptr, 0, true, true}, {"peer_state_based_framing", description_peer_state_based_framing, - additional_constraints_peer_state_based_framing, false, true}, + additional_constraints_peer_state_based_framing, nullptr, 0, false, true}, {"pending_queue_cap", description_pending_queue_cap, - additional_constraints_pending_queue_cap, true, true}, + additional_constraints_pending_queue_cap, nullptr, 0, true, true}, {"pick_first_happy_eyeballs", description_pick_first_happy_eyeballs, - additional_constraints_pick_first_happy_eyeballs, true, true}, + additional_constraints_pick_first_happy_eyeballs, nullptr, 0, true, true}, {"ping_on_rst_stream", description_ping_on_rst_stream, - additional_constraints_ping_on_rst_stream, true, true}, + additional_constraints_ping_on_rst_stream, nullptr, 0, true, true}, {"promise_based_client_call", description_promise_based_client_call, - additional_constraints_promise_based_client_call, false, true}, + additional_constraints_promise_based_client_call, nullptr, 0, false, true}, {"promise_based_inproc_transport", description_promise_based_inproc_transport, - additional_constraints_promise_based_inproc_transport, false, false}, + additional_constraints_promise_based_inproc_transport, nullptr, 0, false, + false}, {"promise_based_server_call", description_promise_based_server_call, - additional_constraints_promise_based_server_call, false, true}, + additional_constraints_promise_based_server_call, + required_experiments_promise_based_server_call, 1, false, true}, {"red_max_concurrent_streams", description_red_max_concurrent_streams, - additional_constraints_red_max_concurrent_streams, false, true}, + additional_constraints_red_max_concurrent_streams, nullptr, 0, false, + true}, {"registered_method_lookup_in_transport", description_registered_method_lookup_in_transport, - additional_constraints_registered_method_lookup_in_transport, true, true}, + additional_constraints_registered_method_lookup_in_transport, nullptr, 0, + true, true}, {"registered_methods_map", description_registered_methods_map, - additional_constraints_registered_methods_map, false, true}, + additional_constraints_registered_methods_map, nullptr, 0, false, true}, {"rfc_max_concurrent_streams", description_rfc_max_concurrent_streams, - additional_constraints_rfc_max_concurrent_streams, false, true}, + additional_constraints_rfc_max_concurrent_streams, nullptr, 0, false, + true}, {"round_robin_delegate_to_pick_first", description_round_robin_delegate_to_pick_first, - additional_constraints_round_robin_delegate_to_pick_first, true, true}, - {"rstpit", description_rstpit, additional_constraints_rstpit, false, true}, + additional_constraints_round_robin_delegate_to_pick_first, nullptr, 0, + true, true}, + {"rstpit", description_rstpit, additional_constraints_rstpit, nullptr, 0, + false, true}, {"schedule_cancellation_over_write", description_schedule_cancellation_over_write, - additional_constraints_schedule_cancellation_over_write, false, true}, + additional_constraints_schedule_cancellation_over_write, nullptr, 0, false, + true}, {"separate_ping_from_keepalive", description_separate_ping_from_keepalive, - additional_constraints_separate_ping_from_keepalive, true, true}, + additional_constraints_separate_ping_from_keepalive, nullptr, 0, true, + true}, {"server_privacy", description_server_privacy, - additional_constraints_server_privacy, false, false}, + additional_constraints_server_privacy, nullptr, 0, false, false}, {"settings_timeout", description_settings_timeout, - additional_constraints_settings_timeout, true, true}, - {"tarpit", description_tarpit, additional_constraints_tarpit, true, true}, + additional_constraints_settings_timeout, nullptr, 0, true, true}, + {"tarpit", description_tarpit, additional_constraints_tarpit, nullptr, 0, + true, true}, {"tcp_frame_size_tuning", description_tcp_frame_size_tuning, - additional_constraints_tcp_frame_size_tuning, false, true}, + additional_constraints_tcp_frame_size_tuning, nullptr, 0, false, true}, {"tcp_rcv_lowat", description_tcp_rcv_lowat, - additional_constraints_tcp_rcv_lowat, false, true}, + additional_constraints_tcp_rcv_lowat, nullptr, 0, false, true}, {"trace_record_callops", description_trace_record_callops, - additional_constraints_trace_record_callops, false, true}, + additional_constraints_trace_record_callops, nullptr, 0, false, true}, {"unconstrained_max_quota_buffer_size", description_unconstrained_max_quota_buffer_size, - additional_constraints_unconstrained_max_quota_buffer_size, false, true}, + additional_constraints_unconstrained_max_quota_buffer_size, nullptr, 0, + false, true}, {"uniquely_unowned", description_uniquely_unowned, - additional_constraints_uniquely_unowned, true, true}, + additional_constraints_uniquely_unowned, nullptr, 0, true, true}, {"work_serializer_clears_time_cache", description_work_serializer_clears_time_cache, - additional_constraints_work_serializer_clears_time_cache, true, true}, + additional_constraints_work_serializer_clears_time_cache, nullptr, 0, true, + true}, {"work_serializer_dispatch", description_work_serializer_dispatch, - additional_constraints_work_serializer_dispatch, false, true}, - {"write_size_cap", description_write_size_cap, - additional_constraints_write_size_cap, true, true}, + additional_constraints_work_serializer_dispatch, nullptr, 0, false, true}, {"write_size_policy", description_write_size_policy, - additional_constraints_write_size_policy, true, true}, + additional_constraints_write_size_policy, nullptr, 0, true, true}, + {"write_size_cap", description_write_size_cap, + additional_constraints_write_size_cap, required_experiments_write_size_cap, + 1, true, true}, {"wrr_delegate_to_pick_first", description_wrr_delegate_to_pick_first, - additional_constraints_wrr_delegate_to_pick_first, true, true}, + additional_constraints_wrr_delegate_to_pick_first, nullptr, 0, true, true}, }; } // namespace grpc_core @@ -638,13 +690,6 @@ const char* const additional_constraints_call_status_override_on_cancellation = const char* const description_canary_client_privacy = "If set, canary client privacy"; const char* const additional_constraints_canary_client_privacy = "{}"; -const char* const description_chttp2_batch_requests = - "Cap the number of requests received by one transport read prior to " - "offload."; -const char* const additional_constraints_chttp2_batch_requests = "{}"; -const char* const description_chttp2_offload_on_rst_stream = - "Offload work on RST_STREAM."; -const char* const additional_constraints_chttp2_offload_on_rst_stream = "{}"; const char* const description_client_idleness = "If enabled, client channel idleness is enabled by default."; const char* const additional_constraints_client_idleness = "{}"; @@ -654,6 +699,17 @@ const char* const description_combiner_offload_to_event_engine = "Offload Combiner work onto the EventEngine instead of the Executor."; const char* const additional_constraints_combiner_offload_to_event_engine = "{}"; +const char* const description_chttp2_batch_requests = + "Cap the number of requests received by one transport read prior to " + "offload."; +const char* const additional_constraints_chttp2_batch_requests = "{}"; +const uint8_t required_experiments_chttp2_batch_requests[] = { + static_cast(grpc_core::kExperimentIdCombinerOffloadToEventEngine)}; +const char* const description_chttp2_offload_on_rst_stream = + "Offload work on RST_STREAM."; +const char* const additional_constraints_chttp2_offload_on_rst_stream = "{}"; +const uint8_t required_experiments_chttp2_offload_on_rst_stream[] = { + static_cast(grpc_core::kExperimentIdCombinerOffloadToEventEngine)}; const char* const description_event_engine_client = "Use EventEngine clients instead of iomgr's grpc_tcp_client"; const char* const additional_constraints_event_engine_client = "{}"; @@ -725,6 +781,8 @@ const char* const description_promise_based_server_call = "If set, use the new gRPC promise based call code when it's appropriate " "(ie when all filters in a stack are promise based)"; const char* const additional_constraints_promise_based_server_call = "{}"; +const uint8_t required_experiments_promise_based_server_call[] = { + static_cast(grpc_core::kExperimentIdLazierStreamUpdates)}; const char* const description_red_max_concurrent_streams = "Perform random early rejection of requests that would exceed a newly " "reduced MAX_CONCURRENT_STREAMS but are allowed by the current."; @@ -797,12 +855,14 @@ const char* const description_work_serializer_dispatch = "callback, instead of running things inline in the first thread that " "successfully enqueues work."; const char* const additional_constraints_work_serializer_dispatch = "{}"; -const char* const description_write_size_cap = - "Limit outgoing writes proportional to the target write size"; -const char* const additional_constraints_write_size_cap = "{}"; const char* const description_write_size_policy = "Try to size writes such that they don't create too large of a backlog"; const char* const additional_constraints_write_size_policy = "{}"; +const char* const description_write_size_cap = + "Limit outgoing writes proportional to the target write size"; +const char* const additional_constraints_write_size_cap = "{}"; +const uint8_t required_experiments_write_size_cap[] = { + static_cast(grpc_core::kExperimentIdWriteSizePolicy)}; const char* const description_wrr_delegate_to_pick_first = "Change WRR code to delegate to pick_first as per dualstack backend " "design."; @@ -819,109 +879,126 @@ namespace grpc_core { const ExperimentMetadata g_experiment_metadata[] = { {"block_excessive_requests_before_settings_ack", description_block_excessive_requests_before_settings_ack, - additional_constraints_block_excessive_requests_before_settings_ack, true, - true}, + additional_constraints_block_excessive_requests_before_settings_ack, + nullptr, 0, true, true}, {"call_status_override_on_cancellation", description_call_status_override_on_cancellation, - additional_constraints_call_status_override_on_cancellation, + additional_constraints_call_status_override_on_cancellation, nullptr, 0, kDefaultForDebugOnly, true}, {"canary_client_privacy", description_canary_client_privacy, - additional_constraints_canary_client_privacy, false, false}, - {"chttp2_batch_requests", description_chttp2_batch_requests, - additional_constraints_chttp2_batch_requests, true, true}, - {"chttp2_offload_on_rst_stream", description_chttp2_offload_on_rst_stream, - additional_constraints_chttp2_offload_on_rst_stream, true, true}, + additional_constraints_canary_client_privacy, nullptr, 0, false, false}, {"client_idleness", description_client_idleness, - additional_constraints_client_idleness, true, true}, + additional_constraints_client_idleness, nullptr, 0, true, true}, {"client_privacy", description_client_privacy, - additional_constraints_client_privacy, false, false}, + additional_constraints_client_privacy, nullptr, 0, false, false}, {"combiner_offload_to_event_engine", description_combiner_offload_to_event_engine, - additional_constraints_combiner_offload_to_event_engine, true, true}, + additional_constraints_combiner_offload_to_event_engine, nullptr, 0, true, + true}, + {"chttp2_batch_requests", description_chttp2_batch_requests, + additional_constraints_chttp2_batch_requests, + required_experiments_chttp2_batch_requests, 1, true, true}, + {"chttp2_offload_on_rst_stream", description_chttp2_offload_on_rst_stream, + additional_constraints_chttp2_offload_on_rst_stream, + required_experiments_chttp2_offload_on_rst_stream, 1, true, true}, {"event_engine_client", description_event_engine_client, - additional_constraints_event_engine_client, false, true}, + additional_constraints_event_engine_client, nullptr, 0, false, true}, {"event_engine_dns", description_event_engine_dns, - additional_constraints_event_engine_dns, false, false}, + additional_constraints_event_engine_dns, nullptr, 0, false, false}, {"event_engine_listener", description_event_engine_listener, - additional_constraints_event_engine_listener, true, true}, + additional_constraints_event_engine_listener, nullptr, 0, true, true}, {"free_large_allocator", description_free_large_allocator, - additional_constraints_free_large_allocator, false, true}, + additional_constraints_free_large_allocator, nullptr, 0, false, true}, {"http2_stats_fix", description_http2_stats_fix, - additional_constraints_http2_stats_fix, true, true}, + additional_constraints_http2_stats_fix, nullptr, 0, true, true}, {"keepalive_fix", description_keepalive_fix, - additional_constraints_keepalive_fix, false, false}, + additional_constraints_keepalive_fix, nullptr, 0, false, false}, {"keepalive_server_fix", description_keepalive_server_fix, - additional_constraints_keepalive_server_fix, false, false}, + additional_constraints_keepalive_server_fix, nullptr, 0, false, false}, {"lazier_stream_updates", description_lazier_stream_updates, - additional_constraints_lazier_stream_updates, true, true}, + additional_constraints_lazier_stream_updates, nullptr, 0, true, true}, {"memory_pressure_controller", description_memory_pressure_controller, - additional_constraints_memory_pressure_controller, false, true}, + additional_constraints_memory_pressure_controller, nullptr, 0, false, + true}, {"monitoring_experiment", description_monitoring_experiment, - additional_constraints_monitoring_experiment, true, true}, + additional_constraints_monitoring_experiment, nullptr, 0, true, true}, {"multiping", description_multiping, additional_constraints_multiping, - false, true}, + nullptr, 0, false, true}, {"overload_protection", description_overload_protection, - additional_constraints_overload_protection, true, true}, + additional_constraints_overload_protection, nullptr, 0, true, true}, {"peer_state_based_framing", description_peer_state_based_framing, - additional_constraints_peer_state_based_framing, false, true}, + additional_constraints_peer_state_based_framing, nullptr, 0, false, true}, {"pending_queue_cap", description_pending_queue_cap, - additional_constraints_pending_queue_cap, true, true}, + additional_constraints_pending_queue_cap, nullptr, 0, true, true}, {"pick_first_happy_eyeballs", description_pick_first_happy_eyeballs, - additional_constraints_pick_first_happy_eyeballs, true, true}, + additional_constraints_pick_first_happy_eyeballs, nullptr, 0, true, true}, {"ping_on_rst_stream", description_ping_on_rst_stream, - additional_constraints_ping_on_rst_stream, true, true}, + additional_constraints_ping_on_rst_stream, nullptr, 0, true, true}, {"promise_based_client_call", description_promise_based_client_call, - additional_constraints_promise_based_client_call, false, true}, + additional_constraints_promise_based_client_call, nullptr, 0, false, true}, {"promise_based_inproc_transport", description_promise_based_inproc_transport, - additional_constraints_promise_based_inproc_transport, false, false}, + additional_constraints_promise_based_inproc_transport, nullptr, 0, false, + false}, {"promise_based_server_call", description_promise_based_server_call, - additional_constraints_promise_based_server_call, false, true}, + additional_constraints_promise_based_server_call, + required_experiments_promise_based_server_call, 1, false, true}, {"red_max_concurrent_streams", description_red_max_concurrent_streams, - additional_constraints_red_max_concurrent_streams, false, true}, + additional_constraints_red_max_concurrent_streams, nullptr, 0, false, + true}, {"registered_method_lookup_in_transport", description_registered_method_lookup_in_transport, - additional_constraints_registered_method_lookup_in_transport, true, true}, + additional_constraints_registered_method_lookup_in_transport, nullptr, 0, + true, true}, {"registered_methods_map", description_registered_methods_map, - additional_constraints_registered_methods_map, false, true}, + additional_constraints_registered_methods_map, nullptr, 0, false, true}, {"rfc_max_concurrent_streams", description_rfc_max_concurrent_streams, - additional_constraints_rfc_max_concurrent_streams, false, true}, + additional_constraints_rfc_max_concurrent_streams, nullptr, 0, false, + true}, {"round_robin_delegate_to_pick_first", description_round_robin_delegate_to_pick_first, - additional_constraints_round_robin_delegate_to_pick_first, true, true}, - {"rstpit", description_rstpit, additional_constraints_rstpit, false, true}, + additional_constraints_round_robin_delegate_to_pick_first, nullptr, 0, + true, true}, + {"rstpit", description_rstpit, additional_constraints_rstpit, nullptr, 0, + false, true}, {"schedule_cancellation_over_write", description_schedule_cancellation_over_write, - additional_constraints_schedule_cancellation_over_write, false, true}, + additional_constraints_schedule_cancellation_over_write, nullptr, 0, false, + true}, {"separate_ping_from_keepalive", description_separate_ping_from_keepalive, - additional_constraints_separate_ping_from_keepalive, true, true}, + additional_constraints_separate_ping_from_keepalive, nullptr, 0, true, + true}, {"server_privacy", description_server_privacy, - additional_constraints_server_privacy, false, false}, + additional_constraints_server_privacy, nullptr, 0, false, false}, {"settings_timeout", description_settings_timeout, - additional_constraints_settings_timeout, true, true}, - {"tarpit", description_tarpit, additional_constraints_tarpit, true, true}, + additional_constraints_settings_timeout, nullptr, 0, true, true}, + {"tarpit", description_tarpit, additional_constraints_tarpit, nullptr, 0, + true, true}, {"tcp_frame_size_tuning", description_tcp_frame_size_tuning, - additional_constraints_tcp_frame_size_tuning, false, true}, + additional_constraints_tcp_frame_size_tuning, nullptr, 0, false, true}, {"tcp_rcv_lowat", description_tcp_rcv_lowat, - additional_constraints_tcp_rcv_lowat, false, true}, + additional_constraints_tcp_rcv_lowat, nullptr, 0, false, true}, {"trace_record_callops", description_trace_record_callops, - additional_constraints_trace_record_callops, false, true}, + additional_constraints_trace_record_callops, nullptr, 0, false, true}, {"unconstrained_max_quota_buffer_size", description_unconstrained_max_quota_buffer_size, - additional_constraints_unconstrained_max_quota_buffer_size, false, true}, + additional_constraints_unconstrained_max_quota_buffer_size, nullptr, 0, + false, true}, {"uniquely_unowned", description_uniquely_unowned, - additional_constraints_uniquely_unowned, true, true}, + additional_constraints_uniquely_unowned, nullptr, 0, true, true}, {"work_serializer_clears_time_cache", description_work_serializer_clears_time_cache, - additional_constraints_work_serializer_clears_time_cache, true, true}, + additional_constraints_work_serializer_clears_time_cache, nullptr, 0, true, + true}, {"work_serializer_dispatch", description_work_serializer_dispatch, - additional_constraints_work_serializer_dispatch, false, true}, - {"write_size_cap", description_write_size_cap, - additional_constraints_write_size_cap, true, true}, + additional_constraints_work_serializer_dispatch, nullptr, 0, false, true}, {"write_size_policy", description_write_size_policy, - additional_constraints_write_size_policy, true, true}, + additional_constraints_write_size_policy, nullptr, 0, true, true}, + {"write_size_cap", description_write_size_cap, + additional_constraints_write_size_cap, required_experiments_write_size_cap, + 1, true, true}, {"wrr_delegate_to_pick_first", description_wrr_delegate_to_pick_first, - additional_constraints_wrr_delegate_to_pick_first, true, true}, + additional_constraints_wrr_delegate_to_pick_first, nullptr, 0, true, true}, }; } // namespace grpc_core diff --git a/src/core/lib/experiments/experiments.h b/src/core/lib/experiments/experiments.h index 5304e7a549ad6..60db6dfc1f36d 100644 --- a/src/core/lib/experiments/experiments.h +++ b/src/core/lib/experiments/experiments.h @@ -70,15 +70,15 @@ inline bool IsCallStatusOverrideOnCancellationEnabled() { #endif } inline bool IsCanaryClientPrivacyEnabled() { return false; } -#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_BATCH_REQUESTS -inline bool IsChttp2BatchRequestsEnabled() { return true; } -#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_OFFLOAD_ON_RST_STREAM -inline bool IsChttp2OffloadOnRstStreamEnabled() { return true; } #define GRPC_EXPERIMENT_IS_INCLUDED_CLIENT_IDLENESS inline bool IsClientIdlenessEnabled() { return true; } inline bool IsClientPrivacyEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_COMBINER_OFFLOAD_TO_EVENT_ENGINE inline bool IsCombinerOffloadToEventEngineEnabled() { return true; } +#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_BATCH_REQUESTS +inline bool IsChttp2BatchRequestsEnabled() { return true; } +#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_OFFLOAD_ON_RST_STREAM +inline bool IsChttp2OffloadOnRstStreamEnabled() { return true; } inline bool IsEventEngineClientEnabled() { return false; } inline bool IsEventEngineDnsEnabled() { return false; } inline bool IsEventEngineListenerEnabled() { return false; } @@ -130,10 +130,10 @@ inline bool IsUniquelyUnownedEnabled() { return true; } #define GRPC_EXPERIMENT_IS_INCLUDED_WORK_SERIALIZER_CLEARS_TIME_CACHE inline bool IsWorkSerializerClearsTimeCacheEnabled() { return true; } inline bool IsWorkSerializerDispatchEnabled() { return false; } -#define GRPC_EXPERIMENT_IS_INCLUDED_WRITE_SIZE_CAP -inline bool IsWriteSizeCapEnabled() { return true; } #define GRPC_EXPERIMENT_IS_INCLUDED_WRITE_SIZE_POLICY inline bool IsWriteSizePolicyEnabled() { return true; } +#define GRPC_EXPERIMENT_IS_INCLUDED_WRITE_SIZE_CAP +inline bool IsWriteSizeCapEnabled() { return true; } #define GRPC_EXPERIMENT_IS_INCLUDED_WRR_DELEGATE_TO_PICK_FIRST inline bool IsWrrDelegateToPickFirstEnabled() { return true; } @@ -151,15 +151,15 @@ inline bool IsCallStatusOverrideOnCancellationEnabled() { #endif } inline bool IsCanaryClientPrivacyEnabled() { return false; } -#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_BATCH_REQUESTS -inline bool IsChttp2BatchRequestsEnabled() { return true; } -#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_OFFLOAD_ON_RST_STREAM -inline bool IsChttp2OffloadOnRstStreamEnabled() { return true; } #define GRPC_EXPERIMENT_IS_INCLUDED_CLIENT_IDLENESS inline bool IsClientIdlenessEnabled() { return true; } inline bool IsClientPrivacyEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_COMBINER_OFFLOAD_TO_EVENT_ENGINE inline bool IsCombinerOffloadToEventEngineEnabled() { return true; } +#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_BATCH_REQUESTS +inline bool IsChttp2BatchRequestsEnabled() { return true; } +#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_OFFLOAD_ON_RST_STREAM +inline bool IsChttp2OffloadOnRstStreamEnabled() { return true; } inline bool IsEventEngineClientEnabled() { return false; } inline bool IsEventEngineDnsEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_EVENT_ENGINE_LISTENER @@ -212,10 +212,10 @@ inline bool IsUniquelyUnownedEnabled() { return true; } #define GRPC_EXPERIMENT_IS_INCLUDED_WORK_SERIALIZER_CLEARS_TIME_CACHE inline bool IsWorkSerializerClearsTimeCacheEnabled() { return true; } inline bool IsWorkSerializerDispatchEnabled() { return false; } -#define GRPC_EXPERIMENT_IS_INCLUDED_WRITE_SIZE_CAP -inline bool IsWriteSizeCapEnabled() { return true; } #define GRPC_EXPERIMENT_IS_INCLUDED_WRITE_SIZE_POLICY inline bool IsWriteSizePolicyEnabled() { return true; } +#define GRPC_EXPERIMENT_IS_INCLUDED_WRITE_SIZE_CAP +inline bool IsWriteSizeCapEnabled() { return true; } #define GRPC_EXPERIMENT_IS_INCLUDED_WRR_DELEGATE_TO_PICK_FIRST inline bool IsWrrDelegateToPickFirstEnabled() { return true; } @@ -233,15 +233,15 @@ inline bool IsCallStatusOverrideOnCancellationEnabled() { #endif } inline bool IsCanaryClientPrivacyEnabled() { return false; } -#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_BATCH_REQUESTS -inline bool IsChttp2BatchRequestsEnabled() { return true; } -#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_OFFLOAD_ON_RST_STREAM -inline bool IsChttp2OffloadOnRstStreamEnabled() { return true; } #define GRPC_EXPERIMENT_IS_INCLUDED_CLIENT_IDLENESS inline bool IsClientIdlenessEnabled() { return true; } inline bool IsClientPrivacyEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_COMBINER_OFFLOAD_TO_EVENT_ENGINE inline bool IsCombinerOffloadToEventEngineEnabled() { return true; } +#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_BATCH_REQUESTS +inline bool IsChttp2BatchRequestsEnabled() { return true; } +#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_OFFLOAD_ON_RST_STREAM +inline bool IsChttp2OffloadOnRstStreamEnabled() { return true; } inline bool IsEventEngineClientEnabled() { return false; } inline bool IsEventEngineDnsEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_EVENT_ENGINE_LISTENER @@ -294,10 +294,10 @@ inline bool IsUniquelyUnownedEnabled() { return true; } #define GRPC_EXPERIMENT_IS_INCLUDED_WORK_SERIALIZER_CLEARS_TIME_CACHE inline bool IsWorkSerializerClearsTimeCacheEnabled() { return true; } inline bool IsWorkSerializerDispatchEnabled() { return false; } -#define GRPC_EXPERIMENT_IS_INCLUDED_WRITE_SIZE_CAP -inline bool IsWriteSizeCapEnabled() { return true; } #define GRPC_EXPERIMENT_IS_INCLUDED_WRITE_SIZE_POLICY inline bool IsWriteSizePolicyEnabled() { return true; } +#define GRPC_EXPERIMENT_IS_INCLUDED_WRITE_SIZE_CAP +inline bool IsWriteSizeCapEnabled() { return true; } #define GRPC_EXPERIMENT_IS_INCLUDED_WRR_DELEGATE_TO_PICK_FIRST inline bool IsWrrDelegateToPickFirstEnabled() { return true; } #endif @@ -307,11 +307,11 @@ enum ExperimentIds { kExperimentIdBlockExcessiveRequestsBeforeSettingsAck, kExperimentIdCallStatusOverrideOnCancellation, kExperimentIdCanaryClientPrivacy, - kExperimentIdChttp2BatchRequests, - kExperimentIdChttp2OffloadOnRstStream, kExperimentIdClientIdleness, kExperimentIdClientPrivacy, kExperimentIdCombinerOffloadToEventEngine, + kExperimentIdChttp2BatchRequests, + kExperimentIdChttp2OffloadOnRstStream, kExperimentIdEventEngineClient, kExperimentIdEventEngineDns, kExperimentIdEventEngineListener, @@ -349,8 +349,8 @@ enum ExperimentIds { kExperimentIdUniquelyUnowned, kExperimentIdWorkSerializerClearsTimeCache, kExperimentIdWorkSerializerDispatch, - kExperimentIdWriteSizeCap, kExperimentIdWriteSizePolicy, + kExperimentIdWriteSizeCap, kExperimentIdWrrDelegateToPickFirst, kNumExperiments }; @@ -367,14 +367,6 @@ inline bool IsCallStatusOverrideOnCancellationEnabled() { inline bool IsCanaryClientPrivacyEnabled() { return IsExperimentEnabled(kExperimentIdCanaryClientPrivacy); } -#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_BATCH_REQUESTS -inline bool IsChttp2BatchRequestsEnabled() { - return IsExperimentEnabled(kExperimentIdChttp2BatchRequests); -} -#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_OFFLOAD_ON_RST_STREAM -inline bool IsChttp2OffloadOnRstStreamEnabled() { - return IsExperimentEnabled(kExperimentIdChttp2OffloadOnRstStream); -} #define GRPC_EXPERIMENT_IS_INCLUDED_CLIENT_IDLENESS inline bool IsClientIdlenessEnabled() { return IsExperimentEnabled(kExperimentIdClientIdleness); @@ -387,6 +379,14 @@ inline bool IsClientPrivacyEnabled() { inline bool IsCombinerOffloadToEventEngineEnabled() { return IsExperimentEnabled(kExperimentIdCombinerOffloadToEventEngine); } +#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_BATCH_REQUESTS +inline bool IsChttp2BatchRequestsEnabled() { + return IsExperimentEnabled(kExperimentIdChttp2BatchRequests); +} +#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_OFFLOAD_ON_RST_STREAM +inline bool IsChttp2OffloadOnRstStreamEnabled() { + return IsExperimentEnabled(kExperimentIdChttp2OffloadOnRstStream); +} #define GRPC_EXPERIMENT_IS_INCLUDED_EVENT_ENGINE_CLIENT inline bool IsEventEngineClientEnabled() { return IsExperimentEnabled(kExperimentIdEventEngineClient); @@ -535,14 +535,14 @@ inline bool IsWorkSerializerClearsTimeCacheEnabled() { inline bool IsWorkSerializerDispatchEnabled() { return IsExperimentEnabled(kExperimentIdWorkSerializerDispatch); } -#define GRPC_EXPERIMENT_IS_INCLUDED_WRITE_SIZE_CAP -inline bool IsWriteSizeCapEnabled() { - return IsExperimentEnabled(kExperimentIdWriteSizeCap); -} #define GRPC_EXPERIMENT_IS_INCLUDED_WRITE_SIZE_POLICY inline bool IsWriteSizePolicyEnabled() { return IsExperimentEnabled(kExperimentIdWriteSizePolicy); } +#define GRPC_EXPERIMENT_IS_INCLUDED_WRITE_SIZE_CAP +inline bool IsWriteSizeCapEnabled() { + return IsExperimentEnabled(kExperimentIdWriteSizeCap); +} #define GRPC_EXPERIMENT_IS_INCLUDED_WRR_DELEGATE_TO_PICK_FIRST inline bool IsWrrDelegateToPickFirstEnabled() { return IsExperimentEnabled(kExperimentIdWrrDelegateToPickFirst); diff --git a/src/core/lib/experiments/experiments.yaml b/src/core/lib/experiments/experiments.yaml index 9a4112b771d8d..60ed3d7eb2e10 100644 --- a/src/core/lib/experiments/experiments.yaml +++ b/src/core/lib/experiments/experiments.yaml @@ -22,6 +22,10 @@ # allow_in_fuzzing_config: optional boolean (true if not specified) # if false, this experiment will not be included in fuzzers that # explore the config space +# requires: A list of names of experiments that this experiment depends on. +# Defaults to the empty list. +# If any of the experiments in the required list is determined to +# be disabled at runtime, this experiment is disabled at runtime. # # Well known test tags: # core_end2end_test: all tests, fixtures in the core end2end suite @@ -59,12 +63,14 @@ expiry: 2024/03/03 owner: ctiller@google.com test_tags: ["cpp_end2end_test", "flow_control_test"] + requires: [combiner_offload_to_event_engine] - name: chttp2_offload_on_rst_stream description: Offload work on RST_STREAM. expiry: 2024/03/03 owner: ctiller@google.com test_tags: ["cpp_end2end_test", "flow_control_test"] + requires: [combiner_offload_to_event_engine] - name: client_idleness description: If enabled, client channel idleness is enabled by default. expiry: 2023/12/15 @@ -210,6 +216,7 @@ expiry: 2024/06/14 owner: ctiller@google.com test_tags: ["core_end2end_test", "cpp_end2end_test", "xds_end2end_test", "logging_test"] + requires: [lazier_stream_updates] - name: red_max_concurrent_streams description: Perform random early rejection of requests that would exceed a newly reduced @@ -331,6 +338,7 @@ expiry: 2024/03/03 owner: ctiller@google.com test_tags: [flow_control_test] + requires: [write_size_policy] - name: write_size_policy description: Try to size writes such that they don't create too large of a backlog diff --git a/src/core/lib/experiments/rollouts.yaml b/src/core/lib/experiments/rollouts.yaml index c35ce9f1cdb23..00b404c61de90 100644 --- a/src/core/lib/experiments/rollouts.yaml +++ b/src/core/lib/experiments/rollouts.yaml @@ -22,6 +22,10 @@ # - debug - the experiment defaults to on in debug builds, # off in release builds in all platforms. # - true - the experiment defaults to on in all platforms. +# requires: A list of names of experiments that this experiment depends on. +# Defaults to the empty list. +# If any of the experiments in the required list is determined to +# be disabled at runtime, this experiment is disabled at runtime. # # [OR] the default can be platform specific: # ----------------------------------------- diff --git a/test/core/experiments/fixtures/experiments.cc b/test/core/experiments/fixtures/experiments.cc index 7d13644bb393b..37b5e9ad9d3bb 100644 --- a/test/core/experiments/fixtures/experiments.cc +++ b/test/core/experiments/fixtures/experiments.cc @@ -41,13 +41,14 @@ namespace grpc_core { const ExperimentMetadata g_test_experiment_metadata[] = { {"test_experiment_1", description_test_experiment_1, - additional_constraints_test_experiment_1, false, true}, + additional_constraints_test_experiment_1, nullptr, 0, false, true}, {"test_experiment_2", description_test_experiment_2, - additional_constraints_test_experiment_2, true, true}, + additional_constraints_test_experiment_2, nullptr, 0, true, true}, {"test_experiment_3", description_test_experiment_3, - additional_constraints_test_experiment_3, kDefaultForDebugOnly, true}, + additional_constraints_test_experiment_3, nullptr, 0, kDefaultForDebugOnly, + true}, {"test_experiment_4", description_test_experiment_4, - additional_constraints_test_experiment_4, true, true}, + additional_constraints_test_experiment_4, nullptr, 0, true, true}, }; } // namespace grpc_core @@ -73,13 +74,14 @@ namespace grpc_core { const ExperimentMetadata g_test_experiment_metadata[] = { {"test_experiment_1", description_test_experiment_1, - additional_constraints_test_experiment_1, false, true}, + additional_constraints_test_experiment_1, nullptr, 0, false, true}, {"test_experiment_2", description_test_experiment_2, - additional_constraints_test_experiment_2, false, true}, + additional_constraints_test_experiment_2, nullptr, 0, false, true}, {"test_experiment_3", description_test_experiment_3, - additional_constraints_test_experiment_3, kDefaultForDebugOnly, true}, + additional_constraints_test_experiment_3, nullptr, 0, kDefaultForDebugOnly, + true}, {"test_experiment_4", description_test_experiment_4, - additional_constraints_test_experiment_4, true, true}, + additional_constraints_test_experiment_4, nullptr, 0, true, true}, }; } // namespace grpc_core @@ -105,13 +107,16 @@ namespace grpc_core { const ExperimentMetadata g_test_experiment_metadata[] = { {"test_experiment_1", description_test_experiment_1, - additional_constraints_test_experiment_1, kDefaultForDebugOnly, true}, + additional_constraints_test_experiment_1, nullptr, 0, kDefaultForDebugOnly, + true}, {"test_experiment_2", description_test_experiment_2, - additional_constraints_test_experiment_2, kDefaultForDebugOnly, true}, + additional_constraints_test_experiment_2, nullptr, 0, kDefaultForDebugOnly, + true}, {"test_experiment_3", description_test_experiment_3, - additional_constraints_test_experiment_3, kDefaultForDebugOnly, true}, + additional_constraints_test_experiment_3, nullptr, 0, kDefaultForDebugOnly, + true}, {"test_experiment_4", description_test_experiment_4, - additional_constraints_test_experiment_4, false, true}, + additional_constraints_test_experiment_4, nullptr, 0, false, true}, }; } // namespace grpc_core diff --git a/tools/codegen/core/experiments_compiler.py b/tools/codegen/core/experiments_compiler.py index 0e61422f28a30..403bfbb69bb9c 100644 --- a/tools/codegen/core/experiments_compiler.py +++ b/tools/codegen/core/experiments_compiler.py @@ -198,6 +198,7 @@ def __init__(self, attributes): self._default = {} self._additional_constraints = {} self._test_tags = [] + self._requires = set() if "allow_in_fuzzing_config" in attributes: self._allow_in_fuzzing_config = attributes[ @@ -207,6 +208,9 @@ def __init__(self, attributes): if "test_tags" in attributes: self._test_tags = attributes["test_tags"] + for requirement in attributes.get("requires", []): + self._requires.add(requirement) + def IsValid(self, check_expiry=False): if self._error: return False @@ -244,6 +248,8 @@ def AddRolloutSpecification( " experiment: %s" % self._name ) return False + for requirement in rollout_attributes.get("requires", []): + self._requires.add(requirement) if "default" not in rollout_attributes: print( "ERROR: no default for experiment %s" @@ -310,7 +316,7 @@ def __init__( self._final_define = final_define self._platforms_define = platforms_define self._bzl_list_for_defaults = bzl_list_for_defaults - self._experiment_definitions = {} + self._experiment_definitions = collections.OrderedDict() self._experiment_rollouts = {} def AddExperimentDefinition(self, experiment_definition): @@ -344,6 +350,27 @@ def AddRolloutSpecification(self, rollout_attributes): self._defaults, self._platforms_define, rollout_attributes ) + def _FinalizeExperiments(self): + queue = collections.OrderedDict() + for name, exp in self._experiment_definitions.items(): + queue[name] = exp._requires + done = set() + final = collections.OrderedDict() + while queue: + take = None + for name, requires in queue.items(): + if requires.issubset(done): + take = name + break + if take is None: + print("ERROR: circular dependency in experiments") + return False + done.add(take) + final[take] = self._experiment_definitions[take] + del queue[take] + self._experiment_definitions = final + return True + def _GenerateExperimentsHdrForPlatform(self, platform, file_desc): for _, exp in self._experiment_definitions.items(): define_fmt = self._final_define[exp.default(platform)] @@ -363,6 +390,7 @@ def _GenerateExperimentsHdrForPlatform(self, platform, file_desc): ) def GenerateExperimentsHdr(self, output_file, mode): + assert self._FinalizeExperiments() with open(output_file, "w") as H: PutCopyright(H, "//") PutBanner( @@ -463,6 +491,18 @@ def _GenerateExperimentsSrcForPlatform(self, platform, mode, file_desc): file=file_desc, ) have_defaults.add(self._defaults[exp.default(platform)]) + if exp._requires: + print( + "const uint8_t required_experiments_%s[] = {%s};" + % ( + exp.name, + ",".join( + f"static_cast(grpc_core::kExperimentId{SnakeToPascal(name)})" + for name in sorted(exp._requires) + ), + ), + file=file_desc, + ) if "kDefaultForDebugOnly" in have_defaults: print("#ifdef NDEBUG", file=file_desc) if "kDefaultForDebugOnly" in have_defaults: @@ -487,11 +527,15 @@ def _GenerateExperimentsSrcForPlatform(self, platform, mode, file_desc): ) for _, exp in self._experiment_definitions.items(): print( - " {%s, description_%s, additional_constraints_%s, %s, %s}," + " {%s, description_%s, additional_constraints_%s, %s, %d, %s, %s}," % ( ToCStr(exp.name), exp.name, exp.name, + f"required_experiments_{exp.name}" + if exp._requires + else "nullptr", + len(exp._requires), self._defaults[exp.default(platform)], "true" if exp.allow_in_fuzzing_config else "false", ), @@ -502,6 +546,7 @@ def _GenerateExperimentsSrcForPlatform(self, platform, mode, file_desc): print("} // namespace grpc_core", file=file_desc) def GenerateExperimentsSrc(self, output_file, header_file_path, mode): + assert self._FinalizeExperiments() with open(output_file, "w") as C: PutCopyright(C, "//") PutBanner( @@ -510,7 +555,15 @@ def GenerateExperimentsSrc(self, output_file, header_file_path, mode): "//", ) + any_requires = False + for _, exp in self._experiment_definitions.items(): + if exp._requires: + any_requires = True + break + print("#include ", file=C) + if any_requires: + print("#include ", file=C) print(f'#include "{header_file_path}"', file=C) print(file=C) print("#ifndef GRPC_EXPERIMENTS_ARE_FINAL", file=C) @@ -540,6 +593,7 @@ def _GenTestExperimentsExpectedValues(self, platform): return defs def GenTest(self, output_file): + assert self._FinalizeExperiments() with open(output_file, "w") as C: PutCopyright(C, "//") PutBanner( @@ -567,6 +621,7 @@ def GenTest(self, output_file): print(_EXPERIMENTS_TEST_SKELETON(defs, test_body), file=C) def GenExperimentsBzl(self, mode, output_file): + assert self._FinalizeExperiments() if self._bzl_list_for_defaults is None: return @@ -610,6 +665,19 @@ def GenExperimentsBzl(self, mode, output_file): file=B, ) + print(file=B) + if mode == "test": + print("TEST_EXPERIMENT_ENABLES = {", file=B) + else: + print("EXPERIMENT_ENABLES = {", file=B) + for name, exp in self._experiment_definitions.items(): + enables = exp._requires.copy() + enables.add(name) + print( + f" \"{name}\": \"{','.join(sorted(enables))}\",", file=B + ) + print("}", file=B) + print(file=B) if mode == "test": print("TEST_EXPERIMENTS = {", file=B) From 0a71e076f8185347be3a27fe8a64cd6c8ecc0d09 Mon Sep 17 00:00:00 2001 From: AJ Heller Date: Thu, 16 Nov 2023 13:33:16 -0800 Subject: [PATCH 011/127] [SoT] Remove import hurdle for Windows code (#35001) We don't have to manually import PRs to run the linters anymore. --- .github/labeler.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/labeler.yml b/.github/labeler.yml index 8eb57f336e15e..08ccbc86a8dee 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -52,9 +52,3 @@ lang/ruby: "lang/C#": - src/compiler/csharp* - src/csharp/** - -"disposition/Needs Internal Changes": -- src/core/lib/event_engine/windows/** -- src/core/lib/gpr/windows/** -- src/core/lib/gprpp/windows/** -- test/core/event_engine/windows/** From 5281789883e55cecfc35fa9a40b7ad5630683739 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Thu, 16 Nov 2023 15:14:38 -0800 Subject: [PATCH 012/127] [PSM Interop] Check for active ADS in Security and URL Map tests (#34968) `test_client.wait_for_server_channel_ready` was not called in `SecurityXdsKubernetesTestCase` and `XdsUrlMapTestCase`. Initial PR: https://github.com/grpc/grpc/pull/34631. Closes #34968 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/34968 from sergiitk:psm-interop-secure-tests-ads a71b422c1cda696de5d4e226a7b0fdf809bccdd1 PiperOrigin-RevId: 583180208 --- .../framework/xds_gamma_testcase.py | 4 +- .../framework/xds_k8s_testcase.py | 54 ++++++++++--------- .../framework/xds_url_map_testcase.py | 3 ++ 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/tools/run_tests/xds_k8s_test_driver/framework/xds_gamma_testcase.py b/tools/run_tests/xds_k8s_test_driver/framework/xds_gamma_testcase.py index ab8d652949462..0d86a15bb768d 100644 --- a/tools/run_tests/xds_k8s_test_driver/framework/xds_gamma_testcase.py +++ b/tools/run_tests/xds_k8s_test_driver/framework/xds_gamma_testcase.py @@ -130,6 +130,8 @@ def startTestClient( # To compensate for this, we double the timeout for GAMMA tests. return self._start_test_client( server_target, - wait_for_active_channel_timeout=datetime.timedelta(minutes=10), + wait_for_server_channel_ready_timeout=datetime.timedelta( + minutes=10 + ), **kwargs, ) diff --git a/tools/run_tests/xds_k8s_test_driver/framework/xds_k8s_testcase.py b/tools/run_tests/xds_k8s_test_driver/framework/xds_k8s_testcase.py index b3779e3842b4a..55743de13b2e6 100644 --- a/tools/run_tests/xds_k8s_test_driver/framework/xds_k8s_testcase.py +++ b/tools/run_tests/xds_k8s_test_driver/framework/xds_k8s_testcase.py @@ -739,6 +739,30 @@ def cleanup(self): force=self.force_cleanup, force_namespace=self.force_cleanup ) + def _start_test_client( + self, + server_target: str, + *, + wait_for_active_ads: bool = True, + wait_for_server_channel_ready: bool = True, + wait_for_active_ads_timeout: Optional[_timedelta] = None, + wait_for_server_channel_ready_timeout: Optional[_timedelta] = None, + **kwargs, + ) -> XdsTestClient: + test_client = self.client_runner.run( + server_target=server_target, **kwargs + ) + if wait_for_active_ads: + test_client.wait_for_active_xds_channel( + xds_server_uri=self.xds_server_uri, + timeout=wait_for_active_ads_timeout, + ) + if wait_for_server_channel_ready: + test_client.wait_for_server_channel_ready( + timeout=wait_for_server_channel_ready_timeout, + ) + return test_client + class RegularXdsKubernetesTestCase(IsolatedXdsKubernetesTestCase): """Regular test case base class for testing PSM features in isolation.""" @@ -822,26 +846,6 @@ def startTestClient( ) -> XdsTestClient: return self._start_test_client(test_server.xds_uri, **kwargs) - def _start_test_client( - self, - server_target: str, - *, - wait_for_active_ads_timeout: Optional[_timedelta] = None, - wait_for_active_channel_timeout: Optional[_timedelta] = None, - **kwargs, - ) -> XdsTestClient: - test_client = self.client_runner.run( - server_target=server_target, **kwargs - ) - test_client.wait_for_active_xds_channel( - xds_server_uri=self.xds_server_uri, - timeout=wait_for_active_ads_timeout, - ) - test_client.wait_for_server_channel_ready( - timeout=wait_for_active_channel_timeout, - ) - return test_client - class AppNetXdsKubernetesTestCase(RegularXdsKubernetesTestCase): td: TrafficDirectorAppNetManager @@ -964,12 +968,12 @@ def startSecureTestClient( wait_for_server_channel_ready=True, **kwargs, ) -> XdsTestClient: - test_client = self.client_runner.run( - server_target=test_server.xds_uri, secure_mode=True, **kwargs + return self._start_test_client( + server_target=test_server.xds_uri, + wait_for_server_channel_ready=wait_for_server_channel_ready, + secure_mode=True, + **kwargs, ) - if wait_for_server_channel_ready: - test_client.wait_for_server_channel_ready() - return test_client def assertTestAppSecurity( self, diff --git a/tools/run_tests/xds_k8s_test_driver/framework/xds_url_map_testcase.py b/tools/run_tests/xds_k8s_test_driver/framework/xds_url_map_testcase.py index ba07e8e8d4c97..25ef9ee9a6b79 100644 --- a/tools/run_tests/xds_k8s_test_driver/framework/xds_url_map_testcase.py +++ b/tools/run_tests/xds_k8s_test_driver/framework/xds_url_map_testcase.py @@ -479,6 +479,9 @@ def run(self, result: unittest.TestResult = None) -> None: super().run(result) def test_client_config(self): + self.test_client.wait_for_active_xds_channel( + xds_server_uri=GcpResourceManager().xds_server_uri, + ) retryer = retryers.constant_retryer( wait_fixed=datetime.timedelta( seconds=_URL_MAP_PROPAGATE_CHECK_INTERVAL_SEC From 4ecead5c0407dcfa30c0899ff6a64d48a74c424b Mon Sep 17 00:00:00 2001 From: AJ Heller Date: Thu, 16 Nov 2023 17:51:34 -0800 Subject: [PATCH 013/127] [EventEngine] Clarify API: callback cancellation and thread safety (#35009) Closes #35009 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35009 from drfloob:improve-ee-API-docs 996e7d3148700996966625737b2a57e912bf400a PiperOrigin-RevId: 583219509 --- include/grpc/event_engine/event_engine.h | 32 +++++++++++++++--------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/include/grpc/event_engine/event_engine.h b/include/grpc/event_engine/event_engine.h index 2130f7feb1a82..4beca657625a3 100644 --- a/include/grpc/event_engine/event_engine.h +++ b/include/grpc/event_engine/event_engine.h @@ -79,7 +79,7 @@ namespace experimental { /// /// /// Blocking EventEngine Callbacks -/// ----------------------------- +/// ------------------------------ /// /// Doing blocking work in EventEngine callbacks is generally not advisable. /// While gRPC's default EventEngine implementations have some capacity to scale @@ -90,6 +90,15 @@ namespace experimental { /// *Best Practice* : Occasional blocking work may be fine, but we do not /// recommend running a mostly blocking workload in EventEngine threads. /// +/// +/// Thread-safety guarantees +/// ------------------------ +/// +/// All EventEngine methods are guaranteed to be thread-safe, no external +/// synchronization is required to call any EventEngine method. Please note that +/// this does not apply to application callbacks, which may be run concurrently; +/// application state synchronization must be managed by the application. +/// //////////////////////////////////////////////////////////////////////////////// class EventEngine : public std::enable_shared_from_this { public: @@ -405,8 +414,8 @@ class EventEngine : public std::enable_shared_from_this { /// Asynchronously executes a task as soon as possible. /// - /// \a Closures scheduled with \a Run cannot be cancelled. The \a closure will - /// not be deleted after it has been run, ownership remains with the caller. + /// \a Closures passed to \a Run cannot be cancelled. The \a closure will not + /// be deleted after it has been run, ownership remains with the caller. /// /// Implementations must not execute the closure in the calling thread before /// \a Run returns. For example, if the caller must release a lock before the @@ -415,9 +424,9 @@ class EventEngine : public std::enable_shared_from_this { virtual void Run(Closure* closure) = 0; /// Asynchronously executes a task as soon as possible. /// - /// \a Closures scheduled with \a Run cannot be cancelled. Unlike the - /// overloaded \a Closure alternative, the absl::AnyInvocable version's \a - /// closure will be deleted by the EventEngine after the closure has been run. + /// \a Closures passed to \a Run cannot be cancelled. Unlike the overloaded \a + /// Closure alternative, the absl::AnyInvocable version's \a closure will be + /// deleted by the EventEngine after the closure has been run. /// /// This version of \a Run may be less performant than the \a Closure version /// in some scenarios. This overload is useful in situations where performance @@ -453,13 +462,12 @@ class EventEngine : public std::enable_shared_from_this { absl::AnyInvocable closure) = 0; /// Request cancellation of a task. /// - /// If the associated closure has already been scheduled to run, it will not - /// be cancelled, and this function will return false. + /// If the associated closure cannot be cancelled for any reason, this + /// function will return false. /// - /// If the associated closure has not been scheduled to run, it will be - /// cancelled, and this method will return true. The associated - /// absl::AnyInvocable or \a Closure* will not be called. If the closure type - /// was an absl::AnyInvocable, it will be destroyed before the method returns. + /// If the associated closure can be cancelled, the associated callback will + /// never be run, and this method will return true. If the callback type was + /// an absl::AnyInvocable, it will be destroyed before the method returns. virtual bool Cancel(TaskHandle handle) = 0; }; From 42284424acd2ba4ba649599984592f5d2eade919 Mon Sep 17 00:00:00 2001 From: AJ Heller Date: Fri, 17 Nov 2023 13:21:21 -0800 Subject: [PATCH 014/127] [EventEngine] Produce better error logs on `bind` failures (#35004) Seeing a rare flake where a fixture address is already in use. This PR adds sockaddr->string conversion for the address, in case some of this address is being truncated before attempting to bind. It's very odd to see this exact-time-based address string generated twice in succession. `E1116 21:34:56.431768483 17 chttp2_server.cc:1051] UNKNOWN:No address added out of total 1 resolved for 'unix-abstract:grpc_fullstack_test.%00.17.974.661825339.14468088171934000544.7442035989947845277' {created_time:"2023-11-16T21:34:56.431729283+00:00", children:[FAILED_PRECONDITION:Error in bind: Address already in use]} ` https://source.cloud.google.com/results/invocations/48ee2e26-9341-46ec-9761-35939b73f3f8/targets/%2F%2Ftest%2Fcore%2Fend2end:retry_transparent_max_concurrent_streams_test@poller%3Dpoll/log Closes #35004 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35004 from drfloob:better-error-on-bind-failure d12d5f86326fdf411fed51093998e09121535c39 PiperOrigin-RevId: 583472016 --- .../posix_engine/posix_engine_listener_utils.cc | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/core/lib/event_engine/posix_engine/posix_engine_listener_utils.cc b/src/core/lib/event_engine/posix_engine/posix_engine_listener_utils.cc index 8c2745c02b27e..ed2321b297100 100644 --- a/src/core/lib/event_engine/posix_engine/posix_engine_listener_utils.cc +++ b/src/core/lib/event_engine/posix_engine/posix_engine_listener_utils.cc @@ -25,6 +25,8 @@ #include "absl/cleanup/cleanup.h" #include "absl/status/status.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_replace.h" #include #include @@ -44,8 +46,6 @@ #include // IWYU pragma: keep #include // IWYU pragma: keep #include // IWYU pragma: keep - -#include "absl/strings/str_cat.h" #endif namespace grpc_event_engine { @@ -176,8 +176,16 @@ absl::Status PrepareSocket(const PosixTcpOptions& options, GRPC_FD_SERVER_LISTENER_USAGE, options)); if (bind(fd, socket.addr.address(), socket.addr.size()) < 0) { + auto sockaddr_str = ResolvedAddressToString(socket.addr); + if (!sockaddr_str.ok()) { + gpr_log(GPR_ERROR, "Could not convert sockaddr to string: %s", + sockaddr_str.status().ToString().c_str()); + sockaddr_str = ""; + } + sockaddr_str = absl::StrReplaceAll(*sockaddr_str, {{"\0", "@"}}); return absl::FailedPreconditionError( - absl::StrCat("Error in bind: ", std::strerror(errno))); + absl::StrCat("Error in bind for address '", *sockaddr_str, + "': ", std::strerror(errno))); } if (listen(fd, GetMaxAcceptQueueSize()) < 0) { From 667def75058ffab2b76abaaeb106fbf59e944a24 Mon Sep 17 00:00:00 2001 From: gRPC Team Bot Date: Mon, 27 Nov 2023 21:27:21 +0000 Subject: [PATCH 015/127] Internal change COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35043 from gtcooke94:deprecate_old_crl_apis 003057a93c2686411be4c02bec38fcad4fa7e85d PiperOrigin-RevId: 585744149 --- include/grpc/grpc_security.h | 5 ++++- .../posix_engine/tcp_socket_utils.cc | 3 +-- .../grpc/_cython/_cygrpc/aio/server.pyx.pxi | 2 ++ test/cpp/interop/xds_stats_watcher.cc | 21 +++++++++++++++++-- test/cpp/interop/xds_stats_watcher_test.cc | 7 +------ 5 files changed, 27 insertions(+), 11 deletions(-) diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h index 54dc862d260a6..d099ff6293316 100644 --- a/include/grpc/grpc_security.h +++ b/include/grpc/grpc_security.h @@ -894,7 +894,10 @@ GRPCAPI void grpc_tls_credentials_options_set_identity_cert_name( GRPCAPI void grpc_tls_credentials_options_set_cert_request_type( grpc_tls_credentials_options* options, grpc_ssl_client_certificate_request_type type); -/** + +/** Deprecated in favor of grpc_tls_credentials_options_set_crl_provider. The + * crl provider interface provides a significantly more flexible approach to + * using CRLs. See gRFC A69 for details. * EXPERIMENTAL API - Subject to change * * If set, gRPC will read all hashed x.509 CRL files in the directory and diff --git a/src/core/lib/event_engine/posix_engine/tcp_socket_utils.cc b/src/core/lib/event_engine/posix_engine/tcp_socket_utils.cc index 845e48cdf4168..c5b2277d6a753 100644 --- a/src/core/lib/event_engine/posix_engine/tcp_socket_utils.cc +++ b/src/core/lib/event_engine/posix_engine/tcp_socket_utils.cc @@ -75,6 +75,7 @@ int AdjustValue(int default_value, int min_value, int max_value, return *actual_value; } +#ifdef GRPC_POSIX_SOCKET_UTILS_COMMON // The default values for TCP_USER_TIMEOUT are currently configured to be in // line with the default values of KEEPALIVE_TIMEOUT as proposed in // https://github.com/grpc/proposal/blob/master/A18-tcp-user-timeout.md */ @@ -83,8 +84,6 @@ int kDefaultServerUserTimeoutMs = 20000; bool kDefaultClientUserTimeoutEnabled = false; bool kDefaultServerUserTimeoutEnabled = true; -#ifdef GRPC_POSIX_SOCKET_UTILS_COMMON - absl::Status ErrorForFd( int fd, const experimental::EventEngine::ResolvedAddress& addr) { if (fd >= 0) return absl::OkStatus(); diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/aio/server.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/aio/server.pyx.pxi index 508196e0a4175..a21c1ec0082cc 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/aio/server.pyx.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/aio/server.pyx.pxi @@ -470,6 +470,7 @@ async def _finish_handler_with_stream_responses(RPCState rpc_state, """ cdef object async_response_generator cdef object response_message + install_context_from_request_call_event_aio(rpc_state) if inspect.iscoroutinefunction(stream_handler): # Case 1: Coroutine async handler - using reader-writer API @@ -523,6 +524,7 @@ async def _finish_handler_with_stream_responses(RPCState rpc_state, rpc_state.metadata_sent = True rpc_state.status_sent = True await execute_batch(rpc_state, finish_ops, loop) + uninstall_context() async def _handle_unary_unary_rpc(object method_handler, diff --git a/test/cpp/interop/xds_stats_watcher.cc b/test/cpp/interop/xds_stats_watcher.cc index d6cb3037b8a5e..1f2852575a349 100644 --- a/test/cpp/interop/xds_stats_watcher.cc +++ b/test/cpp/interop/xds_stats_watcher.cc @@ -51,6 +51,19 @@ std::unordered_set ToLowerCase( return result; } +bool HasNonEmptyMetadata( + const std::map& + metadata_by_peer) { + for (const auto& entry : metadata_by_peer) { + for (const auto& rpc_metadata : entry.second.rpc_metadata()) { + if (rpc_metadata.metadata_size() > 0) { + return true; + } + } + } + return false; +} + } // namespace XdsStatsWatcher::XdsStatsWatcher(int start_id, int end_id, @@ -113,8 +126,12 @@ LoadBalancerStatsResponse XdsStatsWatcher::WaitForRpcStatsResponse( [this] { return rpcs_needed_ == 0; }); response.mutable_rpcs_by_peer()->insert(rpcs_by_peer_.begin(), rpcs_by_peer_.end()); - response.mutable_metadatas_by_peer()->insert(metadata_by_peer_.begin(), - metadata_by_peer_.end()); + // Return metadata if at least one RPC had relevant metadata. Note that empty + // entries would be returned for RCPs with no relevant metadata in this case. + if (HasNonEmptyMetadata(metadata_by_peer_)) { + response.mutable_metadatas_by_peer()->insert(metadata_by_peer_.begin(), + metadata_by_peer_.end()); + } auto& response_rpcs_by_method = *response.mutable_rpcs_by_method(); for (const auto& rpc_by_type : rpcs_by_type_) { std::string method_name; diff --git a/test/cpp/interop/xds_stats_watcher_test.cc b/test/cpp/interop/xds_stats_watcher_test.cc index 0909b49bd1b1d..3d2f951c24681 100644 --- a/test/cpp/interop/xds_stats_watcher_test.cc +++ b/test/cpp/interop/xds_stats_watcher_test.cc @@ -152,7 +152,7 @@ TEST(XdsStatsWatcherTest, WaitForRpcStatsResponseReturnsAll) { watcher.WaitForRpcStatsResponse(0).DebugString()); } -TEST(XdsStatsWatcherTest, WaitForRpcStatsResponseIgnoresMetadata) { +TEST(XdsStatsWatcherTest, WaitForRpcStatsResponseExcludesMetadata) { XdsStatsWatcher watcher(0, 3, {}); // RPC had metadata - but watcher should ignore it watcher.RpcCompleted(BuildCallResult(0), "peer1", @@ -163,11 +163,6 @@ TEST(XdsStatsWatcherTest, WaitForRpcStatsResponseIgnoresMetadata) { {{"k1", "v5"}, {"k2", "v6"}, {"k3", "v7"}}); LoadBalancerStatsResponse expected; expected.mutable_rpcs_by_peer()->insert({{"peer1", 2}, {"peer2", 1}}); - // There will still be an empty metadata collection for each RPC - expected.mutable_metadatas_by_peer()->insert({ - {"peer1", BuildMetadatas({{}, {}})}, - {"peer2", BuildMetadatas({{}})}, - }); (*expected.mutable_rpcs_by_method())["UnaryCall"] .mutable_rpcs_by_peer() ->insert({{"peer1", 2}, {"peer2", 1}}); From 79c9a67dee5bbbd65031296097994e222b885d22 Mon Sep 17 00:00:00 2001 From: aeitzman Date: Mon, 27 Nov 2023 16:46:39 -0800 Subject: [PATCH 016/127] [core/security] Adding metrics header to sts request for external account credentials (#34661) Closes #34661 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/34661 from aeitzman:metrics 9f53992ed4c8aef4f753e9c1ec3d65cb7eab1dba PiperOrigin-RevId: 585796526 --- .../aws_external_account_credentials.cc | 4 + .../aws_external_account_credentials.h | 4 + .../external/external_account_credentials.cc | 48 ++++---- .../external/external_account_credentials.h | 4 + .../file_external_account_credentials.cc | 4 + .../file_external_account_credentials.h | 4 + .../url_external_account_credentials.cc | 4 + .../url_external_account_credentials.h | 4 + test/core/security/credentials_test.cc | 111 ++++++++++++++++-- 9 files changed, 158 insertions(+), 29 deletions(-) diff --git a/src/core/lib/security/credentials/external/aws_external_account_credentials.cc b/src/core/lib/security/credentials/external/aws_external_account_credentials.cc index 68ddaaeb903c9..cd7d117b28ee8 100644 --- a/src/core/lib/security/credentials/external/aws_external_account_credentials.cc +++ b/src/core/lib/security/credentials/external/aws_external_account_credentials.cc @@ -525,4 +525,8 @@ void AwsExternalAccountCredentials::FinishRetrieveSubjectToken( } } +absl::string_view AwsExternalAccountCredentials::CredentialSourceType() { + return "aws"; +} + } // namespace grpc_core diff --git a/src/core/lib/security/credentials/external/aws_external_account_credentials.h b/src/core/lib/security/credentials/external/aws_external_account_credentials.h index e8adc02452f8e..a3a41236615e7 100644 --- a/src/core/lib/security/credentials/external/aws_external_account_credentials.h +++ b/src/core/lib/security/credentials/external/aws_external_account_credentials.h @@ -24,6 +24,8 @@ #include #include +#include "absl/strings/string_view.h" + #include "src/core/lib/gprpp/orphanable.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/http/httpcli.h" @@ -72,6 +74,8 @@ class AwsExternalAccountCredentials final : public ExternalAccountCredentials { void AddMetadataRequestHeaders(grpc_http_request* request); + absl::string_view CredentialSourceType() override; + std::string audience_; OrphanablePtr http_request_; diff --git a/src/core/lib/security/credentials/external/external_account_credentials.cc b/src/core/lib/security/credentials/external/external_account_credentials.cc index 93228dbca4eb7..3ffd2acb0ef94 100644 --- a/src/core/lib/security/credentials/external/external_account_credentials.cc +++ b/src/core/lib/security/credentials/external/external_account_credentials.cc @@ -26,6 +26,7 @@ #include "absl/status/status.h" #include "absl/status/statusor.h" +#include "absl/strings/escaping.h" #include "absl/strings/match.h" #include "absl/strings/numbers.h" #include "absl/strings/str_cat.h" @@ -53,7 +54,6 @@ #include "src/core/lib/security/credentials/external/file_external_account_credentials.h" #include "src/core/lib/security/credentials/external/url_external_account_credentials.h" #include "src/core/lib/security/util/json_util.h" -#include "src/core/lib/slice/b64.h" #include "src/core/lib/uri/uri_parser.h" #define EXTERNAL_ACCOUNT_CREDENTIALS_GRANT_TYPE \ @@ -271,6 +271,20 @@ std::string ExternalAccountCredentials::debug_string() { grpc_oauth2_token_fetcher_credentials::debug_string()); } +std::string ExternalAccountCredentials::MetricsHeaderValue() { + return absl::StrFormat( + "gl-cpp/unknown auth/%s google-byoid-sdk source/%s sa-impersonation/%v " + "config-lifetime/%v", + grpc_version_string(), CredentialSourceType(), + !options_.service_account_impersonation_url.empty(), + options_.service_account_impersonation.token_lifetime_seconds != + IMPERSONATED_CRED_DEFAULT_LIFETIME_IN_SECONDS); +} + +absl::string_view ExternalAccountCredentials::CredentialSourceType() { + return "unknown"; +} + // The token fetching flow: // 1. Retrieve subject token - Subclass's RetrieveSubjectToken() gets called // and the subject token is received in OnRetrieveSubjectTokenInternal(). @@ -317,27 +331,21 @@ void ExternalAccountCredentials::ExchangeToken( } grpc_http_request request; memset(&request, 0, sizeof(grpc_http_request)); - grpc_http_header* headers = nullptr; - if (!options_.client_id.empty() && !options_.client_secret.empty()) { - request.hdr_count = 2; - headers = static_cast( - gpr_malloc(sizeof(grpc_http_header) * request.hdr_count)); - headers[0].key = gpr_strdup("Content-Type"); - headers[0].value = gpr_strdup("application/x-www-form-urlencoded"); + const bool add_authorization_header = + !options_.client_id.empty() && !options_.client_secret.empty(); + request.hdr_count = add_authorization_header ? 3 : 2; + auto* headers = static_cast( + gpr_malloc(sizeof(grpc_http_header) * request.hdr_count)); + headers[0].key = gpr_strdup("Content-Type"); + headers[0].value = gpr_strdup("application/x-www-form-urlencoded"); + headers[1].key = gpr_strdup("x-goog-api-client"); + headers[1].value = gpr_strdup(MetricsHeaderValue().c_str()); + if (add_authorization_header) { std::string raw_cred = absl::StrFormat("%s:%s", options_.client_id, options_.client_secret); - char* encoded_cred = - grpc_base64_encode(raw_cred.c_str(), raw_cred.length(), 0, 0); - std::string str = absl::StrFormat("Basic %s", std::string(encoded_cred)); - headers[1].key = gpr_strdup("Authorization"); - headers[1].value = gpr_strdup(str.c_str()); - gpr_free(encoded_cred); - } else { - request.hdr_count = 1; - headers = static_cast( - gpr_malloc(sizeof(grpc_http_header) * request.hdr_count)); - headers[0].key = gpr_strdup("Content-Type"); - headers[0].value = gpr_strdup("application/x-www-form-urlencoded"); + std::string str = absl::StrFormat("Basic %s", absl::Base64Escape(raw_cred)); + headers[2].key = gpr_strdup("Authorization"); + headers[2].value = gpr_strdup(str.c_str()); } request.hdrs = headers; std::vector body_parts; diff --git a/src/core/lib/security/credentials/external/external_account_credentials.h b/src/core/lib/security/credentials/external/external_account_credentials.h index bcbd33b272bef..13749db8567a7 100644 --- a/src/core/lib/security/credentials/external/external_account_credentials.h +++ b/src/core/lib/security/credentials/external/external_account_credentials.h @@ -101,6 +101,10 @@ class ExternalAccountCredentials HTTPRequestContext* ctx, const Options& options, std::function cb) = 0; + virtual absl::string_view CredentialSourceType(); + + std::string MetricsHeaderValue(); + private: // This method implements the common token fetch logic and it will be called // when grpc_oauth2_token_fetcher_credentials request a new access token. diff --git a/src/core/lib/security/credentials/external/file_external_account_credentials.cc b/src/core/lib/security/credentials/external/file_external_account_credentials.cc index e70131bfeef2b..0fb3ce5091d09 100644 --- a/src/core/lib/security/credentials/external/file_external_account_credentials.cc +++ b/src/core/lib/security/credentials/external/file_external_account_credentials.cc @@ -137,4 +137,8 @@ void FileExternalAccountCredentials::RetrieveSubjectToken( cb(std::string(content), absl::OkStatus()); } +absl::string_view FileExternalAccountCredentials::CredentialSourceType() { + return "file"; +} + } // namespace grpc_core diff --git a/src/core/lib/security/credentials/external/file_external_account_credentials.h b/src/core/lib/security/credentials/external/file_external_account_credentials.h index 40f0e9f23f485..c8cf12177bda0 100644 --- a/src/core/lib/security/credentials/external/file_external_account_credentials.h +++ b/src/core/lib/security/credentials/external/file_external_account_credentials.h @@ -23,6 +23,8 @@ #include #include +#include "absl/strings/string_view.h" + #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/security/credentials/external/external_account_credentials.h" @@ -44,6 +46,8 @@ class FileExternalAccountCredentials final : public ExternalAccountCredentials { HTTPRequestContext* ctx, const Options& options, std::function cb) override; + absl::string_view CredentialSourceType() override; + // Fields of credential source std::string file_; std::string format_type_; diff --git a/src/core/lib/security/credentials/external/url_external_account_credentials.cc b/src/core/lib/security/credentials/external/url_external_account_credentials.cc index 0e4cb8afba17b..4b977c045ee23 100644 --- a/src/core/lib/security/credentials/external/url_external_account_credentials.cc +++ b/src/core/lib/security/credentials/external/url_external_account_credentials.cc @@ -240,4 +240,8 @@ void UrlExternalAccountCredentials::FinishRetrieveSubjectToken( } } +absl::string_view UrlExternalAccountCredentials::CredentialSourceType() { + return "url"; +} + } // namespace grpc_core diff --git a/src/core/lib/security/credentials/external/url_external_account_credentials.h b/src/core/lib/security/credentials/external/url_external_account_credentials.h index 71b734e591e0a..9331412d32190 100644 --- a/src/core/lib/security/credentials/external/url_external_account_credentials.h +++ b/src/core/lib/security/credentials/external/url_external_account_credentials.h @@ -24,6 +24,8 @@ #include #include +#include "absl/strings/string_view.h" + #include "src/core/lib/gprpp/orphanable.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/http/httpcli.h" @@ -48,6 +50,8 @@ class UrlExternalAccountCredentials final : public ExternalAccountCredentials { HTTPRequestContext* ctx, const Options& options, std::function cb) override; + absl::string_view CredentialSourceType() override; + static void OnRetrieveSubjectToken(void* arg, grpc_error_handle error); void OnRetrieveSubjectTokenInternal(grpc_error_handle error); diff --git a/test/core/security/credentials_test.cc b/test/core/security/credentials_test.cc index f0c0543275ccd..ad58ccd394f67 100644 --- a/test/core/security/credentials_test.cc +++ b/test/core/security/credentials_test.cc @@ -2127,12 +2127,12 @@ void validate_external_account_creds_token_exchage_request( // Check the rest of the request. GPR_ASSERT(strcmp(host, "foo.com:5555") == 0); GPR_ASSERT(strcmp(path, "/token") == 0); - GPR_ASSERT(request->hdr_count == 2); + GPR_ASSERT(request->hdr_count == 3); GPR_ASSERT(strcmp(request->hdrs[0].key, "Content-Type") == 0); GPR_ASSERT( strcmp(request->hdrs[0].value, "application/x-www-form-urlencoded") == 0); - GPR_ASSERT(strcmp(request->hdrs[1].key, "Authorization") == 0); - GPR_ASSERT(strcmp(request->hdrs[1].value, + GPR_ASSERT(strcmp(request->hdrs[2].key, "Authorization") == 0); + GPR_ASSERT(strcmp(request->hdrs[2].value, "Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=") == 0); } @@ -2155,12 +2155,12 @@ void validate_external_account_creds_token_exchage_request_with_url_encode( // Check the rest of the request. GPR_ASSERT(strcmp(host, "foo.com:5555") == 0); GPR_ASSERT(strcmp(path, "/token_url_encode") == 0); - GPR_ASSERT(request->hdr_count == 2); + GPR_ASSERT(request->hdr_count == 3); GPR_ASSERT(strcmp(request->hdrs[0].key, "Content-Type") == 0); GPR_ASSERT( strcmp(request->hdrs[0].value, "application/x-www-form-urlencoded") == 0); - GPR_ASSERT(strcmp(request->hdrs[1].key, "Authorization") == 0); - GPR_ASSERT(strcmp(request->hdrs[1].value, + GPR_ASSERT(strcmp(request->hdrs[2].key, "Authorization") == 0); + GPR_ASSERT(strcmp(request->hdrs[2].value, "Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=") == 0); } @@ -2311,12 +2311,18 @@ void validate_aws_external_account_creds_token_exchage_request( // Check the rest of the request. GPR_ASSERT(strcmp(host, "foo.com:5555") == 0); GPR_ASSERT(strcmp(path, "/token") == 0); - GPR_ASSERT(request->hdr_count == 2); + GPR_ASSERT(request->hdr_count == 3); GPR_ASSERT(strcmp(request->hdrs[0].key, "Content-Type") == 0); GPR_ASSERT( strcmp(request->hdrs[0].value, "application/x-www-form-urlencoded") == 0); - GPR_ASSERT(strcmp(request->hdrs[1].key, "Authorization") == 0); - GPR_ASSERT(strcmp(request->hdrs[1].value, + GPR_ASSERT(strcmp(request->hdrs[1].key, "x-goog-api-client") == 0); + EXPECT_EQ( + request->hdrs[1].value, + absl::StrFormat("gl-cpp/unknown auth/%s google-byoid-sdk source/aws " + "sa-impersonation/false config-lifetime/false", + grpc_version_string())); + GPR_ASSERT(strcmp(request->hdrs[2].key, "Authorization") == 0); + GPR_ASSERT(strcmp(request->hdrs[2].value, "Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=") == 0); } @@ -2385,6 +2391,8 @@ class TestExternalAccountCredentials final : public ExternalAccountCredentials { std::vector scopes) : ExternalAccountCredentials(std::move(options), std::move(scopes)) {} + std::string GetMetricsValue() { return MetricsHeaderValue(); } + protected: void RetrieveSubjectToken( HTTPRequestContext* /*ctx*/, const Options& /*options*/, @@ -2393,6 +2401,91 @@ class TestExternalAccountCredentials final : public ExternalAccountCredentials { } }; +TEST(CredentialsTest, TestExternalAccountCredsMetricsHeader) { + Json credential_source = Json::FromString(""); + TestExternalAccountCredentials::ServiceAccountImpersonation + service_account_impersonation; + service_account_impersonation.token_lifetime_seconds = 3600; + TestExternalAccountCredentials::Options options = { + "external_account", // type; + "audience", // audience; + "subject_token_type", // subject_token_type; + "", // service_account_impersonation_url; + service_account_impersonation, // service_account_impersonation; + "https://foo.com:5555/token", // token_url; + "https://foo.com:5555/token_info", // token_info_url; + credential_source, // credential_source; + "quota_project_id", // quota_project_id; + "client_id", // client_id; + "client_secret", // client_secret; + "", // workforce_pool_user_project; + }; + TestExternalAccountCredentials creds(options, {}); + + EXPECT_EQ( + creds.GetMetricsValue(), + absl::StrFormat("gl-cpp/unknown auth/%s google-byoid-sdk source/unknown " + "sa-impersonation/false config-lifetime/false", + grpc_version_string())); +} + +TEST(CredentialsTest, + TestExternalAccountCredsMetricsHeaderWithServiceAccountImpersonation) { + Json credential_source = Json::FromString(""); + TestExternalAccountCredentials::ServiceAccountImpersonation + service_account_impersonation; + service_account_impersonation.token_lifetime_seconds = 3600; + TestExternalAccountCredentials::Options options = { + "external_account", // type; + "audience", // audience; + "subject_token_type", // subject_token_type; + "https://foo.com:5555/service_account_impersonation", // service_account_impersonation_url; + service_account_impersonation, // service_account_impersonation; + "https://foo.com:5555/token", // token_url; + "https://foo.com:5555/token_info", // token_info_url; + credential_source, // credential_source; + "quota_project_id", // quota_project_id; + "client_id", // client_id; + "client_secret", // client_secret; + "", // workforce_pool_user_project; + }; + TestExternalAccountCredentials creds(options, {}); + + EXPECT_EQ( + creds.GetMetricsValue(), + absl::StrFormat("gl-cpp/unknown auth/%s google-byoid-sdk source/unknown " + "sa-impersonation/true config-lifetime/false", + grpc_version_string())); +} + +TEST(CredentialsTest, TestExternalAccountCredsMetricsHeaderWithConfigLifetime) { + Json credential_source = Json::FromString(""); + TestExternalAccountCredentials::ServiceAccountImpersonation + service_account_impersonation; + service_account_impersonation.token_lifetime_seconds = 5000; + TestExternalAccountCredentials::Options options = { + "external_account", // type; + "audience", // audience; + "subject_token_type", // subject_token_type; + "https://foo.com:5555/service_account_impersonation", // service_account_impersonation_url; + service_account_impersonation, // service_account_impersonation; + "https://foo.com:5555/token", // token_url; + "https://foo.com:5555/token_info", // token_info_url; + credential_source, // credential_source; + "quota_project_id", // quota_project_id; + "client_id", // client_id; + "client_secret", // client_secret; + "", // workforce_pool_user_project; + }; + TestExternalAccountCredentials creds(options, {}); + + EXPECT_EQ( + creds.GetMetricsValue(), + absl::StrFormat("gl-cpp/unknown auth/%s google-byoid-sdk source/unknown " + "sa-impersonation/true config-lifetime/true", + grpc_version_string())); +} + TEST(CredentialsTest, TestExternalAccountCredsSuccess) { ExecCtx exec_ctx; Json credential_source = Json::FromString(""); From d47a264991cf52cf5ee48ea85047e04005d5b3fe Mon Sep 17 00:00:00 2001 From: Gregory Cooke Date: Tue, 28 Nov 2023 11:48:50 -0800 Subject: [PATCH 017/127] [Security - Documentation] Mark cpp crl_directory method as deprecated (#35128) The c-core API was marked as deprecated, also mark the cpp api as deprecated Closes #35128 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35128 from gtcooke94:deprecate_cpp_crl_directory 56717d020c3a8b36996878b8f953968b99205e2f PiperOrigin-RevId: 586057092 --- include/grpcpp/security/tls_credentials_options.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/grpcpp/security/tls_credentials_options.h b/include/grpcpp/security/tls_credentials_options.h index 341d3a857bff9..7ad5b0885680d 100644 --- a/include/grpcpp/security/tls_credentials_options.h +++ b/include/grpcpp/security/tls_credentials_options.h @@ -99,8 +99,9 @@ class TlsCredentialsOptions { // verifiers other than the host name verifier is used. void set_check_call_host(bool check_call_host); - // TODO(zhenlian): This is an experimental API is likely to change in the - // future. Before de-experiementalizing, verify the API is up to date. + // Deprecated in favor of set_crl_provider. The + // crl provider interface provides a significantly more flexible approach to + // using CRLs. See gRFC A69 for details. // If set, gRPC will read all hashed x.509 CRL files in the directory and // enforce the CRL files on all TLS handshakes. Only supported for OpenSSL // version > 1.1. From 5ac8442432950c5c11a39904bb1f381829b7ae0c Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 29 Nov 2023 09:41:04 -0800 Subject: [PATCH 018/127] [copybara] omit bot from autofix (#35141) --- .github/workflows/pr-auto-fix.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-auto-fix.yaml b/.github/workflows/pr-auto-fix.yaml index 573de52d9cb30..2374a5e0e0ddc 100644 --- a/.github/workflows/pr-auto-fix.yaml +++ b/.github/workflows/pr-auto-fix.yaml @@ -48,7 +48,7 @@ jobs: with: script: | // If you'd like not to run this code on your commits, add your github user id here: - NO_AUTOFIX_USERS = [] + NO_AUTOFIX_USERS = ["copybara-service"] const { owner, repo } = context.repo if (NO_AUTOFIX_USERS.includes(context.actor)) { console.log('Cancelling'); From 492dfba681e50000ea81b9fbf705625d268686bc Mon Sep 17 00:00:00 2001 From: Paulo Castello da Costa Date: Wed, 29 Nov 2023 10:57:16 -0800 Subject: [PATCH 019/127] [benchmark] Exclude dotnet from OSS benchmarks CI. (#35068) QPS worker build is currently failing. Closes #35068 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35068 from paulosjca:dotnet cc4ef42659651aa8fa9fc9ad6b3c5c42b2dc76d5 PiperOrigin-RevId: 586393834 --- tools/internal_ci/linux/grpc_e2e_performance_gke.sh | 6 +++--- .../linux/grpc_e2e_performance_gke_experiment.sh | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/internal_ci/linux/grpc_e2e_performance_gke.sh b/tools/internal_ci/linux/grpc_e2e_performance_gke.sh index 15951cccc756e..a8da8a9fae6a0 100755 --- a/tools/internal_ci/linux/grpc_e2e_performance_gke.sh +++ b/tools/internal_ci/linux/grpc_e2e_performance_gke.sh @@ -131,9 +131,9 @@ configLangArgs32core+=( -l c++ ) runnerLangArgs+=( -l "cxx:${GRPC_CORE_REPO}:${GRPC_CORE_COMMIT}" ) # dotnet -configLangArgs8core+=( -l dotnet ) -configLangArgs32core+=( -l dotnet ) -runnerLangArgs+=( -l "dotnet:${GRPC_DOTNET_REPO}:${GRPC_DOTNET_COMMIT}" ) +# configLangArgs8core+=( -l dotnet ) +# configLangArgs32core+=( -l dotnet ) +# runnerLangArgs+=( -l "dotnet:${GRPC_DOTNET_REPO}:${GRPC_DOTNET_COMMIT}" ) # # go configLangArgs8core+=( -l go ) diff --git a/tools/internal_ci/linux/grpc_e2e_performance_gke_experiment.sh b/tools/internal_ci/linux/grpc_e2e_performance_gke_experiment.sh index f62d9920b72a4..c3b99af80ebb6 100755 --- a/tools/internal_ci/linux/grpc_e2e_performance_gke_experiment.sh +++ b/tools/internal_ci/linux/grpc_e2e_performance_gke_experiment.sh @@ -125,9 +125,9 @@ configLangArgs32core+=( -l c++ ) runnerLangArgs+=( -l "cxx:${GRPC_CORE_REPO}:${GRPC_CORE_COMMIT}" ) # dotnet -configLangArgs8core+=( -l dotnet ) -configLangArgs32core+=( -l dotnet ) -runnerLangArgs+=( -l "dotnet:${GRPC_DOTNET_REPO}:${GRPC_DOTNET_COMMIT}" ) +# configLangArgs8core+=( -l dotnet ) +# configLangArgs32core+=( -l dotnet ) +# runnerLangArgs+=( -l "dotnet:${GRPC_DOTNET_REPO}:${GRPC_DOTNET_COMMIT}" ) # # go configLangArgs8core+=( -l go ) From 57d8462aee47ead0d2cba51ee7d516a8ab6c6d83 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 29 Nov 2023 11:29:46 -0800 Subject: [PATCH 020/127] Remove IWYU requirements for changes PiperOrigin-RevId: 586404245 --- .../dockerfile/grpc_iwyu/Dockerfile.template | 30 - tools/buildgen/generate_projects.sh | 2 - tools/distrib/fix_build_deps.py | 684 ------------------ tools/distrib/iwyu.sh | 63 -- tools/distrib/iwyu_mappings.imp | 9 - tools/dockerfile/grpc_iwyu/Dockerfile | 28 - tools/dockerfile/grpc_iwyu/iwyu.sh | 139 ---- tools/internal_ci/linux/grpc_iwyu.cfg | 30 - .../linux/pull_request/grpc_iwyu.cfg | 30 - tools/run_tests/run_tests.py | 1 - tools/run_tests/sanity/iwyu_tests.yaml | 2 - 11 files changed, 1018 deletions(-) delete mode 100644 templates/tools/dockerfile/grpc_iwyu/Dockerfile.template delete mode 100755 tools/distrib/fix_build_deps.py delete mode 100755 tools/distrib/iwyu.sh delete mode 100644 tools/distrib/iwyu_mappings.imp delete mode 100644 tools/dockerfile/grpc_iwyu/Dockerfile delete mode 100755 tools/dockerfile/grpc_iwyu/iwyu.sh delete mode 100644 tools/internal_ci/linux/grpc_iwyu.cfg delete mode 100644 tools/internal_ci/linux/pull_request/grpc_iwyu.cfg delete mode 100644 tools/run_tests/sanity/iwyu_tests.yaml diff --git a/templates/tools/dockerfile/grpc_iwyu/Dockerfile.template b/templates/tools/dockerfile/grpc_iwyu/Dockerfile.template deleted file mode 100644 index ecb4deef2839b..0000000000000 --- a/templates/tools/dockerfile/grpc_iwyu/Dockerfile.template +++ /dev/null @@ -1,30 +0,0 @@ -%YAML 1.2 ---- | - # Copyright 2021 gRPC authors. - # - # Licensed 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. - - # Docker file for running IWYU. - # Updated: 2022-11-03 - - FROM silkeh/clang:16-bullseye - - # Install prerequisites for the iwyu script - RUN apt-get update && apt-get install -y python3 jq git cmake python zlib1g-dev libtinfo-dev libclang-16-dev && apt-get clean - ADD iwyu.sh / - - # When running locally, we'll be impersonating the current user, so we need - # to make the script runnable by everyone. - RUN chmod a+rx /iwyu.sh - - CMD ["echo 'Run with tools/distrib/iwyu.sh'"] diff --git a/tools/buildgen/generate_projects.sh b/tools/buildgen/generate_projects.sh index 9ddd588bb37a9..e7905a40c9552 100755 --- a/tools/buildgen/generate_projects.sh +++ b/tools/buildgen/generate_projects.sh @@ -28,8 +28,6 @@ fi cd `dirname $0`/../.. -tools/distrib/fix_build_deps.py - echo "Generating build_autogenerated.yaml from bazel BUILD file" rm -f build_autogenerated.yaml python3 tools/buildgen/extract_metadata_from_bazel_xml.py diff --git a/tools/distrib/fix_build_deps.py b/tools/distrib/fix_build_deps.py deleted file mode 100755 index 0c014ec2b76ea..0000000000000 --- a/tools/distrib/fix_build_deps.py +++ /dev/null @@ -1,684 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright 2022 gRPC authors. -# -# Licensed 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. - -import argparse -import collections -from doctest import SKIP -import multiprocessing -import os -import re -import sys - -import run_buildozer - -# find our home -ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "../..")) -os.chdir(ROOT) - -vendors = collections.defaultdict(list) -scores = collections.defaultdict(int) -avoidness = collections.defaultdict(int) -consumes = {} -no_update = set() -buildozer_commands = [] -original_deps = {} -original_external_deps = {} -skip_headers = collections.defaultdict(set) - -# TODO(ctiller): ideally we wouldn't hardcode a bunch of paths here. -# We can likely parse out BUILD files from dependencies to generate this index. -EXTERNAL_DEPS = { - "absl/algorithm/container.h": "absl/algorithm:container", - "absl/base/attributes.h": "absl/base:core_headers", - "absl/base/call_once.h": "absl/base", - # TODO(ctiller) remove this - "absl/base/internal/endian.h": "absl/base:endian", - "absl/base/thread_annotations.h": "absl/base:core_headers", - "absl/container/flat_hash_map.h": "absl/container:flat_hash_map", - "absl/container/flat_hash_set.h": "absl/container:flat_hash_set", - "absl/container/inlined_vector.h": "absl/container:inlined_vector", - "absl/cleanup/cleanup.h": "absl/cleanup", - "absl/debugging/failure_signal_handler.h": ( - "absl/debugging:failure_signal_handler" - ), - "absl/debugging/stacktrace.h": "absl/debugging:stacktrace", - "absl/debugging/symbolize.h": "absl/debugging:symbolize", - "absl/flags/flag.h": "absl/flags:flag", - "absl/flags/marshalling.h": "absl/flags:marshalling", - "absl/flags/parse.h": "absl/flags:parse", - "absl/functional/any_invocable.h": "absl/functional:any_invocable", - "absl/functional/bind_front.h": "absl/functional:bind_front", - "absl/functional/function_ref.h": "absl/functional:function_ref", - "absl/hash/hash.h": "absl/hash", - "absl/memory/memory.h": "absl/memory", - "absl/meta/type_traits.h": "absl/meta:type_traits", - "absl/numeric/int128.h": "absl/numeric:int128", - "absl/random/random.h": "absl/random", - "absl/random/bit_gen_ref.h": "absl/random:bit_gen_ref", - "absl/random/mocking_bit_gen.h": "absl/random:mocking_bit_gen", - "absl/random/distributions.h": "absl/random:distributions", - "absl/random/uniform_int_distribution.h": "absl/random:distributions", - "absl/status/status.h": "absl/status", - "absl/status/statusor.h": "absl/status:statusor", - "absl/strings/ascii.h": "absl/strings", - "absl/strings/cord.h": "absl/strings:cord", - "absl/strings/escaping.h": "absl/strings", - "absl/strings/match.h": "absl/strings", - "absl/strings/numbers.h": "absl/strings", - "absl/strings/str_cat.h": "absl/strings", - "absl/strings/str_format.h": "absl/strings:str_format", - "absl/strings/str_join.h": "absl/strings", - "absl/strings/str_replace.h": "absl/strings", - "absl/strings/str_split.h": "absl/strings", - "absl/strings/string_view.h": "absl/strings", - "absl/strings/strip.h": "absl/strings", - "absl/strings/substitute.h": "absl/strings", - "absl/synchronization/mutex.h": "absl/synchronization", - "absl/synchronization/notification.h": "absl/synchronization", - "absl/time/clock.h": "absl/time", - "absl/time/time.h": "absl/time", - "absl/types/optional.h": "absl/types:optional", - "absl/types/span.h": "absl/types:span", - "absl/types/variant.h": "absl/types:variant", - "absl/utility/utility.h": "absl/utility", - "address_sorting/address_sorting.h": "address_sorting", - "google/cloud/opentelemetry/resource_detector.h": "google_cloud_cpp:opentelemetry", - "opentelemetry/common/attribute_value.h": "otel/api", - "opentelemetry/common/key_value_iterable.h": "otel/api", - "opentelemetry/nostd/function_ref.h": "otel/api", - "opentelemetry/nostd/string_view.h": "otel/api", - "opentelemetry/context/context.h": "otel/api", - "opentelemetry/metrics/meter.h": "otel/api", - "opentelemetry/metrics/meter_provider.h": "otel/api", - "opentelemetry/metrics/provider.h": "otel/api", - "opentelemetry/metrics/sync_instruments.h": "otel/api", - "opentelemetry/nostd/shared_ptr.h": "otel/api", - "opentelemetry/nostd/unique_ptr.h": "otel/api", - "opentelemetry/sdk/metrics/meter_provider.h": "otel/sdk/src/metrics", - "opentelemetry/sdk/common/attribute_utils.h": "otel/sdk:headers", - "opentelemetry/sdk/resource/resource.h": "otel/sdk:headers", - "opentelemetry/sdk/resource/resource_detector.h": "otel/sdk:headers", - "opentelemetry/sdk/resource/semantic_conventions.h": "otel/sdk:headers", - "ares.h": "cares", - "fuzztest/fuzztest.h": ["fuzztest", "fuzztest_main"], - "google/api/monitored_resource.pb.h": ( - "google/api:monitored_resource_cc_proto" - ), - "google/devtools/cloudtrace/v2/tracing.grpc.pb.h": ( - "googleapis_trace_grpc_service" - ), - "google/logging/v2/logging.grpc.pb.h": "googleapis_logging_grpc_service", - "google/logging/v2/logging.pb.h": "googleapis_logging_cc_proto", - "google/logging/v2/log_entry.pb.h": "googleapis_logging_cc_proto", - "google/monitoring/v3/metric_service.grpc.pb.h": ( - "googleapis_monitoring_grpc_service" - ), - "gmock/gmock.h": "gtest", - "gtest/gtest.h": "gtest", - "opencensus/exporters/stats/stackdriver/stackdriver_exporter.h": ( - "opencensus-stats-stackdriver_exporter" - ), - "opencensus/exporters/trace/stackdriver/stackdriver_exporter.h": ( - "opencensus-trace-stackdriver_exporter" - ), - "opencensus/trace/context_util.h": "opencensus-trace-context_util", - "opencensus/trace/propagation/grpc_trace_bin.h": ( - "opencensus-trace-propagation" - ), - "opencensus/tags/context_util.h": "opencensus-tags-context_util", - "opencensus/trace/span_context.h": "opencensus-trace-span_context", - "openssl/base.h": "libssl", - "openssl/bio.h": "libssl", - "openssl/bn.h": "libcrypto", - "openssl/buffer.h": "libcrypto", - "openssl/crypto.h": "libcrypto", - "openssl/digest.h": "libssl", - "openssl/engine.h": "libcrypto", - "openssl/err.h": "libcrypto", - "openssl/evp.h": "libcrypto", - "openssl/hmac.h": "libcrypto", - "openssl/mem.h": "libcrypto", - "openssl/param_build.h": "libcrypto", - "openssl/pem.h": "libcrypto", - "openssl/rsa.h": "libcrypto", - "openssl/sha.h": "libcrypto", - "openssl/ssl.h": "libssl", - "openssl/tls1.h": "libssl", - "openssl/x509.h": "libcrypto", - "openssl/x509v3.h": "libcrypto", - "re2/re2.h": "re2", - "upb/base/string_view.h": "upb_base_lib", - "upb/collections/map.h": "upb_collections_lib", - "upb/reflection/def.h": "upb_reflection", - "upb/json/encode.h": "upb_json_lib", - "upb/mem/arena.h": "upb_mem_lib", - "upb/text/encode.h": "upb_textformat_lib", - "upb/reflection/def.hpp": "upb_reflection", - "upb/upb.h": "upb_amalgamation_lib", - "upb/upb.hpp": "upb_lib", - "xxhash.h": "xxhash", - "zlib.h": "madler_zlib", -} - -INTERNAL_DEPS = { - "test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h": ( - "//test/core/event_engine/fuzzing_event_engine" - ), - "test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.pb.h": "//test/core/event_engine/fuzzing_event_engine:fuzzing_event_engine_proto", - "test/core/experiments/test_experiments.h": "//test/core/experiments:test_experiments_lib", - "google/api/expr/v1alpha1/syntax.upb.h": "google_api_expr_v1alpha1_syntax_upb", - "google/rpc/status.upb.h": "google_rpc_status_upb", - "google/protobuf/any.upb.h": "protobuf_any_upb", - "google/protobuf/duration.upb.h": "protobuf_duration_upb", - "google/protobuf/struct.upb.h": "protobuf_struct_upb", - "google/protobuf/timestamp.upb.h": "protobuf_timestamp_upb", - "google/protobuf/wrappers.upb.h": "protobuf_wrappers_upb", - "grpc/status.h": "grpc_public_hdrs", - "src/proto/grpc/channelz/channelz.grpc.pb.h": ( - "//src/proto/grpc/channelz:channelz_proto" - ), - "src/proto/grpc/core/stats.pb.h": "//src/proto/grpc/core:stats_proto", - "src/proto/grpc/health/v1/health.upb.h": "grpc_health_upb", - "src/proto/grpc/lb/v1/load_reporter.grpc.pb.h": ( - "//src/proto/grpc/lb/v1:load_reporter_proto" - ), - "src/proto/grpc/lb/v1/load_balancer.upb.h": "grpc_lb_upb", - "src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.h": ( - "//src/proto/grpc/reflection/v1alpha:reflection_proto" - ), - "src/proto/grpc/gcp/transport_security_common.upb.h": "alts_upb", - "src/proto/grpc/gcp/handshaker.upb.h": "alts_upb", - "src/proto/grpc/gcp/altscontext.upb.h": "alts_upb", - "src/proto/grpc/lookup/v1/rls.upb.h": "rls_upb", - "src/proto/grpc/lookup/v1/rls_config.upb.h": "rls_config_upb", - "src/proto/grpc/lookup/v1/rls_config.upbdefs.h": "rls_config_upbdefs", - "src/proto/grpc/testing/xds/v3/csds.grpc.pb.h": ( - "//src/proto/grpc/testing/xds/v3:csds_proto" - ), - "xds/data/orca/v3/orca_load_report.upb.h": "xds_orca_upb", - "xds/service/orca/v3/orca.upb.h": "xds_orca_service_upb", - "xds/type/v3/typed_struct.upb.h": "xds_type_upb", -} - - -class FakeSelects: - def config_setting_group(self, **kwargs): - pass - - -num_cc_libraries = 0 -num_opted_out_cc_libraries = 0 -parsing_path = None - - -# Convert the source or header target to a relative path. -def _get_filename(name, parsing_path): - filename = "%s%s" % ( - ( - parsing_path + "/" - if (parsing_path and not name.startswith("//")) - else "" - ), - name, - ) - filename = filename.replace("//:", "") - filename = filename.replace("//src/core:", "src/core/") - filename = filename.replace( - "//src/cpp/ext/filters/census:", "src/cpp/ext/filters/census/" - ) - return filename - - -def grpc_cc_library( - name, - hdrs=[], - public_hdrs=[], - srcs=[], - select_deps=None, - tags=[], - deps=[], - external_deps=[], - proto=None, - **kwargs, -): - global args - global num_cc_libraries - global num_opted_out_cc_libraries - global parsing_path - assert parsing_path is not None - name = "//%s:%s" % (parsing_path, name) - num_cc_libraries += 1 - if select_deps or "nofixdeps" in tags: - if args.whats_left and not select_deps and "nofixdeps" not in tags: - num_opted_out_cc_libraries += 1 - print("Not opted in: {}".format(name)) - no_update.add(name) - scores[name] = len(public_hdrs + hdrs) - # avoid_dep is the internal way of saying prefer something else - # we add grpc_avoid_dep to allow internal grpc-only stuff to avoid each - # other, whilst not biasing dependent projects - if "avoid_dep" in tags or "grpc_avoid_dep" in tags: - avoidness[name] += 10 - if proto: - proto_hdr = "%s%s" % ( - (parsing_path + "/" if parsing_path else ""), - proto.replace(".proto", ".pb.h"), - ) - skip_headers[name].add(proto_hdr) - - for hdr in hdrs + public_hdrs: - vendors[_get_filename(hdr, parsing_path)].append(name) - inc = set() - original_deps[name] = frozenset(deps) - original_external_deps[name] = frozenset(external_deps) - for src in hdrs + public_hdrs + srcs: - for line in open(_get_filename(src, parsing_path)): - m = re.search(r"^#include <(.*)>", line) - if m: - inc.add(m.group(1)) - m = re.search(r'^#include "(.*)"', line) - if m: - inc.add(m.group(1)) - consumes[name] = list(inc) - - -def grpc_proto_library(name, srcs, **kwargs): - global parsing_path - assert parsing_path is not None - name = "//%s:%s" % (parsing_path, name) - for src in srcs: - proto_hdr = src.replace(".proto", ".pb.h") - vendors[_get_filename(proto_hdr, parsing_path)].append(name) - - -def buildozer(cmd, target): - buildozer_commands.append("%s|%s" % (cmd, target)) - - -def buildozer_set_list(name, values, target, via=""): - if not values: - buildozer("remove %s" % name, target) - return - adjust = via if via else name - buildozer( - "set %s %s" % (adjust, " ".join('"%s"' % s for s in values)), target - ) - if via: - buildozer("remove %s" % name, target) - buildozer("rename %s %s" % (via, name), target) - - -def score_edit_distance(proposed, existing): - """Score a proposed change primarily by edit distance""" - sum = 0 - for p in proposed: - if p not in existing: - sum += 1 - for e in existing: - if e not in proposed: - sum += 1 - return sum - - -def total_score(proposal): - return sum(scores[dep] for dep in proposal) - - -def total_avoidness(proposal): - return sum(avoidness[dep] for dep in proposal) - - -def score_list_size(proposed, existing): - """Score a proposed change primarily by number of dependencies""" - return len(proposed) - - -def score_best(proposed, existing): - """Score a proposed change primarily by dependency score""" - return 0 - - -SCORERS = { - "edit_distance": score_edit_distance, - "list_size": score_list_size, - "best": score_best, -} - -parser = argparse.ArgumentParser(description="Fix build dependencies") -parser.add_argument( - "targets", nargs="*", default=[], help="targets to fix (empty => all)" -) -parser.add_argument( - "--score", - type=str, - default="edit_distance", - help="scoring function to use: one of " + ", ".join(SCORERS.keys()), -) -parser.add_argument( - "--whats_left", - action="store_true", - default=False, - help="show what is left to opt in", -) -parser.add_argument( - "--explain", - action="store_true", - default=False, - help="try to explain some decisions", -) -parser.add_argument( - "--why", - type=str, - default=None, - help="with --explain, target why a given dependency is needed", -) -args = parser.parse_args() - -for dirname in [ - "", - "src/core", - "src/cpp/ext/gcp", - "src/cpp/ext/csm", - "src/cpp/ext/otel", - "test/core/backoff", - "test/core/experiments", - "test/core/uri", - "test/core/util", - "test/core/end2end", - "test/core/event_engine", - "test/core/filters", - "test/core/promise", - "test/core/resource_quota", - "test/core/transport/chaotic_good", - "fuzztest", - "fuzztest/core/channel", - "fuzztest/core/transport/chttp2", -]: - parsing_path = dirname - exec( - open("%sBUILD" % (dirname + "/" if dirname else ""), "r").read(), - { - "load": lambda filename, *args: None, - "licenses": lambda licenses: None, - "package": lambda **kwargs: None, - "exports_files": lambda files, visibility=None: None, - "bool_flag": lambda **kwargs: None, - "config_setting": lambda **kwargs: None, - "selects": FakeSelects(), - "python_config_settings": lambda **kwargs: None, - "grpc_cc_binary": grpc_cc_library, - "grpc_cc_library": grpc_cc_library, - "grpc_cc_test": grpc_cc_library, - "grpc_core_end2end_test": lambda **kwargs: None, - "grpc_fuzzer": grpc_cc_library, - "grpc_fuzz_test": grpc_cc_library, - "grpc_proto_fuzzer": grpc_cc_library, - "grpc_proto_library": grpc_proto_library, - "select": lambda d: d["//conditions:default"], - "glob": lambda files: None, - "grpc_end2end_tests": lambda: None, - "grpc_upb_proto_library": lambda name, **kwargs: None, - "grpc_upb_proto_reflection_library": lambda name, **kwargs: None, - "grpc_generate_one_off_targets": lambda: None, - "grpc_generate_one_off_internal_targets": lambda: None, - "grpc_package": lambda **kwargs: None, - "filegroup": lambda name, **kwargs: None, - "sh_library": lambda name, **kwargs: None, - }, - {}, - ) - parsing_path = None - -if args.whats_left: - print( - "{}/{} libraries are opted in".format( - num_cc_libraries - num_opted_out_cc_libraries, num_cc_libraries - ) - ) - - -def make_relative_path(dep, lib): - if lib is None: - return dep - lib_path = lib[: lib.rfind(":") + 1] - if dep.startswith(lib_path): - return dep[len(lib_path) :] - return dep - - -if args.whats_left: - print( - "{}/{} libraries are opted in".format( - num_cc_libraries - num_opted_out_cc_libraries, num_cc_libraries - ) - ) - - -# Keeps track of all possible sets of dependencies that could satify the -# problem. (models the list monad in Haskell!) -class Choices: - def __init__(self, library, substitutions): - self.library = library - self.to_add = [] - self.to_remove = [] - self.substitutions = substitutions - - def add_one_of(self, choices, trigger): - if not choices: - return - choices = sum( - [self.apply_substitutions(choice) for choice in choices], [] - ) - if args.explain and (args.why is None or args.why in choices): - print( - "{}: Adding one of {} for {}".format( - self.library, choices, trigger - ) - ) - self.to_add.append( - tuple( - make_relative_path(choice, self.library) for choice in choices - ) - ) - - def add(self, choice, trigger): - self.add_one_of([choice], trigger) - - def remove(self, remove): - for remove in self.apply_substitutions(remove): - self.to_remove.append(make_relative_path(remove, self.library)) - - def apply_substitutions(self, dep): - if dep in self.substitutions: - return self.substitutions[dep] - return [dep] - - def best(self, scorer): - choices = set() - choices.add(frozenset()) - - for add in sorted(set(self.to_add), key=lambda x: (len(x), x)): - new_choices = set() - for append_choice in add: - for choice in choices: - new_choices.add(choice.union([append_choice])) - choices = new_choices - for remove in sorted(set(self.to_remove)): - new_choices = set() - for choice in choices: - new_choices.add(choice.difference([remove])) - choices = new_choices - - best = None - - def final_scorer(x): - return (total_avoidness(x), scorer(x), total_score(x)) - - for choice in choices: - if best is None or final_scorer(choice) < final_scorer(best): - best = choice - return best - - -def make_library(library): - error = False - hdrs = sorted(consumes[library]) - # we need a little trickery here since grpc_base has channel.cc, which calls grpc_init - # which is in grpc, which is illegal but hard to change - # once EventEngine lands we can clean this up - deps = Choices( - library, - {"//:grpc_base": ["//:grpc", "//:grpc_unsecure"]} - if library.startswith("//test/") - else {}, - ) - external_deps = Choices(None, {}) - for hdr in hdrs: - if hdr in skip_headers[library]: - continue - - if hdr == "systemd/sd-daemon.h": - continue - - if hdr == "src/core/lib/profiling/stap_probes.h": - continue - - if hdr.startswith("src/libfuzzer/"): - continue - - if hdr == "grpc/grpc.h" and library.startswith("//test:"): - # not the root build including grpc.h ==> //:grpc - deps.add_one_of(["//:grpc", "//:grpc_unsecure"], hdr) - continue - - if hdr in INTERNAL_DEPS: - dep = INTERNAL_DEPS[hdr] - if isinstance(dep, list): - for d in dep: - deps.add(d, hdr) - else: - if not ("//" in dep): - dep = "//:" + dep - deps.add(dep, hdr) - continue - - if hdr in vendors: - deps.add_one_of(vendors[hdr], hdr) - continue - - if "include/" + hdr in vendors: - deps.add_one_of(vendors["include/" + hdr], hdr) - continue - - if "." not in hdr: - # assume a c++ system include - continue - - if hdr in EXTERNAL_DEPS: - if isinstance(EXTERNAL_DEPS[hdr], list): - for dep in EXTERNAL_DEPS[hdr]: - external_deps.add(dep, hdr) - else: - external_deps.add(EXTERNAL_DEPS[hdr], hdr) - continue - - if hdr.startswith("opencensus/"): - trail = hdr[len("opencensus/") :] - trail = trail[: trail.find("/")] - external_deps.add("opencensus-" + trail, hdr) - continue - - if hdr.startswith("envoy/"): - path, file = os.path.split(hdr) - file = file.split(".") - path = path.split("/") - dep = "_".join(path[:-1] + [file[1]]) - deps.add(dep, hdr) - continue - - if hdr.startswith("google/protobuf/") and not hdr.endswith(".upb.h"): - external_deps.add("protobuf_headers", hdr) - continue - - if "/" not in hdr: - # assume a system include - continue - - is_sys_include = False - for sys_path in [ - "sys", - "arpa", - "gperftools", - "netinet", - "linux", - "android", - "mach", - "net", - "CoreFoundation", - ]: - if hdr.startswith(sys_path + "/"): - is_sys_include = True - break - if is_sys_include: - # assume a system include - continue - - print( - "# ERROR: can't categorize header: %s used by %s" % (hdr, library) - ) - error = True - - deps.remove(library) - - deps = sorted( - deps.best(lambda x: SCORERS[args.score](x, original_deps[library])) - ) - external_deps = sorted( - external_deps.best( - lambda x: SCORERS[args.score](x, original_external_deps[library]) - ) - ) - - return (library, error, deps, external_deps) - - -def main() -> None: - update_libraries = [] - for library in sorted(consumes.keys()): - if library in no_update: - continue - if args.targets and library not in args.targets: - continue - update_libraries.append(library) - with multiprocessing.Pool(processes=multiprocessing.cpu_count()) as p: - updated_libraries = p.map(make_library, update_libraries, 1) - - error = False - for library, lib_error, deps, external_deps in updated_libraries: - if lib_error: - error = True - continue - buildozer_set_list("external_deps", external_deps, library, via="deps") - buildozer_set_list("deps", deps, library) - - run_buildozer.run_buildozer(buildozer_commands) - - if error: - sys.exit(1) - - -if __name__ == "__main__": - main() diff --git a/tools/distrib/iwyu.sh b/tools/distrib/iwyu.sh deleted file mode 100755 index 9a00fde2b4d38..0000000000000 --- a/tools/distrib/iwyu.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/bash -# Copyright 2021 gRPC authors. -# -# Licensed 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. - -echo "NOTE: to automagically apply fixes, invoke with --fix" - -set -ex - -# change to root directory -cd $(dirname $0)/../.. -REPO_ROOT=$(pwd) - -# grep targets with manual tag, which is not included in a result of bazel build using ... -# let's get a list of them using query command and pass it to gen_compilation_database.py -export MANUAL_TARGETS=$(bazel query 'attr("tags", "manual", tests(//test/cpp/...))' | grep -v _on_ios) - -# generate a clang compilation database for all C/C++ sources in the repo. -tools/distrib/gen_compilation_database.py \ - --include_headers \ - --ignore_system_headers \ - --dedup_targets \ - "//:*" \ - "//src/core/..." \ - "//src/cpp/ext/csm/..." \ - "//src/cpp/ext/gcp/..." \ - "//src/cpp/ext/otel/..." \ - "//src/compiler/..." \ - "//test/core/..." \ - "//test/cpp/..." \ - "//fuzztest/..." \ - $MANUAL_TARGETS - -# run iwyu against the checked out codebase -# when modifying the checked-out files, the current user will be impersonated -# so that the updated files don't end up being owned by "root". -if [ "$IWYU_SKIP_DOCKER" == "" ] -then - # build iwyu docker image - docker build -t grpc_iwyu tools/dockerfile/grpc_iwyu - - docker run \ - -e TEST="$TEST" \ - -e CHANGED_FILES="$CHANGED_FILES" \ - -e IWYU_ROOT="/local-code" \ - --rm=true \ - -v "${REPO_ROOT}":/local-code \ - -v "${HOME/.cache/bazel}":"${HOME/.cache/bazel}" \ - --user "$(id -u):$(id -g)" \ - -t grpc_iwyu /iwyu.sh "$@" -else - IWYU_ROOT="${REPO_ROOT}" tools/dockerfile/grpc_iwyu/iwyu.sh -fi diff --git a/tools/distrib/iwyu_mappings.imp b/tools/distrib/iwyu_mappings.imp deleted file mode 100644 index 3f993a9aee5fd..0000000000000 --- a/tools/distrib/iwyu_mappings.imp +++ /dev/null @@ -1,9 +0,0 @@ -[ - { include: ["", "private", "", "public"] }, - { include: ["", "public", "\"src/core/lib/iomgr/sockaddr.h\"", "public"]}, - { include: ["", "public", "\"src/core/lib/iomgr/sockaddr.h\"", "public"]}, - { include: ["", "private", "", "public"] }, - { include: ["", "private", "", "public"] }, - # workaround: https://github.com/include-what-you-use/include-what-you-use/issues/908 - { symbol: ["std::max", "private", "", "public" ] }, -] diff --git a/tools/dockerfile/grpc_iwyu/Dockerfile b/tools/dockerfile/grpc_iwyu/Dockerfile deleted file mode 100644 index 01b9a2d3a4aee..0000000000000 --- a/tools/dockerfile/grpc_iwyu/Dockerfile +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2021 gRPC authors. -# -# Licensed 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. - -# Docker file for running IWYU. -# Updated: 2022-11-03 - -FROM silkeh/clang:16-bullseye - -# Install prerequisites for the iwyu script -RUN apt-get update && apt-get install -y python3 jq git cmake python zlib1g-dev libtinfo-dev libclang-16-dev && apt-get clean -ADD iwyu.sh / - -# When running locally, we'll be impersonating the current user, so we need -# to make the script runnable by everyone. -RUN chmod a+rx /iwyu.sh - -CMD ["echo 'Run with tools/distrib/iwyu.sh'"] diff --git a/tools/dockerfile/grpc_iwyu/iwyu.sh b/tools/dockerfile/grpc_iwyu/iwyu.sh deleted file mode 100755 index 96f5ba7459207..0000000000000 --- a/tools/dockerfile/grpc_iwyu/iwyu.sh +++ /dev/null @@ -1,139 +0,0 @@ -#!/bin/sh -# Copyright 2017 gRPC authors. -# -# Licensed 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. - -set -x - -cd ${IWYU_ROOT} - -export PATH=${PATH}:${IWYU_ROOT}/iwyu_build/bin - -# number of CPUs available -CPU_COUNT=`nproc` - -rm -rf iwyu || true -git clone https://github.com/include-what-you-use/include-what-you-use.git iwyu - -############################################################################### -# -# BEWARE! BEWARE! BEWARE! BEWARE! BEWARE! BEWARE! BEWARE! BEWARE! -# -# Changing the version of iwyu can bring along subtle changes. -# You *must* test the new version of iwyu: -# 1. run it on the entire codebase before submitting -# 2. UPLOAD A CHANGE THAT SHOULD BE BROKEN AFTER SUBMISSION OF THIS CHANGE -# ensure that the broken change is caught by the new version of iwyu -# -# BEWARE! BEWARE! BEWARE! BEWARE! BEWARE! BEWARE! BEWARE! BEWARE! -# -############################################################################### - -# latest commit on the clang_16 branch -cd ${IWYU_ROOT}/iwyu -git checkout 7301b1fc88e5e16d8df73aecea55037d9c0a371b -if [ $? -ne 0 ]; then - echo "Failed to checkout iwyu commit" - exit 1 -fi -mkdir -p ${IWYU_ROOT}/iwyu_build -cd ${IWYU_ROOT}/iwyu_build -cmake -G "Unix Makefiles" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DLLVM_ROOT_DIR=/usr/lib/llvm-16 ${IWYU_ROOT}/iwyu -if [ $? -ne 0 ]; then - echo "Failed to cmake iwyu" - exit 1 -fi -make -j $CPU_COUNT -if [ $? -ne 0 ]; then - echo "Failed to make iwyu" - exit 1 -fi -cd ${IWYU_ROOT} - -cat compile_commands.json \ - | sed "s/ -DNDEBUG//g" \ - | sed "s/ -std=c\\+\\+14/ -std=c++17/g" \ - | sed "s,\"file\": \",\"file\": \"${IWYU_ROOT}/,g" \ - > compile_commands_for_iwyu.json - -export ENABLED_MODULES=' - src/core/ext - src/core/lib - src/cpp - src/python/grpcio_observability - test/core - fuzztest -' - -export DISABLED_MODULES=' - src/core/lib/gpr - src/core/lib/iomgr - src/core/ext/transport/binder - test/core/alts - test/core/iomgr - test/core/security - test/core/tsi - test/core/transport/binder -' - -export INCLUSION_REGEX=`echo $ENABLED_MODULES | sed 's/ /|/g' | sed 's,\\(.*\\),^(\\1)/,g'` -export EXCLUSION_REGEX=`echo $DISABLED_MODULES | sed 's/ /|/g' | sed 's,\\(.*\\),^(\\1)/,g'` - -# figure out which files to include -cat compile_commands.json | jq -r '.[].file' \ - | grep -E $INCLUSION_REGEX \ - | grep -v -E "/upb-gen/|/upbdefs-gen/" \ - | grep -v -E $EXCLUSION_REGEX \ - | grep -v src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h \ - | grep -v test/core/end2end/end2end_tests.cc \ - | sort \ - > iwyu_files0.txt - -cat iwyu_files0.txt \ - | xargs -d '\n' ls -1df 2> /dev/null \ - > iwyu_files.txt \ - || true - -echo '#!/bin/sh -${IWYU_ROOT}/iwyu/iwyu_tool.py -p compile_commands_for_iwyu.json $1 \ - -- -Xiwyu --no_fwd_decls \ - -Xiwyu --update_comments \ - -Xiwyu --mapping_file=${IWYU_ROOT}/tools/distrib/iwyu_mappings.imp \ - | grep -v -E "port_platform.h" \ - | grep -v -E "repeated_ptr_field.h" \ - | grep -v -E "repeated_field.h" \ - | grep -v -E "^(- )?namespace " \ - > iwyu/iwyu.`echo $1 | sha1sum`.out -' > iwyu/run_iwyu_on.sh -chmod +x iwyu/run_iwyu_on.sh - -# run iwyu, filtering out changes to port_platform.h -xargs -n 1 -P $CPU_COUNT -a iwyu_files.txt ${IWYU_ROOT}/iwyu/run_iwyu_on.sh - -cat iwyu/iwyu.*.out > iwyu.out - -# apply the suggested changes -${IWYU_ROOT}/iwyu/fix_includes.py \ - --nocomments \ - --nosafe_headers \ - --ignore_re='^(include/.*|src/core/lib/security/credentials/tls/grpc_tls_credentials_options\.h|external/.*)' \ - < iwyu.out \ - | grep 'IWYU edited 0 files on your behalf' - -if [ $? -ne 0 ] -then - echo "Iwyu edited some files. Here is the diff of files edited by iwyu:" - git --no-pager diff - # Exit with a non zero error code to ensure sanity checks fail accordingly. - exit 1 -fi diff --git a/tools/internal_ci/linux/grpc_iwyu.cfg b/tools/internal_ci/linux/grpc_iwyu.cfg deleted file mode 100644 index 33fbbd68bad00..0000000000000 --- a/tools/internal_ci/linux/grpc_iwyu.cfg +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright 2017 gRPC authors. -# -# Licensed 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. - -# Config file for the internal CI (in protobuf text format) - -# Location of the continuous shell script in repository. -build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh" -timeout_mins: 60 -action { - define_artifacts { - regex: "**/*sponge_log.*" - regex: "github/grpc/reports/**" - } -} - -env_vars { - key: "RUN_TESTS_FLAGS" - value: "-f basictests linux iwyu --inner_jobs 16 -j 1 --internal_ci --bq_result_table aggregate_results" -} diff --git a/tools/internal_ci/linux/pull_request/grpc_iwyu.cfg b/tools/internal_ci/linux/pull_request/grpc_iwyu.cfg deleted file mode 100644 index 4d7fcecc9a6ca..0000000000000 --- a/tools/internal_ci/linux/pull_request/grpc_iwyu.cfg +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright 2017 gRPC authors. -# -# Licensed 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. - -# Config file for the internal CI (in protobuf text format) - -# Location of the continuous shell script in repository. -build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh" -timeout_mins: 60 -action { - define_artifacts { - regex: "**/*sponge_log.*" - regex: "github/grpc/reports/**" - } -} - -env_vars { - key: "RUN_TESTS_FLAGS" - value: "-f basictests linux iwyu --inner_jobs 16 -j 1 --internal_ci" -} diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index 64d2cfcbeb01c..88a9a648bbdfb 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -1304,7 +1304,6 @@ def __str__(self): "objc": ObjCLanguage(), "sanity": Sanity("sanity_tests.yaml"), "clang-tidy": Sanity("clang_tidy_tests.yaml"), - "iwyu": Sanity("iwyu_tests.yaml"), } _MSBUILD_CONFIG = { diff --git a/tools/run_tests/sanity/iwyu_tests.yaml b/tools/run_tests/sanity/iwyu_tests.yaml deleted file mode 100644 index 2c9c7836d7fbd..0000000000000 --- a/tools/run_tests/sanity/iwyu_tests.yaml +++ /dev/null @@ -1,2 +0,0 @@ -- script: tools/distrib/iwyu.sh - cpu_cost: 1000 From 92eb194140aff1bde3e045e1c61bf43faf899202 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Wed, 29 Nov 2023 15:27:30 -0800 Subject: [PATCH 021/127] [interop] Add grpc-java 1.59.1 to client_matrix.py (#35130) Closes #35130 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35130 from ejona86:java-1.59.1 8e966842255acaf7a683f8095c0ef5284b87de73 PiperOrigin-RevId: 586470793 --- tools/interop_matrix/client_matrix.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/interop_matrix/client_matrix.py b/tools/interop_matrix/client_matrix.py index 110e29ce2f1aa..836485bdb6949 100644 --- a/tools/interop_matrix/client_matrix.py +++ b/tools/interop_matrix/client_matrix.py @@ -430,7 +430,7 @@ def __init__(self, patch=[], runtimes=[], testcases_file=None): ("v1.56.0", ReleaseInfo()), ("v1.57.2", ReleaseInfo()), ("v1.58.0", ReleaseInfo()), - ("v1.59.0", ReleaseInfo()), + ("v1.59.1", ReleaseInfo()), ] ), "python": OrderedDict( From a215eb671775057bfaa55c16d62a9bf3f0b4a1fd Mon Sep 17 00:00:00 2001 From: AJ Heller Date: Wed, 29 Nov 2023 15:29:34 -0800 Subject: [PATCH 022/127] [test] Sleep between server restarts in retry_transparent_max_concurrent_streams (#35149) This hack temporarily quiets the flaky test report for a known race. This is the only end2end test that shuts down & restarts a server in the same test execution. The PosixEventEngine's Listener implementation asynchronously shuts down listening ports after Listener destruction. Some changes can possibly be made here to only proceed in server restart after the `on_shutdown` callback is called, ensuring all ports are closed before proceeding. Closes #35149 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35149 from drfloob:hack/max_concurrent_fix_for_posix_ee_listener 9a7b7b53ddda421d627a7a49458974af852f8c89 PiperOrigin-RevId: 586471281 --- .../end2end/tests/retry_transparent_max_concurrent_streams.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/core/end2end/tests/retry_transparent_max_concurrent_streams.cc b/test/core/end2end/tests/retry_transparent_max_concurrent_streams.cc index ceb374042475c..663fd6f610597 100644 --- a/test/core/end2end/tests/retry_transparent_max_concurrent_streams.cc +++ b/test/core/end2end/tests/retry_transparent_max_concurrent_streams.cc @@ -104,6 +104,8 @@ CORE_END2END_TEST(RetryHttp2Test, RetryTransparentMaxConcurrentStreams) { EXPECT_EQ(server_status.status(), GRPC_STATUS_OK); EXPECT_EQ(server_status.message(), "xyz"); // Destroy server and then restart it. + // TODO(hork): hack to solve PosixEventEngine Listener's async shutdown issue. + absl::SleepFor(absl::Milliseconds(250)); InitServer(server_args); // Server should get the second call. auto s2 = RequestCall(201); From 0c78392570c4eb050e8cfeaef9588fcf865e2ac3 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Thu, 30 Nov 2023 09:12:37 -0800 Subject: [PATCH 023/127] [autofix] attempt to log actor string (#35182) --- .github/workflows/pr-auto-fix.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pr-auto-fix.yaml b/.github/workflows/pr-auto-fix.yaml index 2374a5e0e0ddc..4b930563dca4a 100644 --- a/.github/workflows/pr-auto-fix.yaml +++ b/.github/workflows/pr-auto-fix.yaml @@ -50,6 +50,7 @@ jobs: // If you'd like not to run this code on your commits, add your github user id here: NO_AUTOFIX_USERS = ["copybara-service"] const { owner, repo } = context.repo + console.log("Actor: " + context.actor); if (NO_AUTOFIX_USERS.includes(context.actor)) { console.log('Cancelling'); const run_id = "${{ github.run_id }}"; From f356ef47e69edf14cc5465cd7763abba68ce4e33 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Thu, 30 Nov 2023 10:06:29 -0800 Subject: [PATCH 024/127] [experiments] extend expiration of happy eyeballs experiment (#35181) Closes #35181 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35181 from markdroth:happy_eyeballs_experiment_expiration 5da6d05f610ce0cf303a851f6b517757bca0cff9 PiperOrigin-RevId: 586709581 --- src/core/lib/experiments/experiments.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/lib/experiments/experiments.yaml b/src/core/lib/experiments/experiments.yaml index 60ed3d7eb2e10..76273515fdf82 100644 --- a/src/core/lib/experiments/experiments.yaml +++ b/src/core/lib/experiments/experiments.yaml @@ -185,7 +185,7 @@ - name: pick_first_happy_eyeballs description: Use Happy Eyeballs in pick_first. - expiry: 2023/12/15 + expiry: 2024/01/15 owner: roth@google.com test_tags: ["lb_unit_test", "cpp_lb_end2end_test", "xds_end2end_test"] - name: ping_on_rst_stream From f9e56a9467eb637bfcc50396712a7c4b80ea748d Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Thu, 30 Nov 2023 11:52:35 -0800 Subject: [PATCH 025/127] [TLS certificate provider] remove pollset_set from cert provider API (#35013) We have no cert providers today that actually use iomgr polling, so this API is not actually used anywhere. And even if we wanted to add a cert provider that did use iomgr polling, I don't think it would work correctly, because we are plumbing the pollset_set linkage only for XdsCredentials, not for normal TlsCredentials. Closes #35013 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35013 from markdroth:cert_provider_remove_pollset_set 383cd02ffb6405a77006a97601bb73606e254067 PiperOrigin-RevId: 586743891 --- .../client_channel/lb_policy/xds/cds.cc | 57 +++++-------------- src/core/ext/xds/certificate_provider_store.h | 5 -- .../tls/grpc_tls_certificate_provider.h | 3 - 3 files changed, 14 insertions(+), 51 deletions(-) diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/cds.cc b/src/core/ext/filters/client_channel/lb_policy/xds/cds.cc index 7e42338d70d86..ea42f22e7c078 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/cds.cc +++ b/src/core/ext/filters/client_channel/lb_policy/xds/cds.cc @@ -199,21 +199,18 @@ class CdsLb : public LoadBalancingPolicy { // The root of the tree is config_->cluster(). std::map watchers_; - // TODO(roth, yashkt): These are here because we need to handle - // pollset_set linkage as clusters are added or removed from the - // XdsCertificateProvider. However, in the aggregate cluster case, - // there may be multiple clusters in the same cert provider, and we're - // only tracking the cert providers for the most recent underlying - // cluster here. I think this is a bug that could cause us to starve - // the underlying cert providers of polling. However, it is not - // actually causing any problem in practice today, because (a) we have - // no cert provider impl that relies on gRPC's polling and (b) - // probably no one is actually configuring an aggregate cluster with - // different cert providers in different underlying clusters. - // Hopefully, this problem won't be an issue in practice until after - // the EventEngine migration is done, at which point the need for - // handling pollset_set linkage will go away, and these fields can - // simply be removed. + // TODO(roth, yashkt): These are here because XdsCertificateProvider + // does not store the actual underlying cert providers, it stores only + // their distributors, so we need to hold a ref to the cert providers + // here. However, in the aggregate cluster case, there may be multiple + // clusters in the same cert provider, and we're only tracking the cert + // providers for the most recent underlying cluster here. This is + // clearly a bug, and I think it will cause us to stop getting updates + // for all but one of the cert providers in the aggregate cluster + // case. Need to figure out the right way to fix this -- I don't + // think we want to store another map here, so ideally, we should just + // have XdsCertificateProvider actually hold the refs to the cert + // providers instead of just the distributors. RefCountedPtr root_certificate_provider_; RefCountedPtr identity_certificate_provider_; @@ -610,20 +607,7 @@ absl::Status CdsLb::UpdateXdsCertificateProvider( root_provider_instance_name, "\" not recognized.")); } } - if (root_certificate_provider_ != new_root_provider) { - if (root_certificate_provider_ != nullptr && - root_certificate_provider_->interested_parties() != nullptr) { - grpc_pollset_set_del_pollset_set( - interested_parties(), - root_certificate_provider_->interested_parties()); - } - if (new_root_provider != nullptr && - new_root_provider->interested_parties() != nullptr) { - grpc_pollset_set_add_pollset_set(interested_parties(), - new_root_provider->interested_parties()); - } - root_certificate_provider_ = std::move(new_root_provider); - } + root_certificate_provider_ = std::move(new_root_provider); xds_certificate_provider_->UpdateRootCertNameAndDistributor( cluster_name, root_provider_cert_name, root_certificate_provider_ == nullptr @@ -647,20 +631,7 @@ absl::Status CdsLb::UpdateXdsCertificateProvider( identity_provider_instance_name, "\" not recognized.")); } } - if (identity_certificate_provider_ != new_identity_provider) { - if (identity_certificate_provider_ != nullptr && - identity_certificate_provider_->interested_parties() != nullptr) { - grpc_pollset_set_del_pollset_set( - interested_parties(), - identity_certificate_provider_->interested_parties()); - } - if (new_identity_provider != nullptr && - new_identity_provider->interested_parties() != nullptr) { - grpc_pollset_set_add_pollset_set( - interested_parties(), new_identity_provider->interested_parties()); - } - identity_certificate_provider_ = std::move(new_identity_provider); - } + identity_certificate_provider_ = std::move(new_identity_provider); xds_certificate_provider_->UpdateIdentityCertNameAndDistributor( cluster_name, identity_provider_cert_name, identity_certificate_provider_ == nullptr diff --git a/src/core/ext/xds/certificate_provider_store.h b/src/core/ext/xds/certificate_provider_store.h index 24b172ac32d78..aba287f97892b 100644 --- a/src/core/ext/xds/certificate_provider_store.h +++ b/src/core/ext/xds/certificate_provider_store.h @@ -36,7 +36,6 @@ #include "src/core/lib/gprpp/sync.h" #include "src/core/lib/gprpp/unique_type_name.h" #include "src/core/lib/gprpp/validation_errors.h" -#include "src/core/lib/iomgr/iomgr_fwd.h" #include "src/core/lib/json/json.h" #include "src/core/lib/json/json_args.h" #include "src/core/lib/json/json_object_loader.h" @@ -96,10 +95,6 @@ class CertificateProviderStore return certificate_provider_->distributor(); } - grpc_pollset_set* interested_parties() const override { - return certificate_provider_->interested_parties(); - } - int CompareImpl(const grpc_tls_certificate_provider* other) const override { // TODO(yashykt): This should probably delegate to the `Compare` method of // the wrapped certificate_provider_ object. diff --git a/src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h b/src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h index 22ccf7ebd74a8..d9f2527a33cfc 100644 --- a/src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h +++ b/src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h @@ -39,7 +39,6 @@ #include "src/core/lib/gprpp/sync.h" #include "src/core/lib/gprpp/thd.h" #include "src/core/lib/gprpp/unique_type_name.h" -#include "src/core/lib/iomgr/iomgr_fwd.h" #include "src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h" #include "src/core/lib/security/security_connector/ssl_utils.h" @@ -55,8 +54,6 @@ struct grpc_tls_certificate_provider : public grpc_core::RefCounted { public: - virtual grpc_pollset_set* interested_parties() const { return nullptr; } - virtual grpc_core::RefCountedPtr distributor() const = 0; From be4d2a6d8b3fa79839bbe5bc43788da046840d05 Mon Sep 17 00:00:00 2001 From: AJ Heller Date: Thu, 30 Nov 2023 13:16:10 -0800 Subject: [PATCH 026/127] [core] Ensure ChannelArgs::SetObject only allows conforming shared_ptr classes (#35008) ChannelArgs shared_ptr only supports types that extend `enable_shared_from_this`. `args.SetObject>(x)` with a non-comforming type X will now fail with something like: ``` ./src/core/lib/channel/channel_args.h:453:12: error: no matching member function for call to 'Set' return Set(ChannelArgNameTraits::ChannelArgName(), std::move(p)); ^~~ test/core/channel/channel_args_test.cc:352:32: note: in instantiation of function template specialization 'grpc_core::ChannelArgs::SetObject' requested here grpc_core::ChannelArgs b = a.SetObject(x); ^ .. ``` Closes #35008 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35008 from drfloob:channel-args-cant-set-unsupported-shared-ptr-type dc93f27ac728fbed233c48aa07fdb839c57ebf0a PiperOrigin-RevId: 586766674 --- src/core/lib/channel/channel_args.h | 26 ++++++++++++------- .../fuzzing_event_engine.h | 4 ++- .../resolver_fuzzer.cc | 3 ++- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h index 38bb070213cab..78848750294e9 100644 --- a/src/core/lib/channel/channel_args.h +++ b/src/core/lib/channel/channel_args.h @@ -125,6 +125,16 @@ struct ChannelArgTypeTraits< }; }; +// Define a check for shared_ptr supported types, which must extend +// enable_shared_from_this. +template +struct SupportedSharedPtrType + : std::integral_constant< + bool, std::is_base_of, T>::value> {}; +template <> +struct SupportedSharedPtrType + : std::true_type {}; + // Specialization for shared_ptr // Incurs an allocation because shared_ptr.release is not a thing. template @@ -174,18 +184,12 @@ struct ChannelArgTypeTraits -struct WrapInSharedPtr - : std::integral_constant< - bool, std::is_base_of, T>::value> {}; -template <> -struct WrapInSharedPtr - : std::true_type {}; template struct GetObjectImpl; // std::shared_ptr implementation template -struct GetObjectImpl::value, void>> { +struct GetObjectImpl< + T, absl::enable_if_t::value, void>> { using Result = T*; using ReffedResult = std::shared_ptr; using StoredType = std::shared_ptr*; @@ -205,7 +209,8 @@ struct GetObjectImpl::value, void>> { }; // RefCountedPtr template -struct GetObjectImpl::value, void>> { +struct GetObjectImpl< + T, absl::enable_if_t::value, void>> { using Result = T*; using ReffedResult = RefCountedPtr; using StoredType = Result; @@ -391,6 +396,9 @@ class ChannelArgs { decltype(ChannelArgTypeTraits>::VTable())>::value, ChannelArgs> Set(absl::string_view name, std::shared_ptr value) const { + static_assert(SupportedSharedPtrType::value, + "Type T must extend std::enable_shared_from_this to be added " + "into ChannelArgs as a shared_ptr"); auto* store_value = new std::shared_ptr(value); return Set( name, diff --git a/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h b/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h index 5f83f44c9ea8b..78e36a65d2a9e 100644 --- a/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h +++ b/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h @@ -48,7 +48,9 @@ namespace experimental { // EventEngine implementation to be used by fuzzers. // It's only allowed to have one FuzzingEventEngine instantiated at a time. -class FuzzingEventEngine : public EventEngine { +class FuzzingEventEngine + : public EventEngine, + public std::enable_shared_from_this { public: struct Options { Duration max_delay_run_after = std::chrono::seconds(30); diff --git a/test/core/ext/filters/event_engine_client_channel_resolver/resolver_fuzzer.cc b/test/core/ext/filters/event_engine_client_channel_resolver/resolver_fuzzer.cc index 483ad6b0e4ac7..97ed6eaa71c65 100644 --- a/test/core/ext/filters/event_engine_client_channel_resolver/resolver_fuzzer.cc +++ b/test/core/ext/filters/event_engine_client_channel_resolver/resolver_fuzzer.cc @@ -71,7 +71,8 @@ absl::Status ErrorToAbslStatus( } class FuzzingResolverEventEngine - : public grpc_event_engine::experimental::AbortingEventEngine { + : public grpc_event_engine::experimental::AbortingEventEngine, + public std::enable_shared_from_this { public: explicit FuzzingResolverEventEngine( const event_engine_client_channel_resolver::Msg& msg, From c10ae5fc636778064dd9bd6f259c1511c7a38e41 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Thu, 30 Nov 2023 14:01:46 -0800 Subject: [PATCH 027/127] [autofix] fix copybara username (#35184) --- .github/workflows/pr-auto-fix.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-auto-fix.yaml b/.github/workflows/pr-auto-fix.yaml index 4b930563dca4a..654f943c1d432 100644 --- a/.github/workflows/pr-auto-fix.yaml +++ b/.github/workflows/pr-auto-fix.yaml @@ -48,7 +48,7 @@ jobs: with: script: | // If you'd like not to run this code on your commits, add your github user id here: - NO_AUTOFIX_USERS = ["copybara-service"] + NO_AUTOFIX_USERS = ["copybara-service[bot]"] const { owner, repo } = context.repo console.log("Actor: " + context.actor); if (NO_AUTOFIX_USERS.includes(context.actor)) { From ff4058a738d6ea78ebf9bb4f540ca655bf1bcc90 Mon Sep 17 00:00:00 2001 From: Alisha Nanda Date: Thu, 30 Nov 2023 15:01:09 -0800 Subject: [PATCH 028/127] Decrease number of inlined elements in slice_buffer from 8 to 7. PiperOrigin-RevId: 586797742 --- include/grpc/impl/slice_type.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/grpc/impl/slice_type.h b/include/grpc/impl/slice_type.h index 5d618740553cc..7d9dfb78123b0 100644 --- a/include/grpc/impl/slice_type.h +++ b/include/grpc/impl/slice_type.h @@ -74,7 +74,7 @@ struct grpc_slice { } data; }; -#define GRPC_SLICE_BUFFER_INLINE_ELEMENTS 8 +#define GRPC_SLICE_BUFFER_INLINE_ELEMENTS 7 /** Represents an expandable array of slices, to be interpreted as a single item. */ From e348d65bc7ce47986c725009b8db47b1e606d878 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 30 Nov 2023 15:24:08 -0800 Subject: [PATCH 029/127] [promises] Add some niceties for StatusFlag, ValueOrFailure PiperOrigin-RevId: 586804010 --- src/core/lib/promise/status_flag.h | 38 ++++++++++++++++++++++++--- test/core/promise/status_flag_test.cc | 2 ++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/core/lib/promise/status_flag.h b/src/core/lib/promise/status_flag.h index 063cb76a079e6..54019d387408a 100644 --- a/src/core/lib/promise/status_flag.h +++ b/src/core/lib/promise/status_flag.h @@ -25,11 +25,31 @@ namespace grpc_core { +struct Failure {}; +struct Success {}; + +inline bool IsStatusOk(Failure) { return false; } +inline bool IsStatusOk(Success) { return true; } + +template <> +struct StatusCastImpl { + static absl::Status Cast(Success) { return absl::OkStatus(); } +}; + +template <> +struct StatusCastImpl { + static absl::Status Cast(Success) { return absl::OkStatus(); } +}; + // A boolean representing whether an operation succeeded (true) or failed // (false). class StatusFlag { public: explicit StatusFlag(bool value) : value_(value) {} + // NOLINTNEXTLINE(google-explicit-constructor) + StatusFlag(Failure) : value_(false) {} + // NOLINTNEXTLINE(google-explicit-constructor) + StatusFlag(Success) : value_(true) {} bool ok() const { return value_; } @@ -46,14 +66,21 @@ struct StatusCastImpl { } }; -struct Failure {}; +template <> +struct StatusCastImpl { + static absl::Status Cast(StatusFlag flag) { + return flag.ok() ? absl::OkStatus() : absl::CancelledError(); + } +}; // A value if an operation was successful, or a failure flag if not. template class ValueOrFailure { public: - explicit ValueOrFailure(T value) : value_(std::move(value)) {} - explicit ValueOrFailure(Failure) {} + // NOLINTNEXTLINE(google-explicit-constructor) + ValueOrFailure(T value) : value_(std::move(value)) {} + // NOLINTNEXTLINE(google-explicit-constructor) + ValueOrFailure(Failure) {} static ValueOrFailure FromOptional(absl::optional value) { return ValueOrFailure{std::move(value)}; @@ -75,6 +102,11 @@ inline bool IsStatusOk(const ValueOrFailure& value) { return value.ok(); } +template +inline T TakeValue(ValueOrFailure&& value) { + return std::move(value.value()); +} + template struct StatusCastImpl> { static absl::Status Cast(const ValueOrFailure flag) { diff --git a/test/core/promise/status_flag_test.cc b/test/core/promise/status_flag_test.cc index 799a08917e722..dcde3641f049c 100644 --- a/test/core/promise/status_flag_test.cc +++ b/test/core/promise/status_flag_test.cc @@ -33,6 +33,8 @@ TEST(StatusFlagTest, Basics) { EXPECT_EQ(ValueOrFailure(42).value(), 42); EXPECT_EQ(StatusCast>(ValueOrFailure(42)).value(), 42); + EXPECT_TRUE(IsStatusOk(Success{})); + EXPECT_FALSE(IsStatusOk(Failure{})); } } // namespace grpc_core From 6e18346c96e145a94493a2a2fceb4f1c46d04b18 Mon Sep 17 00:00:00 2001 From: Yash Tibrewal Date: Thu, 30 Nov 2023 16:08:13 -0800 Subject: [PATCH 030/127] [otel] Update OTel to head (#35151) This is mainly to get the fix made in https://github.com/open-telemetry/opentelemetry-cpp/pull/2213 When opentelemetry-cpp makes a stable release with this fix, we'll switch to that. Closes #35151 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35151 from yashykt:UpdateOTel 1041fbc0bce2d7091607eb671fb8bad91af79fcc PiperOrigin-RevId: 586815878 --- bazel/grpc_deps.bzl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bazel/grpc_deps.bzl b/bazel/grpc_deps.bzl index a982d8079b5a5..1f64e9fe5b43e 100644 --- a/bazel/grpc_deps.bzl +++ b/bazel/grpc_deps.bzl @@ -512,11 +512,11 @@ def grpc_deps(): if "io_opentelemetry_cpp" not in native.existing_rules(): http_archive( name = "io_opentelemetry_cpp", - sha256 = "f30cd88bf898a5726d245eba882b8e81012021eb00df34109f4dfb203f005cea", - strip_prefix = "opentelemetry-cpp-1.11.0", + sha256 = "149f076cc7a79bbd3a3c34fb3ab61d3a3e8dcfe2b9596f79153e17123c32f897", + strip_prefix = "opentelemetry-cpp-064fef0d871c57ffac6739d3311659a5770a9db4", urls = [ - "https://storage.googleapis.com/grpc-bazel-mirror/github.com/open-telemetry/opentelemetry-cpp/archive/refs/tags/v1.11.0.tar.gz", - "https://github.com/open-telemetry/opentelemetry-cpp/archive/refs/tags/v1.11.0.tar.gz", + "https://storage.googleapis.com/grpc-bazel-mirror/github.com/open-telemetry/opentelemetry-cpp/archive/064fef0d871c57ffac6739d3311659a5770a9db4.tar.gz", + "https://github.com/open-telemetry/opentelemetry-cpp/archive/064fef0d871c57ffac6739d3311659a5770a9db4.tar.gz", ], ) From e481f6acc5c1bf560eea5095dbbf36e7fae77fd5 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 1 Dec 2023 09:05:25 -0800 Subject: [PATCH 031/127] [promises] Generate a better error message for a common mistake (#35191) Closes #35191 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35191 from ctiller:cg-promise-like-fix 0683ffe16943bee355dd97735b972a7315aabb93 PiperOrigin-RevId: 587026178 --- src/core/lib/promise/detail/promise_like.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/lib/promise/detail/promise_like.h b/src/core/lib/promise/detail/promise_like.h index 486653856e35e..4bec366164294 100644 --- a/src/core/lib/promise/detail/promise_like.h +++ b/src/core/lib/promise/detail/promise_like.h @@ -68,6 +68,10 @@ class PromiseLike { private: GPR_NO_UNIQUE_ADDRESS F f_; + static_assert(!std::is_void::type>::value, + "PromiseLike cannot be used with a function that returns void " + "- return Empty{} instead"); + public: // NOLINTNEXTLINE - internal detail that drastically simplifies calling code. PromiseLike(F&& f) : f_(std::forward(f)) {} From 49f7ee96d195f44e21d5b57106f2564b6e101b15 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 1 Dec 2023 11:06:38 -0800 Subject: [PATCH 032/127] [promises] Convert http-client filter to v3 filter API (#35189) Also start building a temporary wrapping layer so that the new style filters can execute as promise filters directly. Closes #35189 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35189 from ctiller:cg-http-cli dbd73e8aca651b3c597d78e47b4d52e173e7b02b PiperOrigin-RevId: 587060881 --- .../filters/http/client/http_client_filter.cc | 54 ++-- .../filters/http/client/http_client_filter.h | 14 +- src/core/lib/channel/promise_based_filter.h | 285 ++++++++++++++++++ 3 files changed, 316 insertions(+), 37 deletions(-) diff --git a/src/core/ext/filters/http/client/http_client_filter.cc b/src/core/ext/filters/http/client/http_client_filter.cc index 8b547bac6ee2b..07fcba6258171 100644 --- a/src/core/ext/filters/http/client/http_client_filter.cc +++ b/src/core/ext/filters/http/client/http_client_filter.cc @@ -51,6 +51,9 @@ namespace grpc_core { +const NoInterceptor HttpClientFilter::Call::OnServerToClientMessage; +const NoInterceptor HttpClientFilter::Call::OnClientToServerMessage; + const grpc_channel_filter HttpClientFilter::kFilter = MakePromiseBasedFilter("http-client"); @@ -105,40 +108,27 @@ Slice UserAgentFromArgs(const ChannelArgs& args, } } // namespace -ArenaPromise HttpClientFilter::MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) { - auto& md = call_args.client_initial_metadata; - if (test_only_use_put_requests_) { - md->Set(HttpMethodMetadata(), HttpMethodMetadata::kPut); +void HttpClientFilter::Call::OnClientInitialMetadata(ClientMetadata& md, + HttpClientFilter* filter) { + if (filter->test_only_use_put_requests_) { + md.Set(HttpMethodMetadata(), HttpMethodMetadata::kPut); } else { - md->Set(HttpMethodMetadata(), HttpMethodMetadata::kPost); + md.Set(HttpMethodMetadata(), HttpMethodMetadata::kPost); } - md->Set(HttpSchemeMetadata(), scheme_); - md->Set(TeMetadata(), TeMetadata::kTrailers); - md->Set(ContentTypeMetadata(), ContentTypeMetadata::kApplicationGrpc); - md->Set(UserAgentMetadata(), user_agent_.Ref()); - - auto* initial_metadata_err = - GetContext()->New>(); - - call_args.server_initial_metadata->InterceptAndMap( - [initial_metadata_err]( - ServerMetadataHandle md) -> absl::optional { - auto r = CheckServerMetadata(md.get()); - if (!r.ok()) { - initial_metadata_err->Set(ServerMetadataFromStatus(r)); - return absl::nullopt; - } - return std::move(md); - }); - - return Race(initial_metadata_err->Wait(), - Map(next_promise_factory(std::move(call_args)), - [](ServerMetadataHandle md) -> ServerMetadataHandle { - auto r = CheckServerMetadata(md.get()); - if (!r.ok()) return ServerMetadataFromStatus(r); - return md; - })); + md.Set(HttpSchemeMetadata(), filter->scheme_); + md.Set(TeMetadata(), TeMetadata::kTrailers); + md.Set(ContentTypeMetadata(), ContentTypeMetadata::kApplicationGrpc); + md.Set(UserAgentMetadata(), filter->user_agent_.Ref()); +} + +absl::Status HttpClientFilter::Call::OnServerInitialMetadata( + ServerMetadata& md) { + return CheckServerMetadata(&md); +} + +absl::Status HttpClientFilter::Call::OnServerTrailingMetadata( + ServerMetadata& md) { + return CheckServerMetadata(&md); } HttpClientFilter::HttpClientFilter(HttpSchemeMetadata::ValueType scheme, diff --git a/src/core/ext/filters/http/client/http_client_filter.h b/src/core/ext/filters/http/client/http_client_filter.h index 298daf03c6700..3146ea073852a 100644 --- a/src/core/ext/filters/http/client/http_client_filter.h +++ b/src/core/ext/filters/http/client/http_client_filter.h @@ -25,23 +25,27 @@ #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/channel_fwd.h" #include "src/core/lib/channel/promise_based_filter.h" -#include "src/core/lib/promise/arena_promise.h" #include "src/core/lib/slice/slice.h" #include "src/core/lib/transport/metadata_batch.h" #include "src/core/lib/transport/transport.h" namespace grpc_core { -class HttpClientFilter : public ChannelFilter { +class HttpClientFilter : public ImplementChannelFilter { public: static const grpc_channel_filter kFilter; static absl::StatusOr Create( const ChannelArgs& args, ChannelFilter::Args filter_args); - // Construct a promise for one call. - ArenaPromise MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) override; + class Call { + public: + void OnClientInitialMetadata(ClientMetadata& md, HttpClientFilter* filter); + absl::Status OnServerInitialMetadata(ServerMetadata& md); + absl::Status OnServerTrailingMetadata(ServerMetadata& md); + static const NoInterceptor OnClientToServerMessage; + static const NoInterceptor OnServerToClientMessage; + }; private: HttpClientFilter(HttpSchemeMetadata::ValueType scheme, Slice user_agent, diff --git a/src/core/lib/channel/promise_based_filter.h b/src/core/lib/channel/promise_based_filter.h index 19efe505db29a..25ee1230ef1ea 100644 --- a/src/core/lib/channel/promise_based_filter.h +++ b/src/core/lib/channel/promise_based_filter.h @@ -43,6 +43,7 @@ #include #include "src/core/lib/channel/call_finalization.h" +#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/channel_fwd.h" #include "src/core/lib/channel/channel_stack.h" #include "src/core/lib/channel/context.h" @@ -60,6 +61,7 @@ #include "src/core/lib/promise/context.h" #include "src/core/lib/promise/pipe.h" #include "src/core/lib/promise/poll.h" +#include "src/core/lib/promise/race.h" #include "src/core/lib/resource_quota/arena.h" #include "src/core/lib/slice/slice_buffer.h" #include "src/core/lib/surface/call.h" @@ -122,6 +124,289 @@ class ChannelFilter { grpc_event_engine::experimental::GetDefaultEventEngine(); }; +struct NoInterceptor {}; + +namespace promise_filter_detail { + +// Determine if a list of interceptors has any that need to asyncronously error +// the promise. If so, we need to allocate a latch for the generated promise for +// the original promise stack polyfill code that's generated. + +inline constexpr bool HasAsyncErrorInterceptor() { return false; } + +inline constexpr bool HasAsyncErrorInterceptor(const NoInterceptor*) { + return false; +} + +template +inline constexpr bool HasAsyncErrorInterceptor(absl::Status (T::*)(A...)) { + return true; +} + +template +inline constexpr bool HasAsyncErrorInterceptor(void (T::*)(A...)) { + return false; +} + +// For the list case we do two interceptors to avoid amiguities with the single +// argument forms above. +template +inline constexpr bool HasAsyncErrorInterceptor(I1 i1, I2 i2, + Interceptors... interceptors) { + return HasAsyncErrorInterceptor(i1) || HasAsyncErrorInterceptor(i2) || + HasAsyncErrorInterceptor(interceptors...); +} + +// Composite for a given channel type to determine if any of its interceptors +// fall into this category: later code should use this. +template +inline constexpr bool CallHasAsyncErrorInterceptor() { + return HasAsyncErrorInterceptor(&Derived::Call::OnClientToServerMessage, + &Derived::Call::OnServerInitialMetadata, + &Derived::Call::OnServerToClientMessage); +} + +// Determine if an interceptor needs to access the channel via one of its +// arguments. If so, we need to allocate a pointer to the channel for the +// generated polyfill promise for the original promise stack. + +inline constexpr bool HasChannelAccess() { return false; } + +inline constexpr bool HasChannelAccess(const NoInterceptor*) { return false; } + +template +inline constexpr bool HasChannelAccess(R (T::*)(A)) { + return false; +} + +template +inline constexpr bool HasChannelAccess(R (T::*)(A, C)) { + return true; +} + +// For the list case we do two interceptors to avoid amiguities with the single +// argument forms above. +template +inline constexpr bool HasChannelAccess(I1 i1, I2 i2, + Interceptors... interceptors) { + return HasChannelAccess(i1) || HasChannelAccess(i2) || + HasChannelAccess(interceptors...); +} + +// Composite for a given channel type to determine if any of its interceptors +// fall into this category: later code should use this. +template +inline constexpr bool CallHasChannelAccess() { + return HasChannelAccess(&Derived::Call::OnClientInitialMetadata, + &Derived::Call::OnClientToServerMessage, + &Derived::Call::OnServerInitialMetadata, + &Derived::Call::OnServerToClientMessage, + &Derived::Call::OnServerTrailingMetadata); +} + +// Given a boolean X export a type: +// either T if X is true +// or an empty type if it is false +template +struct TypeIfNeeded; + +template +struct TypeIfNeeded { + struct Type { + Type() = default; + template + explicit Type(Whatever) : Type() {} + }; +}; + +template +struct TypeIfNeeded { + using Type = T; +}; + +// For the original promise scheme polyfill: +// If a set of interceptors might fail asynchronously, wrap the main +// promise in a race with the cancellation latch. +// If not, just return the main promise. +template +struct RaceAsyncCompletion; + +template <> +struct RaceAsyncCompletion { + template + static Promise Run(Promise x, void*) { + return x; + } +}; + +template <> +struct RaceAsyncCompletion { + template + static Promise Run(Promise x, Latch* latch) { + return Race(latch->Wait(), std::move(x)); + } +}; + +// For the original promise scheme polyfill: data associated with once call. +template +struct FilterCallData { + explicit FilterCallData(Derived* channel) : channel(channel) {} + GPR_NO_UNIQUE_ADDRESS typename Derived::Call call; + GPR_NO_UNIQUE_ADDRESS + typename TypeIfNeeded, + CallHasAsyncErrorInterceptor()>::Type + error_latch; + GPR_NO_UNIQUE_ADDRESS + typename TypeIfNeeded()>::Type + channel; +}; + +template +auto MapResult(const NoInterceptor*, Promise x, void*) { + return x; +} + +template +auto MapResult(absl::Status (Derived::Call::*fn)(ServerMetadata&), Promise x, + FilterCallData* call_data) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnServerTrailingMetadata); + return Map(std::move(x), [call_data](ServerMetadataHandle md) { + auto status = call_data->call.OnServerTrailingMetadata(*md); + if (!status.ok()) return ServerMetadataFromStatus(status); + return md; + }); +} + +inline auto RunCall(const NoInterceptor*, CallArgs call_args, + NextPromiseFactory next_promise_factory, void*) { + return next_promise_factory(std::move(call_args)); +} + +template +inline auto RunCall(void (Derived::Call::*fn)(ClientMetadata& md), + CallArgs call_args, NextPromiseFactory next_promise_factory, + FilterCallData* call_data) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnClientInitialMetadata); + call_data->call.OnClientInitialMetadata(*call_args.client_initial_metadata); + return next_promise_factory(std::move(call_args)); +} + +template +inline auto RunCall(void (Derived::Call::*fn)(ClientMetadata& md, + Derived* channel), + CallArgs call_args, NextPromiseFactory next_promise_factory, + FilterCallData* call_data) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnClientInitialMetadata); + call_data->call.OnClientInitialMetadata(*call_args.client_initial_metadata, + call_data->channel); + return next_promise_factory(std::move(call_args)); +} + +inline void InterceptClientToServerMessage(const NoInterceptor*, void*, + CallArgs&) {} + +inline void InterceptServerInitialMetadata(const NoInterceptor*, void*, + CallArgs&) {} + +template +inline void InterceptServerInitialMetadata( + absl::Status (Derived::Call::*fn)(ServerMetadata&), + FilterCallData* call_data, CallArgs& call_args) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnServerInitialMetadata); + call_args.server_initial_metadata->InterceptAndMap( + [call_data]( + ServerMetadataHandle md) -> absl::optional { + auto status = call_data->call.OnServerInitialMetadata(*md); + if (!status.ok() && !call_data->error_latch.is_set()) { + call_data->error_latch.Set(ServerMetadataFromStatus(status)); + return absl::nullopt; + } + return std::move(md); + }); +} + +inline void InterceptServerToClientMessage(const NoInterceptor*, void*, + CallArgs&) {} + +template +absl::enable_if_t>::value, + FilterCallData*> +MakeFilterCall(Derived*) { + static FilterCallData call{nullptr}; + return &call; +} + +template +absl::enable_if_t>::value, + FilterCallData*> +MakeFilterCall(Derived* derived) { + return GetContext()->ManagedNew>(derived); +} + +} // namespace promise_filter_detail + +// Base class for promise-based channel filters. +// Eventually this machinery will move elsewhere (the interception logic will +// move directly into the channel stack, and so filters will just directly +// derive from `ChannelFilter`) +// +// Implements new-style call filters, and polyfills them into the previous +// scheme. +// +// Call filters: +// Derived types should declare a class `Call` with the following members: +// - OnClientInitialMetadata - $VALUE_TYPE = ClientMetadata +// - OnServerInitialMetadata - $VALUE_TYPE = ServerMetadata +// - OnServerToClientMessage - $VALUE_TYPE = Message +// - OnClientToServerMessage - $VALUE_TYPE = Message +// - OnServerTrailingMetadata - $VALUE_TYPE = ServerMetadata +// These members define an interception point for a particular event in +// the call lifecycle. +// The type of these members matters, and is selectable by the class +// author. For $INTERCEPTOR_NAME in the above list: +// - static const NoInterceptor $INTERCEPTOR_NAME: +// defines that this filter does not intercept this event. +// there is zero runtime cost added to handling that event by this filter. +// - void $INTERCEPTOR_NAME($VALUE_TYPE&): +// the filter intercepts this event, and can modify the value. +// it never fails. +// - absl::Status $INTERCEPTOR_NAME($VALUE_TYPE&): +// the filter intercepts this event, and can modify the value. +// it can fail, in which case the call will be aborted. +// - void $INTERCEPTOR_NAME($VALUE_TYPE&, Derived*): +// the filter intercepts this event, and can modify the value. +// it can access the channel via the second argument. +// it never fails. +// - absl::Status $INTERCEPTOR_NAME($VALUE_TYPE&, Derived*): +// the filter intercepts this event, and can modify the value. +// it can access the channel via the second argument. +// it can fail, in which case the call will be aborted. +template +class ImplementChannelFilter : public ChannelFilter { + public: + ArenaPromise MakeCallPromise( + CallArgs call_args, NextPromiseFactory next_promise_factory) final { + auto* call = promise_filter_detail::MakeFilterCall( + static_cast(this)); + promise_filter_detail::InterceptClientToServerMessage( + &Derived::Call::OnClientToServerMessage, call, call_args); + promise_filter_detail::InterceptServerInitialMetadata( + &Derived::Call::OnServerInitialMetadata, call, call_args); + promise_filter_detail::InterceptServerToClientMessage( + &Derived::Call::OnServerToClientMessage, call, call_args); + return promise_filter_detail::MapResult( + &Derived::Call::OnServerTrailingMetadata, + promise_filter_detail::RaceAsyncCompletion< + promise_filter_detail::CallHasAsyncErrorInterceptor()>:: + Run(promise_filter_detail::RunCall( + &Derived::Call::OnClientInitialMetadata, + std::move(call_args), std::move(next_promise_factory), + call), + &call->error_latch), + call); + } +}; + // Designator for whether a filter is client side or server side. // Please don't use this outside calls to MakePromiseBasedFilter - it's // intended to be deleted once the promise conversion is complete. From 84678829af643474e5a8cd468066be3ef1559fae Mon Sep 17 00:00:00 2001 From: Vignesh Babu Date: Fri, 1 Dec 2023 11:41:36 -0800 Subject: [PATCH 033/127] [EventEngine] Add public methods to allow EventEngine Endpoints to support optional Extensions. PiperOrigin-RevId: 587071965 --- CMakeLists.txt | 35 +++++++ build_autogenerated.yaml | 13 +++ include/grpc/event_engine/event_engine.h | 39 ++++++++ src/core/BUILD | 12 +++ src/core/lib/event_engine/query_extensions.h | 70 ++++++++++++++ .../lib/iomgr/event_engine_shims/endpoint.cc | 13 +++ .../lib/iomgr/event_engine_shims/endpoint.h | 5 + test/core/event_engine/BUILD | 13 +++ .../event_engine/query_extensions_test.cc | 95 +++++++++++++++++++ tools/run_tests/generated/tests.json | 24 +++++ 10 files changed, 319 insertions(+) create mode 100644 src/core/lib/event_engine/query_extensions.h create mode 100644 test/core/event_engine/query_extensions_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c8979a56ec45..9d2a53f4ed695 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1229,6 +1229,7 @@ if(gRPC_BUILD_TESTS) add_dependencies(buildtests_cxx proxy_auth_test) add_dependencies(buildtests_cxx qps_json_driver) add_dependencies(buildtests_cxx qps_worker) + add_dependencies(buildtests_cxx query_extensions_test) add_dependencies(buildtests_cxx race_test) add_dependencies(buildtests_cxx random_early_detection_test) add_dependencies(buildtests_cxx raw_end2end_test) @@ -18938,6 +18939,40 @@ target_link_libraries(qps_worker ) +endif() +if(gRPC_BUILD_TESTS) + +add_executable(query_extensions_test + test/core/event_engine/query_extensions_test.cc +) +target_compile_features(query_extensions_test PUBLIC cxx_std_14) +target_include_directories(query_extensions_test + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + ${_gRPC_RE2_INCLUDE_DIR} + ${_gRPC_SSL_INCLUDE_DIR} + ${_gRPC_UPB_GENERATED_DIR} + ${_gRPC_UPB_GRPC_GENERATED_DIR} + ${_gRPC_UPB_INCLUDE_DIR} + ${_gRPC_XXHASH_INCLUDE_DIR} + ${_gRPC_ZLIB_INCLUDE_DIR} + third_party/googletest/googletest/include + third_party/googletest/googletest + third_party/googletest/googlemock/include + third_party/googletest/googlemock + ${_gRPC_PROTO_GENS_DIR} +) + +target_link_libraries(query_extensions_test + ${_gRPC_ALLTARGETS_LIBRARIES} + gtest + absl::statusor + gpr +) + + endif() if(gRPC_BUILD_TESTS) diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index bd2a9aa0bbd76..7eba4bf9d53ba 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -13309,6 +13309,19 @@ targets: deps: - grpc++_test_config - grpc++_test_util +- name: query_extensions_test + gtest: true + build: test + language: c++ + headers: + - src/core/lib/event_engine/query_extensions.h + src: + - test/core/event_engine/query_extensions_test.cc + deps: + - gtest + - absl/status:statusor + - gpr + uses_polling: false - name: race_test gtest: true build: test diff --git a/include/grpc/event_engine/event_engine.h b/include/grpc/event_engine/event_engine.h index 4beca657625a3..20cbc64f52fde 100644 --- a/include/grpc/event_engine/event_engine.h +++ b/include/grpc/event_engine/event_engine.h @@ -255,6 +255,45 @@ class EventEngine : public std::enable_shared_from_this { /// values are expected to remain valid for the life of the Endpoint. virtual const ResolvedAddress& GetPeerAddress() const = 0; virtual const ResolvedAddress& GetLocalAddress() const = 0; + + /// A method which allows users to query whether an Endpoint implementation + /// supports a specified extension. The name of the extension is provided + /// as an input. + /// + /// An extension could be any type with a unique string id. Each extension + /// may support additional capabilities and if the Endpoint implementation + /// supports the queried extension, it should return a valid pointer to the + /// extension type. + /// + /// E.g., use case of an EventEngine::Endpoint supporting a custom + /// extension. + /// + /// class CustomEndpointExtension { + /// public: + /// static constexpr std::string name = "my.namespace.extension_name"; + /// void Process() { ... } + /// } + /// + /// + /// class CustomEndpoint : + /// public EventEngine::Endpoint, CustomEndpointExtension { + /// public: + /// void* QueryExtension(absl::string_view id) override { + /// if (id == CustomEndpointExtension::name) { + /// return static_cast(this); + /// } + /// return nullptr; + /// } + /// ... + /// } + /// + /// auto ext_ = + /// static_cast( + /// endpoint->QueryExtension(CustomrEndpointExtension::name)); + /// if (ext_ != nullptr) { ext_->Process(); } + /// + /// + virtual void* QueryExtension(absl::string_view /*id*/) { return nullptr; } }; /// Called when a new connection is established. diff --git a/src/core/BUILD b/src/core/BUILD index 351f101b81968..e6a4457ac0fb2 100644 --- a/src/core/BUILD +++ b/src/core/BUILD @@ -1540,6 +1540,18 @@ grpc_cc_library( ], ) +grpc_cc_library( + name = "event_engine_query_extensions", + hdrs = [ + "lib/event_engine/query_extensions.h", + ], + external_deps = ["absl/strings"], + deps = [ + "//:event_engine_base_hdrs", + "//:gpr_platform", + ], +) + grpc_cc_library( name = "event_engine_work_queue", hdrs = [ diff --git a/src/core/lib/event_engine/query_extensions.h b/src/core/lib/event_engine/query_extensions.h new file mode 100644 index 0000000000000..2ef15ccfdab6f --- /dev/null +++ b/src/core/lib/event_engine/query_extensions.h @@ -0,0 +1,70 @@ +// Copyright 2023 gRPC Authors +// +// Licensed 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 GRPC_SRC_CORE_LIB_EVENT_ENGINE_QUERY_EXTENSIONS_H +#define GRPC_SRC_CORE_LIB_EVENT_ENGINE_QUERY_EXTENSIONS_H + +#include + +#include "absl/strings/string_view.h" + +#include + +namespace grpc_event_engine { +namespace experimental { + +namespace endpoint_detail { + +template +struct QueryExtensionRecursion; + +template +struct QueryExtensionRecursion { + static void* Query(absl::string_view id, Querying* p) { + if (id == E::EndpointExtensionName()) return static_cast(p); + return QueryExtensionRecursion::Query(id, p); + } +}; + +template +struct QueryExtensionRecursion { + static void* Query(absl::string_view, Querying*) { return nullptr; } +}; + +} // namespace endpoint_detail + +// A helper class to derive from some set of base classes and export +// QueryExtension for them all. +// Endpoint implementations which need to support different extensions just need +// to derive from ExtendedEndpoint class. +template +class ExtendedEndpoint : public EventEngine::Endpoint, public Exports... { + public: + void* QueryExtension(absl::string_view id) override { + return endpoint_detail::QueryExtensionRecursion::Query(id, + this); + } +}; + +/// A helper method which returns a valid pointer if the extension is supported +/// by the endpoint. +template +T* QueryExtension(EventEngine::Endpoint* endpoint) { + return static_cast(endpoint->QueryExtension(T::EndpointExtensionName())); +} + +} // namespace experimental +} // namespace grpc_event_engine + +#endif // GRPC_SRC_CORE_LIB_EVENT_ENGINE_QUERY_EXTENSIONS_H diff --git a/src/core/lib/iomgr/event_engine_shims/endpoint.cc b/src/core/lib/iomgr/event_engine_shims/endpoint.cc index 341fe1e577655..b1e8fdf890490 100644 --- a/src/core/lib/iomgr/event_engine_shims/endpoint.cc +++ b/src/core/lib/iomgr/event_engine_shims/endpoint.cc @@ -69,6 +69,8 @@ class EventEngineEndpointWrapper { explicit EventEngineEndpointWrapper( std::unique_ptr endpoint); + EventEngine::Endpoint* endpoint() { return endpoint_.get(); } + int Fd() { grpc_core::MutexLock lock(&mu_); return fd_; @@ -428,6 +430,17 @@ bool grpc_is_event_engine_endpoint(grpc_endpoint* ep) { return ep->vtable == &grpc_event_engine_endpoint_vtable; } +EventEngine::Endpoint* grpc_get_wrapped_event_engine_endpoint( + grpc_endpoint* ep) { + if (!grpc_is_event_engine_endpoint(ep)) { + return nullptr; + } + auto* eeep = + reinterpret_cast( + ep); + return eeep->wrapper->endpoint(); +} + void grpc_event_engine_endpoint_destroy_and_release_fd( grpc_endpoint* ep, int* fd, grpc_closure* on_release_fd) { auto* eeep = diff --git a/src/core/lib/iomgr/event_engine_shims/endpoint.h b/src/core/lib/iomgr/event_engine_shims/endpoint.h index bc018f1e4d71d..efd57c6ea6d2b 100644 --- a/src/core/lib/iomgr/event_engine_shims/endpoint.h +++ b/src/core/lib/iomgr/event_engine_shims/endpoint.h @@ -31,6 +31,11 @@ grpc_endpoint* grpc_event_engine_endpoint_create( /// Returns true if the passed endpoint is an event engine shim endpoint. bool grpc_is_event_engine_endpoint(grpc_endpoint* ep); +/// Returns the wrapped event engine endpoint if the given grpc_endpoint is an +/// event engine shim endpoint. Otherwise it returns nullptr. +EventEngine::Endpoint* grpc_get_wrapped_event_engine_endpoint( + grpc_endpoint* ep); + /// Destroys the passed in event engine shim endpoint and schedules the /// asynchronous execution of the on_release_fd callback. The int pointer fd is /// set to the underlying endpoint's file descriptor. diff --git a/test/core/event_engine/BUILD b/test/core/event_engine/BUILD index 13543244c14f4..1cdf7d24cd398 100644 --- a/test/core/event_engine/BUILD +++ b/test/core/event_engine/BUILD @@ -232,3 +232,16 @@ grpc_cc_library( "//src/core:time", ], ) + +grpc_cc_test( + name = "query_extensions_test", + srcs = ["query_extensions_test.cc"], + external_deps = ["gtest"], + language = "C++", + uses_event_engine = False, + uses_polling = False, + deps = [ + "//:gpr_platform", + "//src/core:event_engine_query_extensions", + ], +) diff --git a/test/core/event_engine/query_extensions_test.cc b/test/core/event_engine/query_extensions_test.cc new file mode 100644 index 0000000000000..712a496f38ce2 --- /dev/null +++ b/test/core/event_engine/query_extensions_test.cc @@ -0,0 +1,95 @@ +// Copyright 2023 gRPC authors. +// +// Licensed 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. +#include + +#include "src/core/lib/event_engine/query_extensions.h" + +#include + +#include "absl/functional/any_invocable.h" +#include "absl/status/status.h" +#include "gtest/gtest.h" + +#include +#include + +#include "src/core/lib/gprpp/crash.h" + +namespace grpc_event_engine { +namespace experimental { +namespace { + +template +class TestExtension { + public: + TestExtension() = default; + ~TestExtension() = default; + + static std::string EndpointExtensionName() { + return "grpc.test.test_extension" + std::to_string(i); + } + + int GetValue() const { return val_; } + + private: + int val_ = i; +}; + +class ExtendedTestEndpoint + : public ExtendedEndpoint, TestExtension<1>, + TestExtension<2>> { + public: + ExtendedTestEndpoint() = default; + ~ExtendedTestEndpoint() override = default; + bool Read(absl::AnyInvocable /*on_read*/, + SliceBuffer* /*buffer*/, const ReadArgs* /*args*/) override { + grpc_core::Crash("Not implemented"); + }; + bool Write(absl::AnyInvocable /*on_writable*/, + SliceBuffer* /*data*/, const WriteArgs* /*args*/) override { + grpc_core::Crash("Not implemented"); + } + /// Returns an address in the format described in DNSResolver. The returned + /// values are expected to remain valid for the life of the Endpoint. + const EventEngine::ResolvedAddress& GetPeerAddress() const override { + grpc_core::Crash("Not implemented"); + } + const EventEngine::ResolvedAddress& GetLocalAddress() const override { + grpc_core::Crash("Not implemented"); + }; +}; + +TEST(QueryExtensionsTest, EndpointSupportsMultipleExtensions) { + ExtendedTestEndpoint endpoint; + TestExtension<0>* extension_0 = QueryExtension>(&endpoint); + TestExtension<1>* extension_1 = QueryExtension>(&endpoint); + TestExtension<2>* extension_2 = QueryExtension>(&endpoint); + + EXPECT_NE(extension_0, nullptr); + EXPECT_NE(extension_1, nullptr); + EXPECT_NE(extension_2, nullptr); + + EXPECT_EQ(extension_0->GetValue(), 0); + EXPECT_EQ(extension_1->GetValue(), 1); + EXPECT_EQ(extension_2->GetValue(), 2); +} +} // namespace + +} // namespace experimental +} // namespace grpc_event_engine + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index 35bdddc0eb0b4..d58a72accec6f 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -7189,6 +7189,30 @@ ], "uses_polling": true }, + { + "args": [], + "benchmark": false, + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": true, + "language": "c++", + "name": "query_extensions_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "uses_polling": false + }, { "args": [], "benchmark": false, From 1d4ecf66298234578e5a9781df42b72866db7924 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 1 Dec 2023 12:13:37 -0800 Subject: [PATCH 034/127] [RefCounted] allow RefCounted<> to work for const types (#35188) Closes #35188 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35188 from markdroth:ref_counted_const e2dc753b6b234c74e8374e860f2946c840d3b45c PiperOrigin-RevId: 587081377 --- src/core/lib/gprpp/ref_counted.h | 47 ++++++++++++++++++++++------- test/core/gprpp/ref_counted_test.cc | 11 +++++++ 2 files changed, 47 insertions(+), 11 deletions(-) diff --git a/src/core/lib/gprpp/ref_counted.h b/src/core/lib/gprpp/ref_counted.h index cdf692c5ce7df..5eaf5cda0f1fb 100644 --- a/src/core/lib/gprpp/ref_counted.h +++ b/src/core/lib/gprpp/ref_counted.h @@ -219,7 +219,7 @@ class NonPolymorphicRefCount { // Default behavior: Delete the object. struct UnrefDelete { template - void operator()(T* p) { + void operator()(T* p) const { delete p; } }; @@ -231,7 +231,7 @@ struct UnrefDelete { // later by identifying entries for which RefIfNonZero() returns null. struct UnrefNoDelete { template - void operator()(T* /*p*/) {} + void operator()(T* /*p*/) const {} }; // Call the object's dtor but do not delete it. This is useful for cases @@ -239,7 +239,7 @@ struct UnrefNoDelete { // arena). struct UnrefCallDtor { template - void operator()(T* p) { + void operator()(T* p) const { p->~T(); } }; @@ -279,32 +279,44 @@ class RefCounted : public Impl { // Note: Depending on the Impl used, this dtor can be implicitly virtual. ~RefCounted() = default; + // Ref() for mutable types. GRPC_MUST_USE_RESULT RefCountedPtr Ref() { IncrementRefCount(); return RefCountedPtr(static_cast(this)); } - GRPC_MUST_USE_RESULT RefCountedPtr Ref(const DebugLocation& location, const char* reason) { IncrementRefCount(location, reason); return RefCountedPtr(static_cast(this)); } + // Ref() for const types. + GRPC_MUST_USE_RESULT RefCountedPtr Ref() const { + IncrementRefCount(); + return RefCountedPtr(static_cast(this)); + } + GRPC_MUST_USE_RESULT RefCountedPtr Ref( + const DebugLocation& location, const char* reason) const { + IncrementRefCount(location, reason); + return RefCountedPtr(static_cast(this)); + } + // TODO(roth): Once all of our code is converted to C++ and can use // RefCountedPtr<> instead of manual ref-counting, make this method // private, since it will only be used by RefCountedPtr<>, which is a // friend of this class. - void Unref() { + void Unref() const { if (GPR_UNLIKELY(refs_.Unref())) { - unref_behavior_(static_cast(this)); + unref_behavior_(static_cast(this)); } } - void Unref(const DebugLocation& location, const char* reason) { + void Unref(const DebugLocation& location, const char* reason) const { if (GPR_UNLIKELY(refs_.Unref(location, reason))) { - unref_behavior_(static_cast(this)); + unref_behavior_(static_cast(this)); } } + // RefIfNonZero() for mutable types. GRPC_MUST_USE_RESULT RefCountedPtr RefIfNonZero() { return RefCountedPtr(refs_.RefIfNonZero() ? static_cast(this) : nullptr); @@ -316,6 +328,18 @@ class RefCounted : public Impl { : nullptr); } + // RefIfNonZero() for const types. + GRPC_MUST_USE_RESULT RefCountedPtr RefIfNonZero() const { + return RefCountedPtr( + refs_.RefIfNonZero() ? static_cast(this) : nullptr); + } + GRPC_MUST_USE_RESULT RefCountedPtr RefIfNonZero( + const DebugLocation& location, const char* reason) const { + return RefCountedPtr(refs_.RefIfNonZero(location, reason) + ? static_cast(this) + : nullptr); + } + // Not copyable nor movable. RefCounted(const RefCounted&) = delete; RefCounted& operator=(const RefCounted&) = delete; @@ -336,12 +360,13 @@ class RefCounted : public Impl { template friend class RefCountedPtr; - void IncrementRefCount() { refs_.Ref(); } - void IncrementRefCount(const DebugLocation& location, const char* reason) { + void IncrementRefCount() const { refs_.Ref(); } + void IncrementRefCount(const DebugLocation& location, + const char* reason) const { refs_.Ref(location, reason); } - RefCount refs_; + mutable RefCount refs_; GPR_NO_UNIQUE_ADDRESS UnrefBehavior unref_behavior_; }; diff --git a/test/core/gprpp/ref_counted_test.cc b/test/core/gprpp/ref_counted_test.cc index 4d8761ecb1db0..7c28cddc6f645 100644 --- a/test/core/gprpp/ref_counted_test.cc +++ b/test/core/gprpp/ref_counted_test.cc @@ -53,6 +53,17 @@ TEST(RefCounted, ExtraRef) { foo->Unref(); } +TEST(RefCounted, Const) { + const Foo* foo = new Foo(); + RefCountedPtr foop = foo->Ref(); + foop.release(); + foop = foo->RefIfNonZero(); + foop.release(); + foo->Unref(); + foo->Unref(); + foo->Unref(); +} + class Value : public RefCounted { public: Value(int value, std::set>* registry) : value_(value) { From 39493f93c06e0adb46dea88a095f4115fb79d0c1 Mon Sep 17 00:00:00 2001 From: Esun Kim Date: Fri, 1 Dec 2023 16:23:11 -0800 Subject: [PATCH 035/127] Making windows/dll test no-op temporarily. This will be reenabled once DLL work is done. PiperOrigin-RevId: 587155376 --- test/distrib/cpp/run_distrib_test_cmake_for_dll.bat | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/distrib/cpp/run_distrib_test_cmake_for_dll.bat b/test/distrib/cpp/run_distrib_test_cmake_for_dll.bat index 2adfaf141419f..887c20dcd74a9 100644 --- a/test/distrib/cpp/run_distrib_test_cmake_for_dll.bat +++ b/test/distrib/cpp/run_distrib_test_cmake_for_dll.bat @@ -78,6 +78,11 @@ popd @rem folders, like the following command trying to imitate. git submodule foreach bash -c "cd $toplevel; rm -rf $name" +@rem TODO(dawidcha): Remove this once this DLL test can pass { +echo Skipped! +exit /b 0 +@rem TODO(dawidcha): Remove this once this DLL test can pass } + @rem Install gRPC @rem NOTE(jtattermusch): The -DProtobuf_USE_STATIC_LIBS=ON is necessary on cmake3.16+ @rem since by default "find_package(Protobuf ...)" uses the cmake's builtin From addd18b186855f998c729daf36e8dad49f84dcc7 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 1 Dec 2023 17:52:42 -0800 Subject: [PATCH 036/127] [channel-args] Enforce const-correctness for RefCounted values (#35199) Closes #35199 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35199 from ctiller:refcount a3f856858a31b87c7501806223ee82a8edcb9900 PiperOrigin-RevId: 587178819 --- src/core/lib/channel/channel_args.h | 63 ++++++++++++++++++++++++-- test/core/channel/channel_args_test.cc | 31 +++++++++++++ 2 files changed, 89 insertions(+), 5 deletions(-) diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h index 78848750294e9..2c10d955127f4 100644 --- a/src/core/lib/channel/channel_args.h +++ b/src/core/lib/channel/channel_args.h @@ -183,13 +183,27 @@ struct ChannelArgTypeTraits +struct ChannelArgPointerShouldBeConst { + static constexpr bool kValue = false; +}; + +template +struct ChannelArgPointerShouldBeConst< + T, absl::void_t> { + static constexpr bool kValue = T::ChannelArgUseConstPtr(); +}; + // GetObject support for shared_ptr and RefCountedPtr template struct GetObjectImpl; // std::shared_ptr implementation template struct GetObjectImpl< - T, absl::enable_if_t::value, void>> { + T, absl::enable_if_t::kValue && + SupportedSharedPtrType::value, + void>> { using Result = T*; using ReffedResult = std::shared_ptr; using StoredType = std::shared_ptr*; @@ -210,7 +224,9 @@ struct GetObjectImpl< // RefCountedPtr template struct GetObjectImpl< - T, absl::enable_if_t::value, void>> { + T, absl::enable_if_t::kValue && + !SupportedSharedPtrType::value, + void>> { using Result = T*; using ReffedResult = RefCountedPtr; using StoredType = Result; @@ -226,6 +242,26 @@ struct GetObjectImpl< }; }; +template +struct GetObjectImpl< + T, absl::enable_if_t::kValue && + !SupportedSharedPtrType::value, + void>> { + using Result = const T*; + using ReffedResult = RefCountedPtr; + using StoredType = Result; + static Result Get(StoredType p) { return p; }; + static ReffedResult GetReffed(StoredType p) { + if (p == nullptr) return nullptr; + return p->Ref(); + }; + static ReffedResult GetReffed(StoredType p, const DebugLocation& location, + const char* reason) { + if (p == nullptr) return nullptr; + return p->Ref(location, reason); + }; +}; + // Provide the canonical name for a type's channel arg key template struct ChannelArgNameTraits { @@ -242,6 +278,7 @@ struct ChannelArgNameTraits { return GRPC_INTERNAL_ARG_EVENT_ENGINE; } }; + class ChannelArgs { public: class Pointer { @@ -381,15 +418,29 @@ class ChannelArgs { GRPC_MUST_USE_RESULT auto Set(absl::string_view name, RefCountedPtr value) const -> absl::enable_if_t< - std::is_same>::VTable())>::value, + !ChannelArgPointerShouldBeConst::kValue && + std::is_same>::VTable())>::value, ChannelArgs> { return Set( name, Pointer(value.release(), ChannelArgTypeTraits>::VTable())); } template + GRPC_MUST_USE_RESULT auto Set(absl::string_view name, + RefCountedPtr value) const + -> absl::enable_if_t< + ChannelArgPointerShouldBeConst::kValue && + std::is_same>::VTable())>::value, + ChannelArgs> { + return Set( + name, Pointer(const_cast(value.release()), + ChannelArgTypeTraits>::VTable())); + } + template GRPC_MUST_USE_RESULT absl::enable_if_t< std::is_same< const grpc_arg_pointer_vtable*, @@ -426,6 +477,8 @@ class ChannelArgs { absl::optional GetInt(absl::string_view name) const; absl::optional GetString(absl::string_view name) const; absl::optional GetOwnedString(absl::string_view name) const; + // WARNING: this is broken if `name` represents something that was stored as a + // RefCounted - we will discard the const-ness. void* GetVoidPointer(absl::string_view name) const; template typename GetObjectImpl::StoredType GetPointer( diff --git a/test/core/channel/channel_args_test.cc b/test/core/channel/channel_args_test.cc index 10a05d35e2637..fd035ccc12d46 100644 --- a/test/core/channel/channel_args_test.cc +++ b/test/core/channel/channel_args_test.cc @@ -209,6 +209,37 @@ TEST(ChannelArgsTest, GetNonOwningEventEngine) { ASSERT_EQ(p.use_count(), 2); } +struct MutableValue : public RefCounted { + static constexpr absl::string_view ChannelArgName() { + return "grpc.test.mutable_value"; + } + static int ChannelArgsCompare(const MutableValue* a, const MutableValue* b) { + return a->i - b->i; + } + int i = 42; +}; + +struct ConstValue : public RefCounted { + static constexpr absl::string_view ChannelArgName() { + return "grpc.test.const_value"; + } + static constexpr bool ChannelArgUseConstPtr() { return true; }; + static int ChannelArgsCompare(const ConstValue* a, const ConstValue* b) { + return a->i - b->i; + } + int i = 42; +}; + +TEST(ChannelArgsTest, SetObjectRespectsMutabilityConstraints) { + auto m = MakeRefCounted(); + auto c = MakeRefCounted(); + auto args = ChannelArgs().SetObject(m).SetObject(c); + RefCountedPtr m1 = args.GetObjectRef(); + RefCountedPtr c1 = args.GetObjectRef(); + EXPECT_EQ(m1.get(), m.get()); + EXPECT_EQ(c1.get(), c.get()); +} + } // namespace grpc_core TEST(GrpcChannelArgsTest, Create) { From 7047cc17a8337f8c841ae1b5a6afe4bc5b8a72c6 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 1 Dec 2023 17:53:23 -0800 Subject: [PATCH 037/127] [promises] Migrate http server filter to new API (#35197) Closes #35197 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35197 from ctiller:cg-http-svr cdde418a81dff4ad85c7196dc3e3464e429bf9cc PiperOrigin-RevId: 587178983 --- .../filters/http/server/http_server_filter.cc | 81 +++++++++---------- .../filters/http/server/http_server_filter.h | 14 +++- src/core/lib/channel/promise_based_filter.h | 65 +++++++++++++++ 3 files changed, 115 insertions(+), 45 deletions(-) diff --git a/src/core/ext/filters/http/server/http_server_filter.cc b/src/core/ext/filters/http/server/http_server_filter.cc index 2d4953dd26b25..830b931520f74 100644 --- a/src/core/ext/filters/http/server/http_server_filter.cc +++ b/src/core/ext/filters/http/server/http_server_filter.cc @@ -49,6 +49,9 @@ namespace grpc_core { +const NoInterceptor HttpServerFilter::Call::OnClientToServerMessage; +const NoInterceptor HttpServerFilter::Call::OnServerToClientMessage; + const grpc_channel_filter HttpServerFilter::kFilter = MakePromiseBasedFilter("http-server"); @@ -71,85 +74,81 @@ ServerMetadataHandle MalformedRequest(absl::string_view explanation) { } } // namespace -ArenaPromise HttpServerFilter::MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) { - const auto& md = call_args.client_initial_metadata; - - auto method = md->get(HttpMethodMetadata()); +ServerMetadataHandle HttpServerFilter::Call::OnClientInitialMetadata( + ClientMetadata& md, HttpServerFilter* filter) { + auto method = md.get(HttpMethodMetadata()); if (method.has_value()) { switch (*method) { case HttpMethodMetadata::kPost: break; case HttpMethodMetadata::kPut: - if (allow_put_requests_) { + if (filter->allow_put_requests_) { break; } ABSL_FALLTHROUGH_INTENDED; case HttpMethodMetadata::kInvalid: case HttpMethodMetadata::kGet: - return Immediate(MalformedRequest("Bad method header")); + return MalformedRequest("Bad method header"); } } else { - return Immediate(MalformedRequest("Missing :method header")); + return MalformedRequest("Missing :method header"); } - auto te = md->Take(TeMetadata()); + auto te = md.Take(TeMetadata()); if (te == TeMetadata::kTrailers) { // Do nothing, ok. } else if (!te.has_value()) { - return Immediate(MalformedRequest("Missing :te header")); + return MalformedRequest("Missing :te header"); } else { - return Immediate(MalformedRequest("Bad :te header")); + return MalformedRequest("Bad :te header"); } - auto scheme = md->Take(HttpSchemeMetadata()); + auto scheme = md.Take(HttpSchemeMetadata()); if (scheme.has_value()) { if (*scheme == HttpSchemeMetadata::kInvalid) { - return Immediate(MalformedRequest("Bad :scheme header")); + return MalformedRequest("Bad :scheme header"); } } else { - return Immediate(MalformedRequest("Missing :scheme header")); + return MalformedRequest("Missing :scheme header"); } - md->Remove(ContentTypeMetadata()); + md.Remove(ContentTypeMetadata()); - Slice* path_slice = md->get_pointer(HttpPathMetadata()); + Slice* path_slice = md.get_pointer(HttpPathMetadata()); if (path_slice == nullptr) { - return Immediate(MalformedRequest("Missing :path header")); + return MalformedRequest("Missing :path header"); } - if (md->get_pointer(HttpAuthorityMetadata()) == nullptr) { - absl::optional host = md->Take(HostMetadata()); + if (md.get_pointer(HttpAuthorityMetadata()) == nullptr) { + absl::optional host = md.Take(HostMetadata()); if (host.has_value()) { - md->Set(HttpAuthorityMetadata(), std::move(*host)); + md.Set(HttpAuthorityMetadata(), std::move(*host)); } } - if (md->get_pointer(HttpAuthorityMetadata()) == nullptr) { - return Immediate(MalformedRequest("Missing :authority header")); + if (md.get_pointer(HttpAuthorityMetadata()) == nullptr) { + return MalformedRequest("Missing :authority header"); } - if (!surface_user_agent_) { - md->Remove(UserAgentMetadata()); + if (!filter->surface_user_agent_) { + md.Remove(UserAgentMetadata()); } - call_args.server_initial_metadata->InterceptAndMap( - [](ServerMetadataHandle md) { - if (grpc_call_trace.enabled()) { - gpr_log(GPR_INFO, "%s[http-server] Write metadata", - Activity::current()->DebugTag().c_str()); - } - FilterOutgoingMetadata(md.get()); - md->Set(HttpStatusMetadata(), 200); - md->Set(ContentTypeMetadata(), ContentTypeMetadata::kApplicationGrpc); - return md; - }); - - return Map(next_promise_factory(std::move(call_args)), - [](ServerMetadataHandle md) -> ServerMetadataHandle { - FilterOutgoingMetadata(md.get()); - return md; - }); + return nullptr; +} + +void HttpServerFilter::Call::OnServerInitialMetadata(ServerMetadata& md) { + if (grpc_call_trace.enabled()) { + gpr_log(GPR_INFO, "%s[http-server] Write metadata", + Activity::current()->DebugTag().c_str()); + } + FilterOutgoingMetadata(&md); + md.Set(HttpStatusMetadata(), 200); + md.Set(ContentTypeMetadata(), ContentTypeMetadata::kApplicationGrpc); +} + +void HttpServerFilter::Call::OnServerTrailingMetadata(ServerMetadata& md) { + FilterOutgoingMetadata(&md); } absl::StatusOr HttpServerFilter::Create( diff --git a/src/core/ext/filters/http/server/http_server_filter.h b/src/core/ext/filters/http/server/http_server_filter.h index bc97bd53b8a76..43eeb14895790 100644 --- a/src/core/ext/filters/http/server/http_server_filter.h +++ b/src/core/ext/filters/http/server/http_server_filter.h @@ -32,16 +32,22 @@ namespace grpc_core { // Processes metadata on the server side for HTTP2 transports -class HttpServerFilter : public ChannelFilter { +class HttpServerFilter : public ImplementChannelFilter { public: static const grpc_channel_filter kFilter; static absl::StatusOr Create( const ChannelArgs& args, ChannelFilter::Args filter_args); - // Construct a promise for one call. - ArenaPromise MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) override; + class Call { + public: + ServerMetadataHandle OnClientInitialMetadata(ClientMetadata& md, + HttpServerFilter* filter); + void OnServerInitialMetadata(ServerMetadata& md); + void OnServerTrailingMetadata(ServerMetadata& md); + static const NoInterceptor OnClientToServerMessage; + static const NoInterceptor OnServerToClientMessage; + }; private: HttpServerFilter(bool surface_user_agent, bool allow_put_requests) diff --git a/src/core/lib/channel/promise_based_filter.h b/src/core/lib/channel/promise_based_filter.h index 25ee1230ef1ea..a94b79bbd0c0a 100644 --- a/src/core/lib/channel/promise_based_filter.h +++ b/src/core/lib/channel/promise_based_filter.h @@ -61,6 +61,7 @@ #include "src/core/lib/promise/context.h" #include "src/core/lib/promise/pipe.h" #include "src/core/lib/promise/poll.h" +#include "src/core/lib/promise/promise.h" #include "src/core/lib/promise/race.h" #include "src/core/lib/resource_quota/arena.h" #include "src/core/lib/slice/slice_buffer.h" @@ -143,6 +144,12 @@ inline constexpr bool HasAsyncErrorInterceptor(absl::Status (T::*)(A...)) { return true; } +template +inline constexpr bool HasAsyncErrorInterceptor( + ServerMetadataHandle (T::*)(A...)) { + return true; +} + template inline constexpr bool HasAsyncErrorInterceptor(void (T::*)(A...)) { return false; @@ -277,6 +284,16 @@ auto MapResult(absl::Status (Derived::Call::*fn)(ServerMetadata&), Promise x, }); } +template +auto MapResult(void (Derived::Call::*fn)(ServerMetadata&), Promise x, + FilterCallData* call_data) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnServerTrailingMetadata); + return Map(std::move(x), [call_data](ServerMetadataHandle md) { + call_data->call.OnServerTrailingMetadata(*md); + return md; + }); +} + inline auto RunCall(const NoInterceptor*, CallArgs call_args, NextPromiseFactory next_promise_factory, void*) { return next_promise_factory(std::move(call_args)); @@ -291,6 +308,31 @@ inline auto RunCall(void (Derived::Call::*fn)(ClientMetadata& md), return next_promise_factory(std::move(call_args)); } +template +inline auto RunCall( + ServerMetadataHandle (Derived::Call::*fn)(ClientMetadata& md), + CallArgs call_args, NextPromiseFactory next_promise_factory, + FilterCallData* call_data) -> ArenaPromise { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnClientInitialMetadata); + auto return_md = call_data->call.OnClientInitialMetadata( + *call_args.client_initial_metadata); + if (return_md == nullptr) return next_promise_factory(std::move(call_args)); + return Immediate(std::move(return_md)); +} + +template +inline auto RunCall(ServerMetadataHandle (Derived::Call::*fn)( + ClientMetadata& md, Derived* channel), + CallArgs call_args, NextPromiseFactory next_promise_factory, + FilterCallData* call_data) + -> ArenaPromise { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnClientInitialMetadata); + auto return_md = call_data->call.OnClientInitialMetadata( + *call_args.client_initial_metadata, call_data->channel); + if (return_md == nullptr) return next_promise_factory(std::move(call_args)); + return Immediate(std::move(return_md)); +} + template inline auto RunCall(void (Derived::Call::*fn)(ClientMetadata& md, Derived* channel), @@ -308,6 +350,18 @@ inline void InterceptClientToServerMessage(const NoInterceptor*, void*, inline void InterceptServerInitialMetadata(const NoInterceptor*, void*, CallArgs&) {} +template +inline void InterceptServerInitialMetadata( + void (Derived::Call::*fn)(ServerMetadata&), + FilterCallData* call_data, CallArgs& call_args) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnServerInitialMetadata); + call_args.server_initial_metadata->InterceptAndMap( + [call_data](ServerMetadataHandle md) { + call_data->call.OnServerInitialMetadata(*md); + return md; + }); +} + template inline void InterceptServerInitialMetadata( absl::Status (Derived::Call::*fn)(ServerMetadata&), @@ -373,6 +427,11 @@ MakeFilterCall(Derived* derived) { // - absl::Status $INTERCEPTOR_NAME($VALUE_TYPE&): // the filter intercepts this event, and can modify the value. // it can fail, in which case the call will be aborted. +// - ServerMetadataHandle $INTERCEPTOR_NAME($VALUE_TYPE&) +// the filter intercepts this event, and can modify the value. +// the filter can return nullptr for success, or a metadata handle for +// failure (in which case the call will be aborted). +// useful for cases where the exact metadata returned needs to be customized. // - void $INTERCEPTOR_NAME($VALUE_TYPE&, Derived*): // the filter intercepts this event, and can modify the value. // it can access the channel via the second argument. @@ -381,6 +440,12 @@ MakeFilterCall(Derived* derived) { // the filter intercepts this event, and can modify the value. // it can access the channel via the second argument. // it can fail, in which case the call will be aborted. +// - ServerMetadataHandle $INTERCEPTOR_NAME($VALUE_TYPE&, Derived*) +// the filter intercepts this event, and can modify the value. +// it can access the channel via the second argument. +// the filter can return nullptr for success, or a metadata handle for +// failure (in which case the call will be aborted). +// useful for cases where the exact metadata returned needs to be customized. template class ImplementChannelFilter : public ChannelFilter { public: From 207b88186878e67901a8d69095de64c221ed138e Mon Sep 17 00:00:00 2001 From: Tanvi Jagtap <139093547+tanvi-jagtap@users.noreply.github.com> Date: Mon, 4 Dec 2023 11:19:11 -0800 Subject: [PATCH 038/127] [grpc] Remove redundant check (#35161) We dont need this check anymore . Deleting the check from the yaml and the sh file. Closes #35161 PiperOrigin-RevId: 587784923 --- tools/run_tests/sanity/check_do_not_submit.sh | 23 ------------------- tools/run_tests/sanity/sanity_tests.yaml | 1 - 2 files changed, 24 deletions(-) delete mode 100755 tools/run_tests/sanity/check_do_not_submit.sh diff --git a/tools/run_tests/sanity/check_do_not_submit.sh b/tools/run_tests/sanity/check_do_not_submit.sh deleted file mode 100755 index 6e0438cd5cb67..0000000000000 --- a/tools/run_tests/sanity/check_do_not_submit.sh +++ /dev/null @@ -1,23 +0,0 @@ -#! /bin/bash -# Copyright 2021 The gRPC Authors -# -# Licensed 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. -# -# Checks if any file contains "DO NOT SUBMIT" - -cd "$(dirname "$0")/../../.." || exit 1 -git grep -Irn 'DO NOT SUBMIT' -- \ - './*' \ - ':!*check_do_not_submit.sh' \ - ':!third_party/' -test $? -eq 1 || exit 1 diff --git a/tools/run_tests/sanity/sanity_tests.yaml b/tools/run_tests/sanity/sanity_tests.yaml index 439891f75bf06..6c4494b00c284 100644 --- a/tools/run_tests/sanity/sanity_tests.yaml +++ b/tools/run_tests/sanity/sanity_tests.yaml @@ -6,7 +6,6 @@ - script: tools/run_tests/sanity/check_buildifier.sh - script: tools/run_tests/sanity/check_cache_mk.sh - script: tools/run_tests/sanity/check_deprecated_grpc++.py -- script: tools/run_tests/sanity/check_do_not_submit.sh - script: tools/run_tests/sanity/check_illegal_terms.sh - script: tools/run_tests/sanity/check_port_platform.py - script: tools/run_tests/sanity/check_include_style.py From 501b895736b196dcbb4efa6df77bb39220c74a07 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 4 Dec 2023 12:04:41 -0800 Subject: [PATCH 039/127] [fuzzing-heck] Fix a bug that comes up with promises + work serializer dispatch (#35196) b/310341170 I'm kind of proud of our testing for finding this Closes #35196 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35196 from ctiller:fuzz-no 28c95606f97732ea1069f3eb067484f9a3f84ec1 PiperOrigin-RevId: 587798657 --- src/core/ext/filters/client_channel/client_channel.cc | 8 ++++++++ .../negative_deadline/5769288995635200 | 11 +++++++++++ 2 files changed, 19 insertions(+) create mode 100644 test/core/end2end/end2end_test_corpus/negative_deadline/5769288995635200 diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc index b5064ceb20fd9..197173aa7e09c 100644 --- a/src/core/ext/filters/client_channel/client_channel.cc +++ b/src/core/ext/filters/client_channel/client_channel.cc @@ -315,6 +315,14 @@ class ClientChannel::PromiseBasedCallData : public ClientChannel::CallData { public: explicit PromiseBasedCallData(ClientChannel* chand) : chand_(chand) {} + ~PromiseBasedCallData() override { + if (was_queued_ && client_initial_metadata_ != nullptr) { + MutexLock lock(&chand_->resolution_mu_); + RemoveCallFromResolverQueuedCallsLocked(); + chand_->resolver_queued_calls_.erase(this); + } + } + ArenaPromise> MakeNameResolutionPromise( CallArgs call_args) { pollent_ = NowOrNever(call_args.polling_entity->WaitAndCopy()).value(); diff --git a/test/core/end2end/end2end_test_corpus/negative_deadline/5769288995635200 b/test/core/end2end/end2end_test_corpus/negative_deadline/5769288995635200 new file mode 100644 index 0000000000000..bb65fceedf8ac --- /dev/null +++ b/test/core/end2end/end2end_test_corpus/negative_deadline/5769288995635200 @@ -0,0 +1,11 @@ +test_id: 3 +event_engine_actions { + run_delay: 9851624184873214 + run_delay: 1 + run_delay: 1 + run_delay: 0 + run_delay: 53876069761024 +} +config_vars { + experiments: 280384054960896 +} From 16fb6bf640936f21d1b6e4d387a7a135ad5be4cd Mon Sep 17 00:00:00 2001 From: ericsalo <93227906+ericsalo@users.noreply.github.com> Date: Mon, 4 Dec 2023 14:39:06 -0800 Subject: [PATCH 040/127] [upb] Update "upb::SymbolTable" to "upb::DefPool" (#35208) The old name has been deprecated for a while so this should be safe. Also update variable names accordingly. Closes #35208 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35208 from ericsalo:master 80beea4920cd7469782e78c2695187798a8c3cdc PiperOrigin-RevId: 587845096 --- src/core/ext/xds/xds_api.cc | 35 ++++++++++++------- src/core/ext/xds/xds_api.h | 4 +-- src/core/ext/xds/xds_client.cc | 6 ++-- src/core/ext/xds/xds_client.h | 2 +- .../xds/xds_audit_logger_registry_test.cc | 8 ++--- test/core/xds/xds_lb_policy_registry_test.cc | 8 ++--- 6 files changed, 36 insertions(+), 27 deletions(-) diff --git a/src/core/ext/xds/xds_api.cc b/src/core/ext/xds/xds_api.cc index 8b77e30ed7914..b23c446401fb3 100644 --- a/src/core/ext/xds/xds_api.cc +++ b/src/core/ext/xds/xds_api.cc @@ -57,12 +57,12 @@ namespace grpc_core { XdsApi::XdsApi(XdsClient* client, TraceFlag* tracer, - const XdsBootstrap::Node* node, upb::SymbolTable* symtab, + const XdsBootstrap::Node* node, upb::DefPool* def_pool, std::string user_agent_name, std::string user_agent_version) : client_(client), tracer_(tracer), node_(node), - symtab_(symtab), + def_pool_(def_pool), user_agent_name_(std::move(user_agent_name)), user_agent_version_(std::move(user_agent_version)) {} @@ -71,7 +71,7 @@ namespace { struct XdsApiContext { XdsClient* client; TraceFlag* tracer; - upb_DefPool* symtab; + upb_DefPool* def_pool; upb_Arena* arena; }; @@ -183,7 +183,7 @@ void MaybeLogDiscoveryRequest( if (GRPC_TRACE_FLAG_ENABLED(*context.tracer) && gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) { const upb_MessageDef* msg_type = - envoy_service_discovery_v3_DiscoveryRequest_getmsgdef(context.symtab); + envoy_service_discovery_v3_DiscoveryRequest_getmsgdef(context.def_pool); char buf[10240]; upb_TextEncode(request, msg_type, nullptr, 0, buf, sizeof(buf)); gpr_log(GPR_DEBUG, "[xds_client %p] constructed ADS request: %s", @@ -207,7 +207,8 @@ std::string XdsApi::CreateAdsRequest( absl::string_view nonce, const std::vector& resource_names, absl::Status status, bool populate_node) { upb::Arena arena; - const XdsApiContext context = {client_, tracer_, symtab_->ptr(), arena.ptr()}; + const XdsApiContext context = {client_, tracer_, def_pool_->ptr(), + arena.ptr()}; // Create a request. envoy_service_discovery_v3_DiscoveryRequest* request = envoy_service_discovery_v3_DiscoveryRequest_new(arena.ptr()); @@ -270,7 +271,8 @@ void MaybeLogDiscoveryResponse( if (GRPC_TRACE_FLAG_ENABLED(*context.tracer) && gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) { const upb_MessageDef* msg_type = - envoy_service_discovery_v3_DiscoveryResponse_getmsgdef(context.symtab); + envoy_service_discovery_v3_DiscoveryResponse_getmsgdef( + context.def_pool); char buf[10240]; upb_TextEncode(response, msg_type, nullptr, 0, buf, sizeof(buf)); gpr_log(GPR_DEBUG, "[xds_client %p] received response: %s", context.client, @@ -283,7 +285,8 @@ void MaybeLogDiscoveryResponse( absl::Status XdsApi::ParseAdsResponse(absl::string_view encoded_response, AdsResponseParserInterface* parser) { upb::Arena arena; - const XdsApiContext context = {client_, tracer_, symtab_->ptr(), arena.ptr()}; + const XdsApiContext context = {client_, tracer_, def_pool_->ptr(), + arena.ptr()}; // Decode the response. const envoy_service_discovery_v3_DiscoveryResponse* response = envoy_service_discovery_v3_DiscoveryResponse_parse( @@ -356,7 +359,8 @@ void MaybeLogLrsRequest( if (GRPC_TRACE_FLAG_ENABLED(*context.tracer) && gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) { const upb_MessageDef* msg_type = - envoy_service_load_stats_v3_LoadStatsRequest_getmsgdef(context.symtab); + envoy_service_load_stats_v3_LoadStatsRequest_getmsgdef( + context.def_pool); char buf[10240]; upb_TextEncode(request, msg_type, nullptr, 0, buf, sizeof(buf)); gpr_log(GPR_DEBUG, "[xds_client %p] constructed LRS request: %s", @@ -377,7 +381,8 @@ std::string SerializeLrsRequest( std::string XdsApi::CreateLrsInitialRequest() { upb::Arena arena; - const XdsApiContext context = {client_, tracer_, symtab_->ptr(), arena.ptr()}; + const XdsApiContext context = {client_, tracer_, def_pool_->ptr(), + arena.ptr()}; // Create a request. envoy_service_load_stats_v3_LoadStatsRequest* request = envoy_service_load_stats_v3_LoadStatsRequest_new(arena.ptr()); @@ -447,7 +452,8 @@ void LocalityStatsPopulate( std::string XdsApi::CreateLrsRequest( ClusterLoadReportMap cluster_load_report_map) { upb::Arena arena; - const XdsApiContext context = {client_, tracer_, symtab_->ptr(), arena.ptr()}; + const XdsApiContext context = {client_, tracer_, def_pool_->ptr(), + arena.ptr()}; // Create a request. envoy_service_load_stats_v3_LoadStatsRequest* request = envoy_service_load_stats_v3_LoadStatsRequest_new(arena.ptr()); @@ -514,7 +520,8 @@ void MaybeLogLrsResponse( if (GRPC_TRACE_FLAG_ENABLED(*context.tracer) && gpr_should_log(GPR_LOG_SEVERITY_DEBUG)) { const upb_MessageDef* msg_type = - envoy_service_load_stats_v3_LoadStatsResponse_getmsgdef(context.symtab); + envoy_service_load_stats_v3_LoadStatsResponse_getmsgdef( + context.def_pool); char buf[10240]; upb_TextEncode(response, msg_type, nullptr, 0, buf, sizeof(buf)); gpr_log(GPR_DEBUG, "[xds_client %p] received LRS response: %s", @@ -537,7 +544,8 @@ absl::Status XdsApi::ParseLrsResponse(absl::string_view encoded_response, if (decoded_response == nullptr) { return absl::UnavailableError("Can't decode response."); } - const XdsApiContext context = {client_, tracer_, symtab_->ptr(), arena.ptr()}; + const XdsApiContext context = {client_, tracer_, def_pool_->ptr(), + arena.ptr()}; MaybeLogLrsResponse(context, decoded_response); // Check send_all_clusters. if (envoy_service_load_stats_v3_LoadStatsResponse_send_all_clusters( @@ -585,7 +593,8 @@ std::string XdsApi::AssembleClientConfig( // Fill-in the node information auto* node = envoy_service_status_v3_ClientConfig_mutable_node(client_config, arena.ptr()); - const XdsApiContext context = {client_, tracer_, symtab_->ptr(), arena.ptr()}; + const XdsApiContext context = {client_, tracer_, def_pool_->ptr(), + arena.ptr()}; PopulateNode(context, node_, user_agent_name_, user_agent_version_, node); // Dump each resource. std::vector type_url_storage; diff --git a/src/core/ext/xds/xds_api.h b/src/core/ext/xds/xds_api.h index 256998cc24df0..2d96892496667 100644 --- a/src/core/ext/xds/xds_api.h +++ b/src/core/ext/xds/xds_api.h @@ -148,7 +148,7 @@ class XdsApi { ""); XdsApi(XdsClient* client, TraceFlag* tracer, const XdsBootstrap::Node* node, - upb::SymbolTable* symtab, std::string user_agent_name, + upb::DefPool* def_pool, std::string user_agent_name, std::string user_agent_version); // Creates an ADS request. @@ -184,7 +184,7 @@ class XdsApi { XdsClient* client_; TraceFlag* tracer_; const XdsBootstrap::Node* node_; // Do not own. - upb::SymbolTable* symtab_; // Do not own. + upb::DefPool* def_pool_; // Do not own. const std::string user_agent_name_; const std::string user_agent_version_; }; diff --git a/src/core/ext/xds/xds_client.cc b/src/core/ext/xds/xds_client.cc index 19d2702a6d51f..e6399e98d1a30 100644 --- a/src/core/ext/xds/xds_client.cc +++ b/src/core/ext/xds/xds_client.cc @@ -756,7 +756,7 @@ void XdsClient::ChannelState::AdsCallState::AdsResponseParser::ParseResource( // Parse the resource. XdsResourceType::DecodeContext context = { xds_client(), ads_call_state_->chand()->server_, &grpc_xds_client_trace, - xds_client()->symtab_.ptr(), arena}; + xds_client()->def_pool_.ptr(), arena}; XdsResourceType::DecodeResult decode_result = result_.type->Decode(context, serialized_resource); // If we didn't already have the resource name from the Resource @@ -1490,7 +1490,7 @@ XdsClient::XdsClient( transport_factory_(std::move(transport_factory)), request_timeout_(resource_request_timeout), xds_federation_enabled_(XdsFederationEnabled()), - api_(this, &grpc_xds_client_trace, bootstrap_->node(), &symtab_, + api_(this, &grpc_xds_client_trace, bootstrap_->node(), &def_pool_, std::move(user_agent_name), std::move(user_agent_version)), work_serializer_(engine), engine_(std::move(engine)) { @@ -1722,7 +1722,7 @@ void XdsClient::MaybeRegisterResourceTypeLocked( return; } resource_types_.emplace(resource_type->type_url(), resource_type); - resource_type->InitUpbSymtab(this, symtab_.ptr()); + resource_type->InitUpbSymtab(this, def_pool_.ptr()); } const XdsResourceType* XdsClient::GetResourceTypeLocked( diff --git a/src/core/ext/xds/xds_client.h b/src/core/ext/xds/xds_client.h index bd24d8ae193b9..0831c3c768ace 100644 --- a/src/core/ext/xds/xds_client.h +++ b/src/core/ext/xds/xds_client.h @@ -317,7 +317,7 @@ class XdsClient : public DualRefCounted { // Stores resource type objects seen by type URL. std::map resource_types_ ABSL_GUARDED_BY(mu_); - upb::SymbolTable symtab_ ABSL_GUARDED_BY(mu_); + upb::DefPool def_pool_ ABSL_GUARDED_BY(mu_); // Map of existing xDS server channels. // Key is owned by the bootstrap config. diff --git a/test/core/xds/xds_audit_logger_registry_test.cc b/test/core/xds/xds_audit_logger_registry_test.cc index abfc73801e674..7249b1c8b1bfb 100644 --- a/test/core/xds/xds_audit_logger_registry_test.cc +++ b/test/core/xds/xds_audit_logger_registry_test.cc @@ -65,10 +65,10 @@ absl::StatusOr ConvertAuditLoggerConfig( const AuditLoggerConfigProto& config) { std::string serialized_config = config.SerializeAsString(); upb::Arena arena; - upb::SymbolTable symtab; - XdsResourceType::DecodeContext context = {nullptr, - GrpcXdsBootstrap::GrpcXdsServer(), - nullptr, symtab.ptr(), arena.ptr()}; + upb::DefPool def_pool; + XdsResourceType::DecodeContext context = { + nullptr, GrpcXdsBootstrap::GrpcXdsServer(), nullptr, def_pool.ptr(), + arena.ptr()}; auto* upb_config = envoy_config_rbac_v3_RBAC_AuditLoggingOptions_AuditLoggerConfig_parse( serialized_config.data(), serialized_config.size(), arena.ptr()); diff --git a/test/core/xds/xds_lb_policy_registry_test.cc b/test/core/xds/xds_lb_policy_registry_test.cc index b6b10dddd3cd4..d139d6005e3d1 100644 --- a/test/core/xds/xds_lb_policy_registry_test.cc +++ b/test/core/xds/xds_lb_policy_registry_test.cc @@ -74,10 +74,10 @@ absl::StatusOr ConvertXdsPolicy( const LoadBalancingPolicyProto& policy) { std::string serialized_policy = policy.SerializeAsString(); upb::Arena arena; - upb::SymbolTable symtab; - XdsResourceType::DecodeContext context = {nullptr, - GrpcXdsBootstrap::GrpcXdsServer(), - nullptr, symtab.ptr(), arena.ptr()}; + upb::DefPool def_pool; + XdsResourceType::DecodeContext context = { + nullptr, GrpcXdsBootstrap::GrpcXdsServer(), nullptr, def_pool.ptr(), + arena.ptr()}; auto* upb_policy = envoy_config_cluster_v3_LoadBalancingPolicy_parse( serialized_policy.data(), serialized_policy.size(), arena.ptr()); ValidationErrors errors; From b5708790101c9ad207495d3178d9f36684a71e43 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Mon, 4 Dec 2023 15:00:29 -0800 Subject: [PATCH 041/127] [PSM Interop] Log on debug level when resource deletion failure is 404 (#35131) Removes noise from the cleanup/teardown ops. #### GCP APIs In GCP APIs, change log level for delete operations that failed because the resource doesn't exist (API 404) from `info` to `debug`. Framework's logging philosophy is to only log external operations (e.g. APIs, RPCs). If no error logged, the op is assumed successful. In the deletion case, is still possible to discriminate between whether the op was actually performed by observing the `Waiting %s sec for %s operation id: %s` log message. #### K8s APIs In K8s APIs: - For delete operations that failed because the resource doesn't exist (API 404) the log level is changed from `info` to `debug` - For delete operations that failed for any other reason, the log level is changed from `info` to `warning` - When `wait_for_deletion` is enabled (it's the default) the delete operation will be confirmed with `logger.info(" %s deleted", name)`. Previously it logged at the `debug` level. Closes #35131 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35131 from sergiitk:psm-interop-debug-log-on-delete-404 f6629e5132f0f3ef91acb51921b694833d88cbf3 PiperOrigin-RevId: 587851692 --- .../xds_k8s_test_driver/bin/run_ping_pong.py | 1 + .../framework/infrastructure/gcp/api.py | 2 +- .../framework/infrastructure/gcp/compute.py | 4 +- .../test_app/runners/k8s/k8s_base_runner.py | 91 ++++++++++++++----- 4 files changed, 71 insertions(+), 27 deletions(-) diff --git a/tools/run_tests/xds_k8s_test_driver/bin/run_ping_pong.py b/tools/run_tests/xds_k8s_test_driver/bin/run_ping_pong.py index c321e3899077e..d811a16a378f3 100755 --- a/tools/run_tests/xds_k8s_test_driver/bin/run_ping_pong.py +++ b/tools/run_tests/xds_k8s_test_driver/bin/run_ping_pong.py @@ -79,6 +79,7 @@ def get_client_rpc_stats( def run_ping_pong(test_client: _XdsTestClient, num_rpcs: int): + test_client.wait_for_active_xds_channel() test_client.wait_for_server_channel_ready() lb_stats = get_client_rpc_stats(test_client, num_rpcs) for backend, rpcs_count in lb_stats.rpcs_by_peer.items(): diff --git a/tools/run_tests/xds_k8s_test_driver/framework/infrastructure/gcp/api.py b/tools/run_tests/xds_k8s_test_driver/framework/infrastructure/gcp/api.py index 05bd08ab6f2a6..33e48d760092a 100644 --- a/tools/run_tests/xds_k8s_test_driver/framework/infrastructure/gcp/api.py +++ b/tools/run_tests/xds_k8s_test_driver/framework/infrastructure/gcp/api.py @@ -501,7 +501,7 @@ def _delete_resource( return True except _HttpError as error: if error.resp and error.resp.status == 404: - logger.info("%s not deleted since it does not exist", full_name) + logger.debug("%s not deleted since it doesn't exist", full_name) else: logger.warning("Failed to delete %s, %r", full_name, error) return False diff --git a/tools/run_tests/xds_k8s_test_driver/framework/infrastructure/gcp/compute.py b/tools/run_tests/xds_k8s_test_driver/framework/infrastructure/gcp/compute.py index 93ed60d25fc23..b06a1007b4ef1 100644 --- a/tools/run_tests/xds_k8s_test_driver/framework/infrastructure/gcp/compute.py +++ b/tools/run_tests/xds_k8s_test_driver/framework/infrastructure/gcp/compute.py @@ -565,8 +565,8 @@ def _delete_resource( return True except googleapiclient.errors.HttpError as error: if error.resp and error.resp.status == 404: - logger.info( - 'Resource %s "%s" not deleted since it does not exist', + logger.debug( + "Resource %s %s not deleted since it doesn't exist", resource_type, resource_name, ) diff --git a/tools/run_tests/xds_k8s_test_driver/framework/test_app/runners/k8s/k8s_base_runner.py b/tools/run_tests/xds_k8s_test_driver/framework/test_app/runners/k8s/k8s_base_runner.py index da17961d5f443..3df9bd19a253e 100644 --- a/tools/run_tests/xds_k8s_test_driver/framework/test_app/runners/k8s/k8s_base_runner.py +++ b/tools/run_tests/xds_k8s_test_driver/framework/test_app/runners/k8s/k8s_base_runner.py @@ -582,20 +582,32 @@ def _delete_gamma_route(self, name, wait_for_deletion=True): logger.info("Deleting HTTPRoute %s", name) try: self.k8s_namespace.delete_gamma_route(name) - except (retryers.RetryError, k8s.NotFound) as e: - logger.info("HTTPRoute %s deletion failed: %s", name, e) + except k8s.NotFound: + logger.debug( + "HTTPRoute %s not deleted since it doesn't exist", name + ) + return + except retryers.RetryError as e: + logger.warning("HTTPRoute %s deletion failed: %s", name, e) return if wait_for_deletion: self.k8s_namespace.wait_for_get_gamma_route_deleted(name) - logger.debug("HTTPRoute %s deleted", name) + logger.info("HTTPRoute %s deleted", name) def _delete_session_affinity_policy(self, name, wait_for_deletion=True): logger.info("Deleting GCPSessionAffinityPolicy %s", name) try: self.k8s_namespace.delete_session_affinity_policy(name) - except (retryers.RetryError, k8s.NotFound) as e: - logger.info( + except k8s.NotFound: + logger.debug( + "GCPSessionAffinityPolicy %s not deleted since it" + " doesn't exist", + name, + ) + return + except retryers.RetryError as e: + logger.warning( "GCPSessionAffinityPolicy %s deletion failed: %s", name, e ) return @@ -604,14 +616,21 @@ def _delete_session_affinity_policy(self, name, wait_for_deletion=True): self.k8s_namespace.wait_for_get_session_affinity_policy_deleted( name ) - logger.debug("GCPSessionAffinityPolicy %s deleted", name) + logger.info("GCPSessionAffinityPolicy %s deleted", name) def _delete_session_affinity_filter(self, name, wait_for_deletion=True): logger.info("Deleting GCPSessionAffinityFilter %s", name) try: self.k8s_namespace.delete_session_affinity_filter(name) - except (retryers.RetryError, k8s.NotFound) as e: - logger.info( + except k8s.NotFound: + logger.debug( + "GCPSessionAffinityFilter %s not deleted since it" + " doesn't exist", + name, + ) + return + except retryers.RetryError as e: + logger.warning( "GCPSessionAffinityFilter %s deletion failed: %s", name, e ) return @@ -620,71 +639,95 @@ def _delete_session_affinity_filter(self, name, wait_for_deletion=True): self.k8s_namespace.wait_for_get_session_affinity_filter_deleted( name ) - logger.debug("GCPSessionAffinityFilter %s deleted", name) + logger.info("GCPSessionAffinityFilter %s deleted", name) def _delete_backend_policy(self, name, wait_for_deletion=True): logger.info("Deleting GCPBackendPolicy %s", name) try: self.k8s_namespace.delete_backend_policy(name) - except (retryers.RetryError, k8s.NotFound) as e: - logger.info("GGCPBackendPolicy %s deletion failed: %s", name, e) + except k8s.NotFound: + logger.debug( + "GGCPBackendPolicy %s not deleted since it doesn't exist", name + ) + return + except retryers.RetryError as e: + logger.warning("GGCPBackendPolicy %s deletion failed: %s", name, e) return if wait_for_deletion: self.k8s_namespace.wait_for_get_backend_policy_deleted(name) - logger.debug("GCPBackendPolicy %s deleted", name) + logger.info("GCPBackendPolicy %s deleted", name) def _delete_deployment(self, name, wait_for_deletion=True): logger.info("Deleting deployment %s", name) self.stop_pod_dependencies() try: self.k8s_namespace.delete_deployment(name) - except (retryers.RetryError, k8s.NotFound) as e: - logger.info("Deployment %s deletion failed: %s", name, e) + except k8s.NotFound: + logger.debug( + "Deployment %s not deleted since it doesn't exist", name + ) + return + except retryers.RetryError as e: + logger.warning("Deployment %s deletion failed: %s", name, e) return if wait_for_deletion: self.k8s_namespace.wait_for_deployment_deleted(name) - logger.debug("Deployment %s deleted", name) + logger.info("Deployment %s deleted", name) def _delete_service(self, name, wait_for_deletion=True): logger.info("Deleting service %s", name) try: self.k8s_namespace.delete_service(name) - except (retryers.RetryError, k8s.NotFound) as e: - logger.info("Service %s deletion failed: %s", name, e) + except k8s.NotFound: + logger.debug("Service %s not deleted since it doesn't exist", name) + return + except retryers.RetryError as e: + logger.warning("Service %s deletion failed: %s", name, e) return if wait_for_deletion: self.k8s_namespace.wait_for_service_deleted(name) - logger.debug("Service %s deleted", name) + logger.info("Service %s deleted", name) def _delete_service_account(self, name, wait_for_deletion=True): logger.info("Deleting service account %s", name) try: self.k8s_namespace.delete_service_account(name) - except (retryers.RetryError, k8s.NotFound) as e: - logger.info("Service account %s deletion failed: %s", name, e) + except k8s.NotFound: + logger.debug( + "Service account %s not deleted since it doesn't exist", name + ) + return + except retryers.RetryError as e: + logger.warning("Service account %s deletion failed: %s", name, e) return if wait_for_deletion: self.k8s_namespace.wait_for_service_account_deleted(name) - logger.debug("Service account %s deleted", name) + logger.info("Service account %s deleted", name) def delete_namespace(self, wait_for_deletion=True): logger.info("Deleting namespace %s", self.k8s_namespace.name) try: self.k8s_namespace.delete() - except (retryers.RetryError, k8s.NotFound) as e: - logger.info( + except k8s.NotFound: + logger.debug( + "Namespace %s not deleted since it doesn't exist", + self.k8s_namespace.name, + ) + return + except retryers.RetryError as e: + logger.warning( "Namespace %s deletion failed: %s", self.k8s_namespace.name, e ) return if wait_for_deletion: self.k8s_namespace.wait_for_namespace_deleted() - logger.debug("Namespace %s deleted", self.k8s_namespace.name) + logger.info("Namespace %s deleted", self.k8s_namespace.name) def _wait_deployment_with_available_replicas(self, name, count=1, **kwargs): logger.info( From 01fb4a0fe4399a525635df6672cb1af486f30d03 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 4 Dec 2023 15:16:30 -0800 Subject: [PATCH 042/127] [experiments] Clean up some rolled out experiments (#35195) Closes #35195 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35195 from ctiller:cleanup-cleanup 1f22298ac977dfe1f476824cf79f614d5e4cc698 PiperOrigin-RevId: 587857022 --- bazel/experiments.bzl | 45 +--- .../chttp2/transport/chttp2_transport.cc | 8 +- .../chttp2/transport/flow_control.cc | 20 +- .../chttp2/transport/frame_rst_stream.cc | 2 +- .../ext/transport/chttp2/transport/parsing.cc | 6 +- .../ext/transport/chttp2/transport/writing.cc | 10 +- src/core/lib/experiments/experiments.cc | 225 +----------------- src/core/lib/experiments/experiments.h | 111 --------- src/core/lib/experiments/experiments.yaml | 66 ----- src/core/lib/experiments/rollouts.yaml | 22 -- src/core/lib/iomgr/combiner.cc | 66 ++--- src/core/lib/transport/metadata_batch.h | 5 +- .../tests/initial_settings_frame.cc | 10 +- 13 files changed, 37 insertions(+), 559 deletions(-) diff --git a/bazel/experiments.bzl b/bazel/experiments.bzl index 6e0200f2fd988..e5f402426956b 100644 --- a/bazel/experiments.bzl +++ b/bazel/experiments.bzl @@ -17,14 +17,10 @@ """Dictionary of tags to experiments so we know when to test different experiments.""" EXPERIMENT_ENABLES = { - "block_excessive_requests_before_settings_ack": "block_excessive_requests_before_settings_ack", "call_status_override_on_cancellation": "call_status_override_on_cancellation", "canary_client_privacy": "canary_client_privacy", "client_idleness": "client_idleness", "client_privacy": "client_privacy", - "combiner_offload_to_event_engine": "combiner_offload_to_event_engine", - "chttp2_batch_requests": "chttp2_batch_requests,combiner_offload_to_event_engine", - "chttp2_offload_on_rst_stream": "chttp2_offload_on_rst_stream,combiner_offload_to_event_engine", "event_engine_client": "event_engine_client", "event_engine_dns": "event_engine_dns", "event_engine_listener": "event_engine_listener", @@ -32,7 +28,6 @@ EXPERIMENT_ENABLES = { "http2_stats_fix": "http2_stats_fix", "keepalive_fix": "keepalive_fix", "keepalive_server_fix": "keepalive_server_fix", - "lazier_stream_updates": "lazier_stream_updates", "memory_pressure_controller": "memory_pressure_controller", "monitoring_experiment": "monitoring_experiment", "multiping": "multiping", @@ -40,10 +35,9 @@ EXPERIMENT_ENABLES = { "peer_state_based_framing": "peer_state_based_framing", "pending_queue_cap": "pending_queue_cap", "pick_first_happy_eyeballs": "pick_first_happy_eyeballs", - "ping_on_rst_stream": "ping_on_rst_stream", "promise_based_client_call": "promise_based_client_call", "promise_based_inproc_transport": "promise_based_inproc_transport", - "promise_based_server_call": "lazier_stream_updates,promise_based_server_call", + "promise_based_server_call": "promise_based_server_call", "red_max_concurrent_streams": "red_max_concurrent_streams", "registered_method_lookup_in_transport": "registered_method_lookup_in_transport", "registered_methods_map": "registered_methods_map", @@ -51,15 +45,11 @@ EXPERIMENT_ENABLES = { "round_robin_delegate_to_pick_first": "round_robin_delegate_to_pick_first", "rstpit": "rstpit", "schedule_cancellation_over_write": "schedule_cancellation_over_write", - "separate_ping_from_keepalive": "separate_ping_from_keepalive", "server_privacy": "server_privacy", - "settings_timeout": "settings_timeout", - "tarpit": "tarpit", "tcp_frame_size_tuning": "tcp_frame_size_tuning", "tcp_rcv_lowat": "tcp_rcv_lowat", "trace_record_callops": "trace_record_callops", "unconstrained_max_quota_buffer_size": "unconstrained_max_quota_buffer_size", - "uniquely_unowned": "uniquely_unowned", "work_serializer_clears_time_cache": "work_serializer_clears_time_cache", "work_serializer_dispatch": "work_serializer_dispatch", "write_size_policy": "write_size_policy", @@ -116,17 +106,9 @@ EXPERIMENTS = { ], }, "on": { - "bad_client_test": [ - "block_excessive_requests_before_settings_ack", - "tarpit", - ], "core_end2end_test": [ "event_engine_listener", ], - "cpp_end2end_test": [ - "chttp2_batch_requests", - "chttp2_offload_on_rst_stream", - ], "cpp_lb_end2end_test": [ "pick_first_happy_eyeballs", "round_robin_delegate_to_pick_first", @@ -136,9 +118,6 @@ EXPERIMENTS = { "event_engine_listener", ], "flow_control_test": [ - "chttp2_batch_requests", - "chttp2_offload_on_rst_stream", - "lazier_stream_updates", "overload_protection", "write_size_cap", "write_size_policy", @@ -206,23 +185,12 @@ EXPERIMENTS = { ], }, "on": { - "bad_client_test": [ - "block_excessive_requests_before_settings_ack", - "tarpit", - ], - "cpp_end2end_test": [ - "chttp2_batch_requests", - "chttp2_offload_on_rst_stream", - ], "cpp_lb_end2end_test": [ "pick_first_happy_eyeballs", "round_robin_delegate_to_pick_first", "wrr_delegate_to_pick_first", ], "flow_control_test": [ - "chttp2_batch_requests", - "chttp2_offload_on_rst_stream", - "lazier_stream_updates", "overload_protection", "write_size_cap", "write_size_policy", @@ -300,17 +268,9 @@ EXPERIMENTS = { ], }, "on": { - "bad_client_test": [ - "block_excessive_requests_before_settings_ack", - "tarpit", - ], "core_end2end_test": [ "event_engine_listener", ], - "cpp_end2end_test": [ - "chttp2_batch_requests", - "chttp2_offload_on_rst_stream", - ], "cpp_lb_end2end_test": [ "pick_first_happy_eyeballs", "round_robin_delegate_to_pick_first", @@ -320,9 +280,6 @@ EXPERIMENTS = { "event_engine_listener", ], "flow_control_test": [ - "chttp2_batch_requests", - "chttp2_offload_on_rst_stream", - "lazier_stream_updates", "overload_protection", "write_size_cap", "write_size_policy", diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc index a1e52fab67b92..b75d792e5721e 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc @@ -503,10 +503,8 @@ static void read_channel_args(grpc_chttp2_transport* t, if (max_requests_per_read.has_value()) { t->max_requests_per_read = grpc_core::Clamp(*max_requests_per_read, 1, 10000); - } else if (grpc_core::IsChttp2BatchRequestsEnabled()) { - t->max_requests_per_read = 32; } else { - t->max_requests_per_read = std::numeric_limits::max(); + t->max_requests_per_read = 32; } if (channel_args.GetBool(GRPC_ARG_ENABLE_CHANNELZ) @@ -523,8 +521,8 @@ static void read_channel_args(grpc_chttp2_transport* t, t->ack_pings = channel_args.GetBool("grpc.http2.ack_pings").value_or(true); - t->allow_tarpit = channel_args.GetBool(GRPC_ARG_HTTP_ALLOW_TARPIT) - .value_or(grpc_core::IsTarpitEnabled()); + t->allow_tarpit = + channel_args.GetBool(GRPC_ARG_HTTP_ALLOW_TARPIT).value_or(true); t->min_tarpit_duration_ms = channel_args .GetDurationFromIntMillis(GRPC_ARG_HTTP_TARPIT_MIN_DURATION_MS) diff --git a/src/core/ext/transport/chttp2/transport/flow_control.cc b/src/core/ext/transport/chttp2/transport/flow_control.cc index c7d1eff946f02..986c62bc427e5 100644 --- a/src/core/ext/transport/chttp2/transport/flow_control.cc +++ b/src/core/ext/transport/chttp2/transport/flow_control.cc @@ -422,23 +422,9 @@ FlowControlAction StreamFlowControl::UpdateAction(FlowControlAction action) { } // min_progress_size_ > 0 means we have a reader ready to read. if (min_progress_size_ > 0) { - if (IsLazierStreamUpdatesEnabled()) { - if (announced_window_delta_ <= - -static_cast(tfc_->sent_init_window()) / 2) { - urgency = FlowControlAction::Urgency::UPDATE_IMMEDIATELY; - } - } else { - // If we're into initial window to receive that data we should wake up - // and send an update. - if (announced_window_delta_ < 0) { - urgency = FlowControlAction::Urgency::UPDATE_IMMEDIATELY; - } else if (announced_window_delta_ == 0 && - tfc_->queued_init_window() == 0) { - // Special case when initial window size is zero, meaning that - // announced_window_delta cannot become negative (it may already be so - // however). - urgency = FlowControlAction::Urgency::UPDATE_IMMEDIATELY; - } + if (announced_window_delta_ <= + -static_cast(tfc_->sent_init_window()) / 2) { + urgency = FlowControlAction::Urgency::UPDATE_IMMEDIATELY; } } action.set_send_stream_update(urgency); diff --git a/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc b/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc index 6c3a56ef74fe5..71e5cd7098f89 100644 --- a/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc +++ b/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc @@ -126,7 +126,7 @@ grpc_error_handle grpc_chttp2_rst_stream_parser_parse(void* parser, grpc_core::StatusIntProperty::kHttp2Error, static_cast(reason)); } - if (grpc_core::IsPingOnRstStreamEnabled() && !t->is_client && + if (!t->is_client && absl::Bernoulli(t->bitgen, t->ping_on_rst_stream_percent / 100.0)) { ++t->num_pending_induced_frames; t->ping_callbacks.RequestPing(); diff --git a/src/core/ext/transport/chttp2/transport/parsing.cc b/src/core/ext/transport/chttp2/transport/parsing.cc index ade5363264a72..efa216fcf6e60 100644 --- a/src/core/ext/transport/chttp2/transport/parsing.cc +++ b/src/core/ext/transport/chttp2/transport/parsing.cc @@ -395,8 +395,7 @@ absl::variant grpc_chttp2_perform_read( } cur += t->incoming_frame_size; t->incoming_stream = nullptr; - if (t->incoming_frame_type == GRPC_CHTTP2_FRAME_RST_STREAM && - grpc_core::IsChttp2OffloadOnRstStreamEnabled()) { + if (t->incoming_frame_type == GRPC_CHTTP2_FRAME_RST_STREAM) { requests_started = std::numeric_limits::max(); } goto dts_fh_0; // loop @@ -702,8 +701,7 @@ static grpc_error_handle init_header_frame_parser(grpc_chttp2_transport* t, t, std::string(t->peer_string.as_string_view()).c_str(), t->incoming_stream_id, t->last_new_stream_id)); return init_header_skip_frame_parser(t, priority_type, is_eoh); - } else if (grpc_core::IsBlockExcessiveRequestsBeforeSettingsAckEnabled() && - t->num_incoming_streams_before_settings_ack == 0) { + } else if (t->num_incoming_streams_before_settings_ack == 0) { GRPC_CHTTP2_IF_TRACING(gpr_log( GPR_ERROR, "transport:%p SERVER peer:%s rejecting grpc_chttp2_stream id=%d, " diff --git a/src/core/ext/transport/chttp2/transport/writing.cc b/src/core/ext/transport/chttp2/transport/writing.cc index 1d168479985d7..c81f2cf28081d 100644 --- a/src/core/ext/transport/chttp2/transport/writing.cc +++ b/src/core/ext/transport/chttp2/transport/writing.cc @@ -280,8 +280,7 @@ class WriteContext { t_->settings[GRPC_LOCAL_SETTINGS], t_->force_send_settings, GRPC_CHTTP2_NUM_SETTINGS)); - if (grpc_core::IsSettingsTimeoutEnabled() && - t_->keepalive_timeout != grpc_core::Duration::Infinity()) { + if (t_->keepalive_timeout != grpc_core::Duration::Infinity()) { GPR_ASSERT( t_->settings_ack_watchdog == grpc_event_engine::experimental::EventEngine::TaskHandle::kInvalid); @@ -734,9 +733,7 @@ void grpc_chttp2_end_write(grpc_chttp2_transport* t, grpc_error_handle error) { t->keepalive_timeout != grpc_core::Duration::Infinity()) { // Set ping timeout after finishing write so we don't measure our own send // time. - const auto timeout = grpc_core::IsSeparatePingFromKeepaliveEnabled() - ? t->ping_timeout - : t->keepalive_timeout; + const auto timeout = t->ping_timeout; auto id = t->ping_callbacks.OnPingTimeout( timeout, t->event_engine.get(), [t = t->Ref()] { grpc_core::ApplicationCallbackExecCtx callback_exec_ctx; @@ -750,8 +747,7 @@ void grpc_chttp2_end_write(grpc_chttp2_transport* t, grpc_error_handle error) { id.value()); } - if (grpc_core::IsSeparatePingFromKeepaliveEnabled() && - t->keepalive_incoming_data_wanted && + if (t->keepalive_incoming_data_wanted && t->keepalive_timeout < t->ping_timeout && t->keepalive_ping_timeout_handle != grpc_event_engine::experimental::EventEngine::TaskHandle:: diff --git a/src/core/lib/experiments/experiments.cc b/src/core/lib/experiments/experiments.cc index 1e8c852545dda..d44fdac9f7216 100644 --- a/src/core/lib/experiments/experiments.cc +++ b/src/core/lib/experiments/experiments.cc @@ -24,10 +24,6 @@ #if defined(GRPC_CFSTREAM) namespace { -const char* const description_block_excessive_requests_before_settings_ack = - "If set, block excessive requests before receiving SETTINGS ACK."; -const char* const - additional_constraints_block_excessive_requests_before_settings_ack = "{}"; const char* const description_call_status_override_on_cancellation = "Avoid overriding call status of successfully finished calls if it races " "with cancellation."; @@ -41,21 +37,6 @@ const char* const description_client_idleness = const char* const additional_constraints_client_idleness = "{}"; const char* const description_client_privacy = "If set, client privacy"; const char* const additional_constraints_client_privacy = "{}"; -const char* const description_combiner_offload_to_event_engine = - "Offload Combiner work onto the EventEngine instead of the Executor."; -const char* const additional_constraints_combiner_offload_to_event_engine = - "{}"; -const char* const description_chttp2_batch_requests = - "Cap the number of requests received by one transport read prior to " - "offload."; -const char* const additional_constraints_chttp2_batch_requests = "{}"; -const uint8_t required_experiments_chttp2_batch_requests[] = { - static_cast(grpc_core::kExperimentIdCombinerOffloadToEventEngine)}; -const char* const description_chttp2_offload_on_rst_stream = - "Offload work on RST_STREAM."; -const char* const additional_constraints_chttp2_offload_on_rst_stream = "{}"; -const uint8_t required_experiments_chttp2_offload_on_rst_stream[] = { - static_cast(grpc_core::kExperimentIdCombinerOffloadToEventEngine)}; const char* const description_event_engine_client = "Use EventEngine clients instead of iomgr's grpc_tcp_client"; const char* const additional_constraints_event_engine_client = "{}"; @@ -79,10 +60,6 @@ const char* const description_keepalive_server_fix = "Allows overriding keepalive_permit_without_calls for servers. Refer " "https://github.com/grpc/grpc/pull/33917 for more information."; const char* const additional_constraints_keepalive_server_fix = "{}"; -const char* const description_lazier_stream_updates = - "Allow streams to consume up to 50% of the incoming window before we force " - "send a flow control update."; -const char* const additional_constraints_lazier_stream_updates = "{}"; const char* const description_memory_pressure_controller = "New memory pressure controller"; const char* const additional_constraints_memory_pressure_controller = "{}"; @@ -112,10 +89,6 @@ const char* const additional_constraints_pending_queue_cap = "{}"; const char* const description_pick_first_happy_eyeballs = "Use Happy Eyeballs in pick_first."; const char* const additional_constraints_pick_first_happy_eyeballs = "{}"; -const char* const description_ping_on_rst_stream = - "Send a ping on receiving some RST_STREAM frames on the server (proportion " - "configurable via grpc.http2.ping_on_rst_stream_percent channel arg)."; -const char* const additional_constraints_ping_on_rst_stream = "{}"; const char* const description_promise_based_client_call = "If set, use the new gRPC promise based call code when it's appropriate " "(ie when all filters in a stack are promise based)"; @@ -127,8 +100,6 @@ const char* const description_promise_based_server_call = "If set, use the new gRPC promise based call code when it's appropriate " "(ie when all filters in a stack are promise based)"; const char* const additional_constraints_promise_based_server_call = "{}"; -const uint8_t required_experiments_promise_based_server_call[] = { - static_cast(grpc_core::kExperimentIdLazierStreamUpdates)}; const char* const description_red_max_concurrent_streams = "Perform random early rejection of requests that would exceed a newly " "reduced MAX_CONCURRENT_STREAMS but are allowed by the current."; @@ -158,20 +129,8 @@ const char* const description_schedule_cancellation_over_write = "Allow cancellation op to be scheduled over a write"; const char* const additional_constraints_schedule_cancellation_over_write = "{}"; -const char* const description_separate_ping_from_keepalive = - "Keep a different keepalive timeout (resolution is seeing data after " - "sending a ping) from a ping timeout (resolution is getting a ping ack " - "after sending a ping) The first can be short and determines liveness. The " - "second can be longer and determines protocol correctness."; -const char* const additional_constraints_separate_ping_from_keepalive = "{}"; const char* const description_server_privacy = "If set, server privacy"; const char* const additional_constraints_server_privacy = "{}"; -const char* const description_settings_timeout = - "If set, use the settings timeout to send settings frame to the peer."; -const char* const additional_constraints_settings_timeout = "{}"; -const char* const description_tarpit = - "If set, tarpit invalid requests for some amount of time"; -const char* const additional_constraints_tarpit = "{}"; const char* const description_tcp_frame_size_tuning = "If set, enables TCP to use RPC size estimation made by higher layers. TCP " "would not indicate completion of a read operation until a specified " @@ -188,10 +147,6 @@ const char* const description_unconstrained_max_quota_buffer_size = "Discard the cap on the max free pool size for one memory allocator"; const char* const additional_constraints_unconstrained_max_quota_buffer_size = "{}"; -const char* const description_uniquely_unowned = - "Ensure HPACK table takes a unique copy of data when parsing unknown " - "metadata"; -const char* const additional_constraints_uniquely_unowned = "{}"; const char* const description_work_serializer_clears_time_cache = "Have the work serializer clear the time cache when it dispatches work."; const char* const additional_constraints_work_serializer_clears_time_cache = @@ -223,10 +178,6 @@ const bool kDefaultForDebugOnly = true; namespace grpc_core { const ExperimentMetadata g_experiment_metadata[] = { - {"block_excessive_requests_before_settings_ack", - description_block_excessive_requests_before_settings_ack, - additional_constraints_block_excessive_requests_before_settings_ack, - nullptr, 0, true, true}, {"call_status_override_on_cancellation", description_call_status_override_on_cancellation, additional_constraints_call_status_override_on_cancellation, nullptr, 0, @@ -237,16 +188,6 @@ const ExperimentMetadata g_experiment_metadata[] = { additional_constraints_client_idleness, nullptr, 0, true, true}, {"client_privacy", description_client_privacy, additional_constraints_client_privacy, nullptr, 0, false, false}, - {"combiner_offload_to_event_engine", - description_combiner_offload_to_event_engine, - additional_constraints_combiner_offload_to_event_engine, nullptr, 0, true, - true}, - {"chttp2_batch_requests", description_chttp2_batch_requests, - additional_constraints_chttp2_batch_requests, - required_experiments_chttp2_batch_requests, 1, true, true}, - {"chttp2_offload_on_rst_stream", description_chttp2_offload_on_rst_stream, - additional_constraints_chttp2_offload_on_rst_stream, - required_experiments_chttp2_offload_on_rst_stream, 1, true, true}, {"event_engine_client", description_event_engine_client, additional_constraints_event_engine_client, nullptr, 0, false, true}, {"event_engine_dns", description_event_engine_dns, @@ -261,8 +202,6 @@ const ExperimentMetadata g_experiment_metadata[] = { additional_constraints_keepalive_fix, nullptr, 0, false, false}, {"keepalive_server_fix", description_keepalive_server_fix, additional_constraints_keepalive_server_fix, nullptr, 0, false, false}, - {"lazier_stream_updates", description_lazier_stream_updates, - additional_constraints_lazier_stream_updates, nullptr, 0, true, true}, {"memory_pressure_controller", description_memory_pressure_controller, additional_constraints_memory_pressure_controller, nullptr, 0, false, true}, @@ -278,8 +217,6 @@ const ExperimentMetadata g_experiment_metadata[] = { additional_constraints_pending_queue_cap, nullptr, 0, true, true}, {"pick_first_happy_eyeballs", description_pick_first_happy_eyeballs, additional_constraints_pick_first_happy_eyeballs, nullptr, 0, true, true}, - {"ping_on_rst_stream", description_ping_on_rst_stream, - additional_constraints_ping_on_rst_stream, nullptr, 0, true, true}, {"promise_based_client_call", description_promise_based_client_call, additional_constraints_promise_based_client_call, nullptr, 0, false, true}, {"promise_based_inproc_transport", @@ -287,8 +224,7 @@ const ExperimentMetadata g_experiment_metadata[] = { additional_constraints_promise_based_inproc_transport, nullptr, 0, false, false}, {"promise_based_server_call", description_promise_based_server_call, - additional_constraints_promise_based_server_call, - required_experiments_promise_based_server_call, 1, false, true}, + additional_constraints_promise_based_server_call, nullptr, 0, false, true}, {"red_max_concurrent_streams", description_red_max_concurrent_streams, additional_constraints_red_max_concurrent_streams, nullptr, 0, false, true}, @@ -311,15 +247,8 @@ const ExperimentMetadata g_experiment_metadata[] = { description_schedule_cancellation_over_write, additional_constraints_schedule_cancellation_over_write, nullptr, 0, false, true}, - {"separate_ping_from_keepalive", description_separate_ping_from_keepalive, - additional_constraints_separate_ping_from_keepalive, nullptr, 0, true, - true}, {"server_privacy", description_server_privacy, additional_constraints_server_privacy, nullptr, 0, false, false}, - {"settings_timeout", description_settings_timeout, - additional_constraints_settings_timeout, nullptr, 0, true, true}, - {"tarpit", description_tarpit, additional_constraints_tarpit, nullptr, 0, - true, true}, {"tcp_frame_size_tuning", description_tcp_frame_size_tuning, additional_constraints_tcp_frame_size_tuning, nullptr, 0, false, true}, {"tcp_rcv_lowat", description_tcp_rcv_lowat, @@ -330,8 +259,6 @@ const ExperimentMetadata g_experiment_metadata[] = { description_unconstrained_max_quota_buffer_size, additional_constraints_unconstrained_max_quota_buffer_size, nullptr, 0, false, true}, - {"uniquely_unowned", description_uniquely_unowned, - additional_constraints_uniquely_unowned, nullptr, 0, true, true}, {"work_serializer_clears_time_cache", description_work_serializer_clears_time_cache, additional_constraints_work_serializer_clears_time_cache, nullptr, 0, true, @@ -351,10 +278,6 @@ const ExperimentMetadata g_experiment_metadata[] = { #elif defined(GPR_WINDOWS) namespace { -const char* const description_block_excessive_requests_before_settings_ack = - "If set, block excessive requests before receiving SETTINGS ACK."; -const char* const - additional_constraints_block_excessive_requests_before_settings_ack = "{}"; const char* const description_call_status_override_on_cancellation = "Avoid overriding call status of successfully finished calls if it races " "with cancellation."; @@ -368,21 +291,6 @@ const char* const description_client_idleness = const char* const additional_constraints_client_idleness = "{}"; const char* const description_client_privacy = "If set, client privacy"; const char* const additional_constraints_client_privacy = "{}"; -const char* const description_combiner_offload_to_event_engine = - "Offload Combiner work onto the EventEngine instead of the Executor."; -const char* const additional_constraints_combiner_offload_to_event_engine = - "{}"; -const char* const description_chttp2_batch_requests = - "Cap the number of requests received by one transport read prior to " - "offload."; -const char* const additional_constraints_chttp2_batch_requests = "{}"; -const uint8_t required_experiments_chttp2_batch_requests[] = { - static_cast(grpc_core::kExperimentIdCombinerOffloadToEventEngine)}; -const char* const description_chttp2_offload_on_rst_stream = - "Offload work on RST_STREAM."; -const char* const additional_constraints_chttp2_offload_on_rst_stream = "{}"; -const uint8_t required_experiments_chttp2_offload_on_rst_stream[] = { - static_cast(grpc_core::kExperimentIdCombinerOffloadToEventEngine)}; const char* const description_event_engine_client = "Use EventEngine clients instead of iomgr's grpc_tcp_client"; const char* const additional_constraints_event_engine_client = "{}"; @@ -406,10 +314,6 @@ const char* const description_keepalive_server_fix = "Allows overriding keepalive_permit_without_calls for servers. Refer " "https://github.com/grpc/grpc/pull/33917 for more information."; const char* const additional_constraints_keepalive_server_fix = "{}"; -const char* const description_lazier_stream_updates = - "Allow streams to consume up to 50% of the incoming window before we force " - "send a flow control update."; -const char* const additional_constraints_lazier_stream_updates = "{}"; const char* const description_memory_pressure_controller = "New memory pressure controller"; const char* const additional_constraints_memory_pressure_controller = "{}"; @@ -439,10 +343,6 @@ const char* const additional_constraints_pending_queue_cap = "{}"; const char* const description_pick_first_happy_eyeballs = "Use Happy Eyeballs in pick_first."; const char* const additional_constraints_pick_first_happy_eyeballs = "{}"; -const char* const description_ping_on_rst_stream = - "Send a ping on receiving some RST_STREAM frames on the server (proportion " - "configurable via grpc.http2.ping_on_rst_stream_percent channel arg)."; -const char* const additional_constraints_ping_on_rst_stream = "{}"; const char* const description_promise_based_client_call = "If set, use the new gRPC promise based call code when it's appropriate " "(ie when all filters in a stack are promise based)"; @@ -454,8 +354,6 @@ const char* const description_promise_based_server_call = "If set, use the new gRPC promise based call code when it's appropriate " "(ie when all filters in a stack are promise based)"; const char* const additional_constraints_promise_based_server_call = "{}"; -const uint8_t required_experiments_promise_based_server_call[] = { - static_cast(grpc_core::kExperimentIdLazierStreamUpdates)}; const char* const description_red_max_concurrent_streams = "Perform random early rejection of requests that would exceed a newly " "reduced MAX_CONCURRENT_STREAMS but are allowed by the current."; @@ -485,20 +383,8 @@ const char* const description_schedule_cancellation_over_write = "Allow cancellation op to be scheduled over a write"; const char* const additional_constraints_schedule_cancellation_over_write = "{}"; -const char* const description_separate_ping_from_keepalive = - "Keep a different keepalive timeout (resolution is seeing data after " - "sending a ping) from a ping timeout (resolution is getting a ping ack " - "after sending a ping) The first can be short and determines liveness. The " - "second can be longer and determines protocol correctness."; -const char* const additional_constraints_separate_ping_from_keepalive = "{}"; const char* const description_server_privacy = "If set, server privacy"; const char* const additional_constraints_server_privacy = "{}"; -const char* const description_settings_timeout = - "If set, use the settings timeout to send settings frame to the peer."; -const char* const additional_constraints_settings_timeout = "{}"; -const char* const description_tarpit = - "If set, tarpit invalid requests for some amount of time"; -const char* const additional_constraints_tarpit = "{}"; const char* const description_tcp_frame_size_tuning = "If set, enables TCP to use RPC size estimation made by higher layers. TCP " "would not indicate completion of a read operation until a specified " @@ -515,10 +401,6 @@ const char* const description_unconstrained_max_quota_buffer_size = "Discard the cap on the max free pool size for one memory allocator"; const char* const additional_constraints_unconstrained_max_quota_buffer_size = "{}"; -const char* const description_uniquely_unowned = - "Ensure HPACK table takes a unique copy of data when parsing unknown " - "metadata"; -const char* const additional_constraints_uniquely_unowned = "{}"; const char* const description_work_serializer_clears_time_cache = "Have the work serializer clear the time cache when it dispatches work."; const char* const additional_constraints_work_serializer_clears_time_cache = @@ -550,10 +432,6 @@ const bool kDefaultForDebugOnly = true; namespace grpc_core { const ExperimentMetadata g_experiment_metadata[] = { - {"block_excessive_requests_before_settings_ack", - description_block_excessive_requests_before_settings_ack, - additional_constraints_block_excessive_requests_before_settings_ack, - nullptr, 0, true, true}, {"call_status_override_on_cancellation", description_call_status_override_on_cancellation, additional_constraints_call_status_override_on_cancellation, nullptr, 0, @@ -564,16 +442,6 @@ const ExperimentMetadata g_experiment_metadata[] = { additional_constraints_client_idleness, nullptr, 0, true, true}, {"client_privacy", description_client_privacy, additional_constraints_client_privacy, nullptr, 0, false, false}, - {"combiner_offload_to_event_engine", - description_combiner_offload_to_event_engine, - additional_constraints_combiner_offload_to_event_engine, nullptr, 0, true, - true}, - {"chttp2_batch_requests", description_chttp2_batch_requests, - additional_constraints_chttp2_batch_requests, - required_experiments_chttp2_batch_requests, 1, true, true}, - {"chttp2_offload_on_rst_stream", description_chttp2_offload_on_rst_stream, - additional_constraints_chttp2_offload_on_rst_stream, - required_experiments_chttp2_offload_on_rst_stream, 1, true, true}, {"event_engine_client", description_event_engine_client, additional_constraints_event_engine_client, nullptr, 0, false, true}, {"event_engine_dns", description_event_engine_dns, @@ -588,8 +456,6 @@ const ExperimentMetadata g_experiment_metadata[] = { additional_constraints_keepalive_fix, nullptr, 0, false, false}, {"keepalive_server_fix", description_keepalive_server_fix, additional_constraints_keepalive_server_fix, nullptr, 0, false, false}, - {"lazier_stream_updates", description_lazier_stream_updates, - additional_constraints_lazier_stream_updates, nullptr, 0, true, true}, {"memory_pressure_controller", description_memory_pressure_controller, additional_constraints_memory_pressure_controller, nullptr, 0, false, true}, @@ -605,8 +471,6 @@ const ExperimentMetadata g_experiment_metadata[] = { additional_constraints_pending_queue_cap, nullptr, 0, true, true}, {"pick_first_happy_eyeballs", description_pick_first_happy_eyeballs, additional_constraints_pick_first_happy_eyeballs, nullptr, 0, true, true}, - {"ping_on_rst_stream", description_ping_on_rst_stream, - additional_constraints_ping_on_rst_stream, nullptr, 0, true, true}, {"promise_based_client_call", description_promise_based_client_call, additional_constraints_promise_based_client_call, nullptr, 0, false, true}, {"promise_based_inproc_transport", @@ -614,8 +478,7 @@ const ExperimentMetadata g_experiment_metadata[] = { additional_constraints_promise_based_inproc_transport, nullptr, 0, false, false}, {"promise_based_server_call", description_promise_based_server_call, - additional_constraints_promise_based_server_call, - required_experiments_promise_based_server_call, 1, false, true}, + additional_constraints_promise_based_server_call, nullptr, 0, false, true}, {"red_max_concurrent_streams", description_red_max_concurrent_streams, additional_constraints_red_max_concurrent_streams, nullptr, 0, false, true}, @@ -638,15 +501,8 @@ const ExperimentMetadata g_experiment_metadata[] = { description_schedule_cancellation_over_write, additional_constraints_schedule_cancellation_over_write, nullptr, 0, false, true}, - {"separate_ping_from_keepalive", description_separate_ping_from_keepalive, - additional_constraints_separate_ping_from_keepalive, nullptr, 0, true, - true}, {"server_privacy", description_server_privacy, additional_constraints_server_privacy, nullptr, 0, false, false}, - {"settings_timeout", description_settings_timeout, - additional_constraints_settings_timeout, nullptr, 0, true, true}, - {"tarpit", description_tarpit, additional_constraints_tarpit, nullptr, 0, - true, true}, {"tcp_frame_size_tuning", description_tcp_frame_size_tuning, additional_constraints_tcp_frame_size_tuning, nullptr, 0, false, true}, {"tcp_rcv_lowat", description_tcp_rcv_lowat, @@ -657,8 +513,6 @@ const ExperimentMetadata g_experiment_metadata[] = { description_unconstrained_max_quota_buffer_size, additional_constraints_unconstrained_max_quota_buffer_size, nullptr, 0, false, true}, - {"uniquely_unowned", description_uniquely_unowned, - additional_constraints_uniquely_unowned, nullptr, 0, true, true}, {"work_serializer_clears_time_cache", description_work_serializer_clears_time_cache, additional_constraints_work_serializer_clears_time_cache, nullptr, 0, true, @@ -678,10 +532,6 @@ const ExperimentMetadata g_experiment_metadata[] = { #else namespace { -const char* const description_block_excessive_requests_before_settings_ack = - "If set, block excessive requests before receiving SETTINGS ACK."; -const char* const - additional_constraints_block_excessive_requests_before_settings_ack = "{}"; const char* const description_call_status_override_on_cancellation = "Avoid overriding call status of successfully finished calls if it races " "with cancellation."; @@ -695,21 +545,6 @@ const char* const description_client_idleness = const char* const additional_constraints_client_idleness = "{}"; const char* const description_client_privacy = "If set, client privacy"; const char* const additional_constraints_client_privacy = "{}"; -const char* const description_combiner_offload_to_event_engine = - "Offload Combiner work onto the EventEngine instead of the Executor."; -const char* const additional_constraints_combiner_offload_to_event_engine = - "{}"; -const char* const description_chttp2_batch_requests = - "Cap the number of requests received by one transport read prior to " - "offload."; -const char* const additional_constraints_chttp2_batch_requests = "{}"; -const uint8_t required_experiments_chttp2_batch_requests[] = { - static_cast(grpc_core::kExperimentIdCombinerOffloadToEventEngine)}; -const char* const description_chttp2_offload_on_rst_stream = - "Offload work on RST_STREAM."; -const char* const additional_constraints_chttp2_offload_on_rst_stream = "{}"; -const uint8_t required_experiments_chttp2_offload_on_rst_stream[] = { - static_cast(grpc_core::kExperimentIdCombinerOffloadToEventEngine)}; const char* const description_event_engine_client = "Use EventEngine clients instead of iomgr's grpc_tcp_client"; const char* const additional_constraints_event_engine_client = "{}"; @@ -733,10 +568,6 @@ const char* const description_keepalive_server_fix = "Allows overriding keepalive_permit_without_calls for servers. Refer " "https://github.com/grpc/grpc/pull/33917 for more information."; const char* const additional_constraints_keepalive_server_fix = "{}"; -const char* const description_lazier_stream_updates = - "Allow streams to consume up to 50% of the incoming window before we force " - "send a flow control update."; -const char* const additional_constraints_lazier_stream_updates = "{}"; const char* const description_memory_pressure_controller = "New memory pressure controller"; const char* const additional_constraints_memory_pressure_controller = "{}"; @@ -766,10 +597,6 @@ const char* const additional_constraints_pending_queue_cap = "{}"; const char* const description_pick_first_happy_eyeballs = "Use Happy Eyeballs in pick_first."; const char* const additional_constraints_pick_first_happy_eyeballs = "{}"; -const char* const description_ping_on_rst_stream = - "Send a ping on receiving some RST_STREAM frames on the server (proportion " - "configurable via grpc.http2.ping_on_rst_stream_percent channel arg)."; -const char* const additional_constraints_ping_on_rst_stream = "{}"; const char* const description_promise_based_client_call = "If set, use the new gRPC promise based call code when it's appropriate " "(ie when all filters in a stack are promise based)"; @@ -781,8 +608,6 @@ const char* const description_promise_based_server_call = "If set, use the new gRPC promise based call code when it's appropriate " "(ie when all filters in a stack are promise based)"; const char* const additional_constraints_promise_based_server_call = "{}"; -const uint8_t required_experiments_promise_based_server_call[] = { - static_cast(grpc_core::kExperimentIdLazierStreamUpdates)}; const char* const description_red_max_concurrent_streams = "Perform random early rejection of requests that would exceed a newly " "reduced MAX_CONCURRENT_STREAMS but are allowed by the current."; @@ -812,20 +637,8 @@ const char* const description_schedule_cancellation_over_write = "Allow cancellation op to be scheduled over a write"; const char* const additional_constraints_schedule_cancellation_over_write = "{}"; -const char* const description_separate_ping_from_keepalive = - "Keep a different keepalive timeout (resolution is seeing data after " - "sending a ping) from a ping timeout (resolution is getting a ping ack " - "after sending a ping) The first can be short and determines liveness. The " - "second can be longer and determines protocol correctness."; -const char* const additional_constraints_separate_ping_from_keepalive = "{}"; const char* const description_server_privacy = "If set, server privacy"; const char* const additional_constraints_server_privacy = "{}"; -const char* const description_settings_timeout = - "If set, use the settings timeout to send settings frame to the peer."; -const char* const additional_constraints_settings_timeout = "{}"; -const char* const description_tarpit = - "If set, tarpit invalid requests for some amount of time"; -const char* const additional_constraints_tarpit = "{}"; const char* const description_tcp_frame_size_tuning = "If set, enables TCP to use RPC size estimation made by higher layers. TCP " "would not indicate completion of a read operation until a specified " @@ -842,10 +655,6 @@ const char* const description_unconstrained_max_quota_buffer_size = "Discard the cap on the max free pool size for one memory allocator"; const char* const additional_constraints_unconstrained_max_quota_buffer_size = "{}"; -const char* const description_uniquely_unowned = - "Ensure HPACK table takes a unique copy of data when parsing unknown " - "metadata"; -const char* const additional_constraints_uniquely_unowned = "{}"; const char* const description_work_serializer_clears_time_cache = "Have the work serializer clear the time cache when it dispatches work."; const char* const additional_constraints_work_serializer_clears_time_cache = @@ -877,10 +686,6 @@ const bool kDefaultForDebugOnly = true; namespace grpc_core { const ExperimentMetadata g_experiment_metadata[] = { - {"block_excessive_requests_before_settings_ack", - description_block_excessive_requests_before_settings_ack, - additional_constraints_block_excessive_requests_before_settings_ack, - nullptr, 0, true, true}, {"call_status_override_on_cancellation", description_call_status_override_on_cancellation, additional_constraints_call_status_override_on_cancellation, nullptr, 0, @@ -891,16 +696,6 @@ const ExperimentMetadata g_experiment_metadata[] = { additional_constraints_client_idleness, nullptr, 0, true, true}, {"client_privacy", description_client_privacy, additional_constraints_client_privacy, nullptr, 0, false, false}, - {"combiner_offload_to_event_engine", - description_combiner_offload_to_event_engine, - additional_constraints_combiner_offload_to_event_engine, nullptr, 0, true, - true}, - {"chttp2_batch_requests", description_chttp2_batch_requests, - additional_constraints_chttp2_batch_requests, - required_experiments_chttp2_batch_requests, 1, true, true}, - {"chttp2_offload_on_rst_stream", description_chttp2_offload_on_rst_stream, - additional_constraints_chttp2_offload_on_rst_stream, - required_experiments_chttp2_offload_on_rst_stream, 1, true, true}, {"event_engine_client", description_event_engine_client, additional_constraints_event_engine_client, nullptr, 0, false, true}, {"event_engine_dns", description_event_engine_dns, @@ -915,8 +710,6 @@ const ExperimentMetadata g_experiment_metadata[] = { additional_constraints_keepalive_fix, nullptr, 0, false, false}, {"keepalive_server_fix", description_keepalive_server_fix, additional_constraints_keepalive_server_fix, nullptr, 0, false, false}, - {"lazier_stream_updates", description_lazier_stream_updates, - additional_constraints_lazier_stream_updates, nullptr, 0, true, true}, {"memory_pressure_controller", description_memory_pressure_controller, additional_constraints_memory_pressure_controller, nullptr, 0, false, true}, @@ -932,8 +725,6 @@ const ExperimentMetadata g_experiment_metadata[] = { additional_constraints_pending_queue_cap, nullptr, 0, true, true}, {"pick_first_happy_eyeballs", description_pick_first_happy_eyeballs, additional_constraints_pick_first_happy_eyeballs, nullptr, 0, true, true}, - {"ping_on_rst_stream", description_ping_on_rst_stream, - additional_constraints_ping_on_rst_stream, nullptr, 0, true, true}, {"promise_based_client_call", description_promise_based_client_call, additional_constraints_promise_based_client_call, nullptr, 0, false, true}, {"promise_based_inproc_transport", @@ -941,8 +732,7 @@ const ExperimentMetadata g_experiment_metadata[] = { additional_constraints_promise_based_inproc_transport, nullptr, 0, false, false}, {"promise_based_server_call", description_promise_based_server_call, - additional_constraints_promise_based_server_call, - required_experiments_promise_based_server_call, 1, false, true}, + additional_constraints_promise_based_server_call, nullptr, 0, false, true}, {"red_max_concurrent_streams", description_red_max_concurrent_streams, additional_constraints_red_max_concurrent_streams, nullptr, 0, false, true}, @@ -965,15 +755,8 @@ const ExperimentMetadata g_experiment_metadata[] = { description_schedule_cancellation_over_write, additional_constraints_schedule_cancellation_over_write, nullptr, 0, false, true}, - {"separate_ping_from_keepalive", description_separate_ping_from_keepalive, - additional_constraints_separate_ping_from_keepalive, nullptr, 0, true, - true}, {"server_privacy", description_server_privacy, additional_constraints_server_privacy, nullptr, 0, false, false}, - {"settings_timeout", description_settings_timeout, - additional_constraints_settings_timeout, nullptr, 0, true, true}, - {"tarpit", description_tarpit, additional_constraints_tarpit, nullptr, 0, - true, true}, {"tcp_frame_size_tuning", description_tcp_frame_size_tuning, additional_constraints_tcp_frame_size_tuning, nullptr, 0, false, true}, {"tcp_rcv_lowat", description_tcp_rcv_lowat, @@ -984,8 +767,6 @@ const ExperimentMetadata g_experiment_metadata[] = { description_unconstrained_max_quota_buffer_size, additional_constraints_unconstrained_max_quota_buffer_size, nullptr, 0, false, true}, - {"uniquely_unowned", description_uniquely_unowned, - additional_constraints_uniquely_unowned, nullptr, 0, true, true}, {"work_serializer_clears_time_cache", description_work_serializer_clears_time_cache, additional_constraints_work_serializer_clears_time_cache, nullptr, 0, true, diff --git a/src/core/lib/experiments/experiments.h b/src/core/lib/experiments/experiments.h index 60db6dfc1f36d..1b023557b33d0 100644 --- a/src/core/lib/experiments/experiments.h +++ b/src/core/lib/experiments/experiments.h @@ -57,8 +57,6 @@ namespace grpc_core { #ifdef GRPC_EXPERIMENTS_ARE_FINAL #if defined(GRPC_CFSTREAM) -#define GRPC_EXPERIMENT_IS_INCLUDED_BLOCK_EXCESSIVE_REQUESTS_BEFORE_SETTINGS_ACK -inline bool IsBlockExcessiveRequestsBeforeSettingsAckEnabled() { return true; } #ifndef NDEBUG #define GRPC_EXPERIMENT_IS_INCLUDED_CALL_STATUS_OVERRIDE_ON_CANCELLATION #endif @@ -73,12 +71,6 @@ inline bool IsCanaryClientPrivacyEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_CLIENT_IDLENESS inline bool IsClientIdlenessEnabled() { return true; } inline bool IsClientPrivacyEnabled() { return false; } -#define GRPC_EXPERIMENT_IS_INCLUDED_COMBINER_OFFLOAD_TO_EVENT_ENGINE -inline bool IsCombinerOffloadToEventEngineEnabled() { return true; } -#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_BATCH_REQUESTS -inline bool IsChttp2BatchRequestsEnabled() { return true; } -#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_OFFLOAD_ON_RST_STREAM -inline bool IsChttp2OffloadOnRstStreamEnabled() { return true; } inline bool IsEventEngineClientEnabled() { return false; } inline bool IsEventEngineDnsEnabled() { return false; } inline bool IsEventEngineListenerEnabled() { return false; } @@ -87,8 +79,6 @@ inline bool IsFreeLargeAllocatorEnabled() { return false; } inline bool IsHttp2StatsFixEnabled() { return true; } inline bool IsKeepaliveFixEnabled() { return false; } inline bool IsKeepaliveServerFixEnabled() { return false; } -#define GRPC_EXPERIMENT_IS_INCLUDED_LAZIER_STREAM_UPDATES -inline bool IsLazierStreamUpdatesEnabled() { return true; } inline bool IsMemoryPressureControllerEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_MONITORING_EXPERIMENT inline bool IsMonitoringExperimentEnabled() { return true; } @@ -100,8 +90,6 @@ inline bool IsPeerStateBasedFramingEnabled() { return false; } inline bool IsPendingQueueCapEnabled() { return true; } #define GRPC_EXPERIMENT_IS_INCLUDED_PICK_FIRST_HAPPY_EYEBALLS inline bool IsPickFirstHappyEyeballsEnabled() { return true; } -#define GRPC_EXPERIMENT_IS_INCLUDED_PING_ON_RST_STREAM -inline bool IsPingOnRstStreamEnabled() { return true; } inline bool IsPromiseBasedClientCallEnabled() { return false; } inline bool IsPromiseBasedInprocTransportEnabled() { return false; } inline bool IsPromiseBasedServerCallEnabled() { return false; } @@ -114,19 +102,11 @@ inline bool IsRfcMaxConcurrentStreamsEnabled() { return false; } inline bool IsRoundRobinDelegateToPickFirstEnabled() { return true; } inline bool IsRstpitEnabled() { return false; } inline bool IsScheduleCancellationOverWriteEnabled() { return false; } -#define GRPC_EXPERIMENT_IS_INCLUDED_SEPARATE_PING_FROM_KEEPALIVE -inline bool IsSeparatePingFromKeepaliveEnabled() { return true; } inline bool IsServerPrivacyEnabled() { return false; } -#define GRPC_EXPERIMENT_IS_INCLUDED_SETTINGS_TIMEOUT -inline bool IsSettingsTimeoutEnabled() { return true; } -#define GRPC_EXPERIMENT_IS_INCLUDED_TARPIT -inline bool IsTarpitEnabled() { return true; } inline bool IsTcpFrameSizeTuningEnabled() { return false; } inline bool IsTcpRcvLowatEnabled() { return false; } inline bool IsTraceRecordCallopsEnabled() { return false; } inline bool IsUnconstrainedMaxQuotaBufferSizeEnabled() { return false; } -#define GRPC_EXPERIMENT_IS_INCLUDED_UNIQUELY_UNOWNED -inline bool IsUniquelyUnownedEnabled() { return true; } #define GRPC_EXPERIMENT_IS_INCLUDED_WORK_SERIALIZER_CLEARS_TIME_CACHE inline bool IsWorkSerializerClearsTimeCacheEnabled() { return true; } inline bool IsWorkSerializerDispatchEnabled() { return false; } @@ -138,8 +118,6 @@ inline bool IsWriteSizeCapEnabled() { return true; } inline bool IsWrrDelegateToPickFirstEnabled() { return true; } #elif defined(GPR_WINDOWS) -#define GRPC_EXPERIMENT_IS_INCLUDED_BLOCK_EXCESSIVE_REQUESTS_BEFORE_SETTINGS_ACK -inline bool IsBlockExcessiveRequestsBeforeSettingsAckEnabled() { return true; } #ifndef NDEBUG #define GRPC_EXPERIMENT_IS_INCLUDED_CALL_STATUS_OVERRIDE_ON_CANCELLATION #endif @@ -154,12 +132,6 @@ inline bool IsCanaryClientPrivacyEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_CLIENT_IDLENESS inline bool IsClientIdlenessEnabled() { return true; } inline bool IsClientPrivacyEnabled() { return false; } -#define GRPC_EXPERIMENT_IS_INCLUDED_COMBINER_OFFLOAD_TO_EVENT_ENGINE -inline bool IsCombinerOffloadToEventEngineEnabled() { return true; } -#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_BATCH_REQUESTS -inline bool IsChttp2BatchRequestsEnabled() { return true; } -#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_OFFLOAD_ON_RST_STREAM -inline bool IsChttp2OffloadOnRstStreamEnabled() { return true; } inline bool IsEventEngineClientEnabled() { return false; } inline bool IsEventEngineDnsEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_EVENT_ENGINE_LISTENER @@ -169,8 +141,6 @@ inline bool IsFreeLargeAllocatorEnabled() { return false; } inline bool IsHttp2StatsFixEnabled() { return true; } inline bool IsKeepaliveFixEnabled() { return false; } inline bool IsKeepaliveServerFixEnabled() { return false; } -#define GRPC_EXPERIMENT_IS_INCLUDED_LAZIER_STREAM_UPDATES -inline bool IsLazierStreamUpdatesEnabled() { return true; } inline bool IsMemoryPressureControllerEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_MONITORING_EXPERIMENT inline bool IsMonitoringExperimentEnabled() { return true; } @@ -182,8 +152,6 @@ inline bool IsPeerStateBasedFramingEnabled() { return false; } inline bool IsPendingQueueCapEnabled() { return true; } #define GRPC_EXPERIMENT_IS_INCLUDED_PICK_FIRST_HAPPY_EYEBALLS inline bool IsPickFirstHappyEyeballsEnabled() { return true; } -#define GRPC_EXPERIMENT_IS_INCLUDED_PING_ON_RST_STREAM -inline bool IsPingOnRstStreamEnabled() { return true; } inline bool IsPromiseBasedClientCallEnabled() { return false; } inline bool IsPromiseBasedInprocTransportEnabled() { return false; } inline bool IsPromiseBasedServerCallEnabled() { return false; } @@ -196,19 +164,11 @@ inline bool IsRfcMaxConcurrentStreamsEnabled() { return false; } inline bool IsRoundRobinDelegateToPickFirstEnabled() { return true; } inline bool IsRstpitEnabled() { return false; } inline bool IsScheduleCancellationOverWriteEnabled() { return false; } -#define GRPC_EXPERIMENT_IS_INCLUDED_SEPARATE_PING_FROM_KEEPALIVE -inline bool IsSeparatePingFromKeepaliveEnabled() { return true; } inline bool IsServerPrivacyEnabled() { return false; } -#define GRPC_EXPERIMENT_IS_INCLUDED_SETTINGS_TIMEOUT -inline bool IsSettingsTimeoutEnabled() { return true; } -#define GRPC_EXPERIMENT_IS_INCLUDED_TARPIT -inline bool IsTarpitEnabled() { return true; } inline bool IsTcpFrameSizeTuningEnabled() { return false; } inline bool IsTcpRcvLowatEnabled() { return false; } inline bool IsTraceRecordCallopsEnabled() { return false; } inline bool IsUnconstrainedMaxQuotaBufferSizeEnabled() { return false; } -#define GRPC_EXPERIMENT_IS_INCLUDED_UNIQUELY_UNOWNED -inline bool IsUniquelyUnownedEnabled() { return true; } #define GRPC_EXPERIMENT_IS_INCLUDED_WORK_SERIALIZER_CLEARS_TIME_CACHE inline bool IsWorkSerializerClearsTimeCacheEnabled() { return true; } inline bool IsWorkSerializerDispatchEnabled() { return false; } @@ -220,8 +180,6 @@ inline bool IsWriteSizeCapEnabled() { return true; } inline bool IsWrrDelegateToPickFirstEnabled() { return true; } #else -#define GRPC_EXPERIMENT_IS_INCLUDED_BLOCK_EXCESSIVE_REQUESTS_BEFORE_SETTINGS_ACK -inline bool IsBlockExcessiveRequestsBeforeSettingsAckEnabled() { return true; } #ifndef NDEBUG #define GRPC_EXPERIMENT_IS_INCLUDED_CALL_STATUS_OVERRIDE_ON_CANCELLATION #endif @@ -236,12 +194,6 @@ inline bool IsCanaryClientPrivacyEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_CLIENT_IDLENESS inline bool IsClientIdlenessEnabled() { return true; } inline bool IsClientPrivacyEnabled() { return false; } -#define GRPC_EXPERIMENT_IS_INCLUDED_COMBINER_OFFLOAD_TO_EVENT_ENGINE -inline bool IsCombinerOffloadToEventEngineEnabled() { return true; } -#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_BATCH_REQUESTS -inline bool IsChttp2BatchRequestsEnabled() { return true; } -#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_OFFLOAD_ON_RST_STREAM -inline bool IsChttp2OffloadOnRstStreamEnabled() { return true; } inline bool IsEventEngineClientEnabled() { return false; } inline bool IsEventEngineDnsEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_EVENT_ENGINE_LISTENER @@ -251,8 +203,6 @@ inline bool IsFreeLargeAllocatorEnabled() { return false; } inline bool IsHttp2StatsFixEnabled() { return true; } inline bool IsKeepaliveFixEnabled() { return false; } inline bool IsKeepaliveServerFixEnabled() { return false; } -#define GRPC_EXPERIMENT_IS_INCLUDED_LAZIER_STREAM_UPDATES -inline bool IsLazierStreamUpdatesEnabled() { return true; } inline bool IsMemoryPressureControllerEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_MONITORING_EXPERIMENT inline bool IsMonitoringExperimentEnabled() { return true; } @@ -264,8 +214,6 @@ inline bool IsPeerStateBasedFramingEnabled() { return false; } inline bool IsPendingQueueCapEnabled() { return true; } #define GRPC_EXPERIMENT_IS_INCLUDED_PICK_FIRST_HAPPY_EYEBALLS inline bool IsPickFirstHappyEyeballsEnabled() { return true; } -#define GRPC_EXPERIMENT_IS_INCLUDED_PING_ON_RST_STREAM -inline bool IsPingOnRstStreamEnabled() { return true; } inline bool IsPromiseBasedClientCallEnabled() { return false; } inline bool IsPromiseBasedInprocTransportEnabled() { return false; } inline bool IsPromiseBasedServerCallEnabled() { return false; } @@ -278,19 +226,11 @@ inline bool IsRfcMaxConcurrentStreamsEnabled() { return false; } inline bool IsRoundRobinDelegateToPickFirstEnabled() { return true; } inline bool IsRstpitEnabled() { return false; } inline bool IsScheduleCancellationOverWriteEnabled() { return false; } -#define GRPC_EXPERIMENT_IS_INCLUDED_SEPARATE_PING_FROM_KEEPALIVE -inline bool IsSeparatePingFromKeepaliveEnabled() { return true; } inline bool IsServerPrivacyEnabled() { return false; } -#define GRPC_EXPERIMENT_IS_INCLUDED_SETTINGS_TIMEOUT -inline bool IsSettingsTimeoutEnabled() { return true; } -#define GRPC_EXPERIMENT_IS_INCLUDED_TARPIT -inline bool IsTarpitEnabled() { return true; } inline bool IsTcpFrameSizeTuningEnabled() { return false; } inline bool IsTcpRcvLowatEnabled() { return false; } inline bool IsTraceRecordCallopsEnabled() { return false; } inline bool IsUnconstrainedMaxQuotaBufferSizeEnabled() { return false; } -#define GRPC_EXPERIMENT_IS_INCLUDED_UNIQUELY_UNOWNED -inline bool IsUniquelyUnownedEnabled() { return true; } #define GRPC_EXPERIMENT_IS_INCLUDED_WORK_SERIALIZER_CLEARS_TIME_CACHE inline bool IsWorkSerializerClearsTimeCacheEnabled() { return true; } inline bool IsWorkSerializerDispatchEnabled() { return false; } @@ -304,14 +244,10 @@ inline bool IsWrrDelegateToPickFirstEnabled() { return true; } #else enum ExperimentIds { - kExperimentIdBlockExcessiveRequestsBeforeSettingsAck, kExperimentIdCallStatusOverrideOnCancellation, kExperimentIdCanaryClientPrivacy, kExperimentIdClientIdleness, kExperimentIdClientPrivacy, - kExperimentIdCombinerOffloadToEventEngine, - kExperimentIdChttp2BatchRequests, - kExperimentIdChttp2OffloadOnRstStream, kExperimentIdEventEngineClient, kExperimentIdEventEngineDns, kExperimentIdEventEngineListener, @@ -319,7 +255,6 @@ enum ExperimentIds { kExperimentIdHttp2StatsFix, kExperimentIdKeepaliveFix, kExperimentIdKeepaliveServerFix, - kExperimentIdLazierStreamUpdates, kExperimentIdMemoryPressureController, kExperimentIdMonitoringExperiment, kExperimentIdMultiping, @@ -327,7 +262,6 @@ enum ExperimentIds { kExperimentIdPeerStateBasedFraming, kExperimentIdPendingQueueCap, kExperimentIdPickFirstHappyEyeballs, - kExperimentIdPingOnRstStream, kExperimentIdPromiseBasedClientCall, kExperimentIdPromiseBasedInprocTransport, kExperimentIdPromiseBasedServerCall, @@ -338,15 +272,11 @@ enum ExperimentIds { kExperimentIdRoundRobinDelegateToPickFirst, kExperimentIdRstpit, kExperimentIdScheduleCancellationOverWrite, - kExperimentIdSeparatePingFromKeepalive, kExperimentIdServerPrivacy, - kExperimentIdSettingsTimeout, - kExperimentIdTarpit, kExperimentIdTcpFrameSizeTuning, kExperimentIdTcpRcvLowat, kExperimentIdTraceRecordCallops, kExperimentIdUnconstrainedMaxQuotaBufferSize, - kExperimentIdUniquelyUnowned, kExperimentIdWorkSerializerClearsTimeCache, kExperimentIdWorkSerializerDispatch, kExperimentIdWriteSizePolicy, @@ -354,11 +284,6 @@ enum ExperimentIds { kExperimentIdWrrDelegateToPickFirst, kNumExperiments }; -#define GRPC_EXPERIMENT_IS_INCLUDED_BLOCK_EXCESSIVE_REQUESTS_BEFORE_SETTINGS_ACK -inline bool IsBlockExcessiveRequestsBeforeSettingsAckEnabled() { - return IsExperimentEnabled( - kExperimentIdBlockExcessiveRequestsBeforeSettingsAck); -} #define GRPC_EXPERIMENT_IS_INCLUDED_CALL_STATUS_OVERRIDE_ON_CANCELLATION inline bool IsCallStatusOverrideOnCancellationEnabled() { return IsExperimentEnabled(kExperimentIdCallStatusOverrideOnCancellation); @@ -375,18 +300,6 @@ inline bool IsClientIdlenessEnabled() { inline bool IsClientPrivacyEnabled() { return IsExperimentEnabled(kExperimentIdClientPrivacy); } -#define GRPC_EXPERIMENT_IS_INCLUDED_COMBINER_OFFLOAD_TO_EVENT_ENGINE -inline bool IsCombinerOffloadToEventEngineEnabled() { - return IsExperimentEnabled(kExperimentIdCombinerOffloadToEventEngine); -} -#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_BATCH_REQUESTS -inline bool IsChttp2BatchRequestsEnabled() { - return IsExperimentEnabled(kExperimentIdChttp2BatchRequests); -} -#define GRPC_EXPERIMENT_IS_INCLUDED_CHTTP2_OFFLOAD_ON_RST_STREAM -inline bool IsChttp2OffloadOnRstStreamEnabled() { - return IsExperimentEnabled(kExperimentIdChttp2OffloadOnRstStream); -} #define GRPC_EXPERIMENT_IS_INCLUDED_EVENT_ENGINE_CLIENT inline bool IsEventEngineClientEnabled() { return IsExperimentEnabled(kExperimentIdEventEngineClient); @@ -415,10 +328,6 @@ inline bool IsKeepaliveFixEnabled() { inline bool IsKeepaliveServerFixEnabled() { return IsExperimentEnabled(kExperimentIdKeepaliveServerFix); } -#define GRPC_EXPERIMENT_IS_INCLUDED_LAZIER_STREAM_UPDATES -inline bool IsLazierStreamUpdatesEnabled() { - return IsExperimentEnabled(kExperimentIdLazierStreamUpdates); -} #define GRPC_EXPERIMENT_IS_INCLUDED_MEMORY_PRESSURE_CONTROLLER inline bool IsMemoryPressureControllerEnabled() { return IsExperimentEnabled(kExperimentIdMemoryPressureController); @@ -447,10 +356,6 @@ inline bool IsPendingQueueCapEnabled() { inline bool IsPickFirstHappyEyeballsEnabled() { return IsExperimentEnabled(kExperimentIdPickFirstHappyEyeballs); } -#define GRPC_EXPERIMENT_IS_INCLUDED_PING_ON_RST_STREAM -inline bool IsPingOnRstStreamEnabled() { - return IsExperimentEnabled(kExperimentIdPingOnRstStream); -} #define GRPC_EXPERIMENT_IS_INCLUDED_PROMISE_BASED_CLIENT_CALL inline bool IsPromiseBasedClientCallEnabled() { return IsExperimentEnabled(kExperimentIdPromiseBasedClientCall); @@ -491,22 +396,10 @@ inline bool IsRstpitEnabled() { inline bool IsScheduleCancellationOverWriteEnabled() { return IsExperimentEnabled(kExperimentIdScheduleCancellationOverWrite); } -#define GRPC_EXPERIMENT_IS_INCLUDED_SEPARATE_PING_FROM_KEEPALIVE -inline bool IsSeparatePingFromKeepaliveEnabled() { - return IsExperimentEnabled(kExperimentIdSeparatePingFromKeepalive); -} #define GRPC_EXPERIMENT_IS_INCLUDED_SERVER_PRIVACY inline bool IsServerPrivacyEnabled() { return IsExperimentEnabled(kExperimentIdServerPrivacy); } -#define GRPC_EXPERIMENT_IS_INCLUDED_SETTINGS_TIMEOUT -inline bool IsSettingsTimeoutEnabled() { - return IsExperimentEnabled(kExperimentIdSettingsTimeout); -} -#define GRPC_EXPERIMENT_IS_INCLUDED_TARPIT -inline bool IsTarpitEnabled() { - return IsExperimentEnabled(kExperimentIdTarpit); -} #define GRPC_EXPERIMENT_IS_INCLUDED_TCP_FRAME_SIZE_TUNING inline bool IsTcpFrameSizeTuningEnabled() { return IsExperimentEnabled(kExperimentIdTcpFrameSizeTuning); @@ -523,10 +416,6 @@ inline bool IsTraceRecordCallopsEnabled() { inline bool IsUnconstrainedMaxQuotaBufferSizeEnabled() { return IsExperimentEnabled(kExperimentIdUnconstrainedMaxQuotaBufferSize); } -#define GRPC_EXPERIMENT_IS_INCLUDED_UNIQUELY_UNOWNED -inline bool IsUniquelyUnownedEnabled() { - return IsExperimentEnabled(kExperimentIdUniquelyUnowned); -} #define GRPC_EXPERIMENT_IS_INCLUDED_WORK_SERIALIZER_CLEARS_TIME_CACHE inline bool IsWorkSerializerClearsTimeCacheEnabled() { return IsExperimentEnabled(kExperimentIdWorkSerializerClearsTimeCache); diff --git a/src/core/lib/experiments/experiments.yaml b/src/core/lib/experiments/experiments.yaml index 76273515fdf82..9bd319f2b282f 100644 --- a/src/core/lib/experiments/experiments.yaml +++ b/src/core/lib/experiments/experiments.yaml @@ -37,12 +37,6 @@ # This file only defines the experiments. Refer to rollouts.yaml for the rollout # state of each experiment. -- name: block_excessive_requests_before_settings_ack - description: - If set, block excessive requests before receiving SETTINGS ACK. - expiry: 2024/03/03 - owner: ctiller@google.com - test_tags: [bad_client_test] - name: call_status_override_on_cancellation description: Avoid overriding call status of successfully finished calls if it races with @@ -57,20 +51,6 @@ owner: alishananda@google.com test_tags: [] allow_in_fuzzing_config: false -- name: chttp2_batch_requests - description: - Cap the number of requests received by one transport read prior to offload. - expiry: 2024/03/03 - owner: ctiller@google.com - test_tags: ["cpp_end2end_test", "flow_control_test"] - requires: [combiner_offload_to_event_engine] -- name: chttp2_offload_on_rst_stream - description: - Offload work on RST_STREAM. - expiry: 2024/03/03 - owner: ctiller@google.com - test_tags: ["cpp_end2end_test", "flow_control_test"] - requires: [combiner_offload_to_event_engine] - name: client_idleness description: If enabled, client channel idleness is enabled by default. expiry: 2023/12/15 @@ -83,12 +63,6 @@ owner: alishananda@google.com test_tags: [] allow_in_fuzzing_config: false -- name: combiner_offload_to_event_engine - description: - Offload Combiner work onto the EventEngine instead of the Executor. - expiry: 2024/01/15 - owner: hork@google.com - test_tags: [] - name: event_engine_client description: Use EventEngine clients instead of iomgr's grpc_tcp_client expiry: 2024/01/21 @@ -133,13 +107,6 @@ owner: yashkt@google.com test_tags: [] allow_in_fuzzing_config: false -- name: lazier_stream_updates - description: - Allow streams to consume up to 50% of the incoming window before we - force send a flow control update. - expiry: 2024/01/23 - owner: ctiller@google.com - test_tags: [flow_control_test] - name: memory_pressure_controller description: New memory pressure controller expiry: 2024/05/05 @@ -188,13 +155,6 @@ expiry: 2024/01/15 owner: roth@google.com test_tags: ["lb_unit_test", "cpp_lb_end2end_test", "xds_end2end_test"] -- name: ping_on_rst_stream - description: - Send a ping on receiving some RST_STREAM frames on the server - (proportion configurable via grpc.http2.ping_on_rst_stream_percent channel arg). - expiry: 2024/03/03 - owner: ctiller@google.com - test_tags: [] - name: promise_based_client_call description: If set, use the new gRPC promise based call code when it's appropriate @@ -216,7 +176,6 @@ expiry: 2024/06/14 owner: ctiller@google.com test_tags: ["core_end2end_test", "cpp_end2end_test", "xds_end2end_test", "logging_test"] - requires: [lazier_stream_updates] - name: red_max_concurrent_streams description: Perform random early rejection of requests that would exceed a newly reduced @@ -262,15 +221,6 @@ expiry: 2024/01/01 owner: vigneshbabu@google.com test_tags: [] -- name: separate_ping_from_keepalive - description: - Keep a different keepalive timeout (resolution is seeing data after sending a ping) - from a ping timeout (resolution is getting a ping ack after sending a ping) - The first can be short and determines liveness. - The second can be longer and determines protocol correctness. - expiry: 2024/03/03 - owner: ctiller@google.com - test_tags: [] - name: server_privacy description: If set, server privacy @@ -278,18 +228,6 @@ owner: alishananda@google.com test_tags: [] allow_in_fuzzing_config: false -- name: settings_timeout - description: - If set, use the settings timeout to send settings frame to the peer. - expiry: 2024/03/03 - owner: ctiller@google.com - test_tags: [] -- name: tarpit - description: - If set, tarpit invalid requests for some amount of time - expiry: 2024/03/03 - owner: ctiller@google.com - test_tags: [bad_client_test] - name: tcp_frame_size_tuning description: If set, enables TCP to use RPC size estimation made by higher layers. @@ -314,10 +252,6 @@ expiry: 2024/02/01 owner: ctiller@google.com test_tags: [resource_quota_test] -- name: uniquely_unowned - description: Ensure HPACK table takes a unique copy of data when parsing unknown metadata - expiry: 2024/03/03 - owner: ctiller@google.com - name: work_serializer_clears_time_cache description: Have the work serializer clear the time cache when it dispatches work. diff --git a/src/core/lib/experiments/rollouts.yaml b/src/core/lib/experiments/rollouts.yaml index 00b404c61de90..160a12e55a01a 100644 --- a/src/core/lib/experiments/rollouts.yaml +++ b/src/core/lib/experiments/rollouts.yaml @@ -40,22 +40,14 @@ # # Supported platforms: ios, windows, posix -- name: block_excessive_requests_before_settings_ack - default: true - name: call_status_override_on_cancellation default: debug - name: canary_client_privacy default: false -- name: chttp2_batch_requests - default: true -- name: chttp2_offload_on_rst_stream - default: true - name: client_idleness default: true - name: client_privacy default: false -- name: combiner_offload_to_event_engine - default: true - name: event_engine_client default: # not tested on iOS at all @@ -82,14 +74,10 @@ default: false - name: http2_stats_fix default: true -- name: jitter_max_idle - default: true - name: keepalive_fix default: false - name: keepalive_server_fix default: false -- name: lazier_stream_updates - default: true - name: memory_pressure_controller default: false - name: monitoring_experiment @@ -102,8 +90,6 @@ default: true - name: pick_first_happy_eyeballs default: true -- name: ping_on_rst_stream - default: true - name: promise_based_client_call default: false - name: promise_based_server_call @@ -122,14 +108,8 @@ default: false - name: schedule_cancellation_over_write default: false -- name: separate_ping_from_keepalive - default: true - name: server_privacy default: false -- name: settings_timeout - default: true -- name: tarpit - default: true - name: tcp_frame_size_tuning default: false - name: tcp_rcv_lowat @@ -138,8 +118,6 @@ default: false - name: unconstrained_max_quota_buffer_size default: false -- name: uniquely_unowned - default: true - name: work_serializer_clears_time_cache default: true - name: work_serializer_dispatch diff --git a/src/core/lib/iomgr/combiner.cc b/src/core/lib/iomgr/combiner.cc index e29c6fcbe35b4..0d77bb579d4cb 100644 --- a/src/core/lib/iomgr/combiner.cc +++ b/src/core/lib/iomgr/combiner.cc @@ -51,19 +51,11 @@ static void combiner_finally_exec(grpc_core::Combiner* lock, grpc_closure* closure, grpc_error_handle error); -// TODO(ctiller): delete this when the combiner_offload_to_event_engine -// experiment is removed. -static void offload(void* arg, grpc_error_handle error); - grpc_core::Combiner* grpc_combiner_create( std::shared_ptr event_engine) { grpc_core::Combiner* lock = new grpc_core::Combiner(); - if (grpc_core::IsCombinerOffloadToEventEngineEnabled()) { - lock->event_engine = event_engine; - } else { - GRPC_CLOSURE_INIT(&lock->offload, offload, lock, nullptr); - } + lock->event_engine = event_engine; gpr_ref_init(&lock->refs, 1); gpr_atm_no_barrier_store(&lock->state, STATE_UNORPHANED); grpc_closure_list_init(&lock->final_list); @@ -173,27 +165,18 @@ static void move_next() { } } -static void offload(void* arg, grpc_error_handle /*error*/) { - grpc_core::Combiner* lock = static_cast(arg); - push_last_on_exec_ctx(lock); -} - static void queue_offload(grpc_core::Combiner* lock) { move_next(); // Make the combiner look uncontended by storing a non-null value here, so // that we don't immediately offload again. gpr_atm_no_barrier_store(&lock->initiating_exec_ctx_or_null, 1); GRPC_COMBINER_TRACE(gpr_log(GPR_INFO, "C:%p queue_offload", lock)); - if (grpc_core::IsCombinerOffloadToEventEngineEnabled()) { - lock->event_engine->Run([lock] { - grpc_core::ApplicationCallbackExecCtx callback_exec_ctx; - grpc_core::ExecCtx exec_ctx(0); - push_last_on_exec_ctx(lock); - exec_ctx.Flush(); - }); - } else { - grpc_core::Executor::Run(&lock->offload, absl::OkStatus()); - } + lock->event_engine->Run([lock] { + grpc_core::ApplicationCallbackExecCtx callback_exec_ctx; + grpc_core::ExecCtx exec_ctx(0); + push_last_on_exec_ctx(lock); + exec_ctx.Flush(); + }); } bool grpc_combiner_continue_exec_ctx() { @@ -215,33 +198,14 @@ bool grpc_combiner_continue_exec_ctx() { grpc_core::ExecCtx::Get()->IsReadyToFinish(), lock->time_to_execute_final_list)); - if (grpc_core::IsCombinerOffloadToEventEngineEnabled()) { - // offload only if both (1) the combiner is contended and has more than one - // closure to execute, and (2) the current execution context needs to finish - // as soon as possible - if (contended && grpc_core::ExecCtx::Get()->IsReadyToFinish()) { - // this execution context wants to move on: schedule remaining work to be - // picked up on the executor - queue_offload(lock); - return true; - } - } else { - // TODO(ctiller): delete this when the combiner_offload_to_event_engine - // experiment is removed. - - // offload only if all the following conditions are true: - // 1. the combiner is contended and has more than one closure to execute - // 2. the current execution context needs to finish as soon as possible - // 3. the current thread is not a worker for any background poller - // 4. the DEFAULT executor is threaded - if (contended && grpc_core::ExecCtx::Get()->IsReadyToFinish() && - !grpc_iomgr_platform_is_any_background_poller_thread() && - grpc_core::Executor::IsThreadedDefault()) { - // this execution context wants to move on: schedule remaining work to be - // picked up on the executor - queue_offload(lock); - return true; - } + // offload only if both (1) the combiner is contended and has more than one + // closure to execute, and (2) the current execution context needs to finish + // as soon as possible + if (contended && grpc_core::ExecCtx::Get()->IsReadyToFinish()) { + // this execution context wants to move on: schedule remaining work to be + // picked up on the executor + queue_offload(lock); + return true; } if (!lock->time_to_execute_final_list || diff --git a/src/core/lib/transport/metadata_batch.h b/src/core/lib/transport/metadata_batch.h index 0a81bd22a0ab2..6bb12289d5aed 100644 --- a/src/core/lib/transport/metadata_batch.h +++ b/src/core/lib/transport/metadata_batch.h @@ -649,9 +649,8 @@ class ParseHelper { return ParsedMetadata( typename ParsedMetadata::FromSlicePair{}, Slice::FromCopiedString(key), - IsUniquelyUnownedEnabled() && will_keep_past_request_lifetime_ - ? value_.TakeUniquelyOwned() - : std::move(value_), + will_keep_past_request_lifetime_ ? value_.TakeUniquelyOwned() + : std::move(value_), transport_size_); } diff --git a/test/core/bad_client/tests/initial_settings_frame.cc b/test/core/bad_client/tests/initial_settings_frame.cc index 4f0af52b01621..384d1662ab24c 100644 --- a/test/core/bad_client/tests/initial_settings_frame.cc +++ b/test/core/bad_client/tests/initial_settings_frame.cc @@ -200,12 +200,10 @@ int main(int argc, char** argv) { GRPC_BAD_CLIENT_DISCONNECT); // too many requests before the settings ack is sent should be cancelled - if (grpc_core::IsBlockExcessiveRequestsBeforeSettingsAckEnabled()) { - GRPC_RUN_BAD_CLIENT_TEST(single_request_verifier, nullptr, - PFX_STR ZERO_SETTING_HDR FOOBAR_0 FOOBAR_2 - SETTING_ACK RST_STREAM_1 RST_STREAM_3 FOOBAR_1, - GRPC_BAD_CLIENT_MAX_CONCURRENT_REQUESTS_OF_ONE); - } + GRPC_RUN_BAD_CLIENT_TEST(single_request_verifier, nullptr, + PFX_STR ZERO_SETTING_HDR FOOBAR_0 FOOBAR_2 + SETTING_ACK RST_STREAM_1 RST_STREAM_3 FOOBAR_1, + GRPC_BAD_CLIENT_MAX_CONCURRENT_REQUESTS_OF_ONE); grpc_shutdown(); return 0; From 9eadf42dbfece3b0682a561f67c76f1722275b8b Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 4 Dec 2023 22:10:48 -0800 Subject: [PATCH 043/127] [promises] Add an API to access new style filters (#35200) Will be used during this transition time to run 5-pipe style filters somewhat more natively. Once everything is getting closer to 5-pipes, we'll drop this method and have the channel stack understand how to create an interception-map that can be reused per-call, instead of creating the interception-map every time a call is created. Closes #35200 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35200 from ctiller:cg-channel-filter-api 2fc11dd273f0bafcfffbd713284f042db947f79a PiperOrigin-RevId: 587940947 --- .../filters/client_channel/client_channel.cc | 3 + .../filters/client_channel/retry_filter.cc | 1 + .../ext/filters/deadline/deadline_filter.cc | 2 + src/core/lib/channel/channel_stack.h | 6 + src/core/lib/channel/connected_channel.cc | 1 + src/core/lib/channel/promise_based_filter.h | 203 +++++++++++++++++- src/core/lib/surface/call_trace.cc | 3 +- src/core/lib/surface/server.cc | 1 + src/core/lib/transport/transport.h | 70 ++++++ .../channel/channel_stack_builder_test.cc | 4 +- test/core/channel/channel_stack_test.cc | 1 + .../core/end2end/tests/filter_causes_close.cc | 1 + test/core/end2end/tests/filter_context.cc | 2 +- test/core/end2end/tests/filter_init_fails.cc | 2 +- ...retry_cancel_with_multiple_send_batches.cc | 1 + .../tests/retry_recv_message_replay.cc | 1 + .../retry_recv_trailing_metadata_error.cc | 1 + .../core/end2end/tests/retry_send_op_fails.cc | 1 + .../end2end/tests/retry_transparent_goaway.cc | 1 + .../retry_transparent_not_sent_on_wire.cc | 1 + test/core/surface/channel_init_test.cc | 6 +- .../transport/chttp2/streams_not_seen_test.cc | 1 + .../xds/xds_channel_stack_modifier_test.cc | 8 +- 23 files changed, 303 insertions(+), 18 deletions(-) diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc index 197173aa7e09c..91b4712c61ac9 100644 --- a/src/core/ext/filters/client_channel/client_channel.cc +++ b/src/core/ext/filters/client_channel/client_channel.cc @@ -407,6 +407,7 @@ class ClientChannel::PromiseBasedCallData : public ClientChannel::CallData { const grpc_channel_filter ClientChannel::kFilterVtableWithPromises = { ClientChannel::FilterBasedCallData::StartTransportStreamOpBatch, ClientChannel::MakeCallPromise, + /* init_call: */ nullptr, ClientChannel::StartTransportOp, sizeof(ClientChannel::FilterBasedCallData), ClientChannel::FilterBasedCallData::Init, @@ -423,6 +424,7 @@ const grpc_channel_filter ClientChannel::kFilterVtableWithPromises = { const grpc_channel_filter ClientChannel::kFilterVtableWithoutPromises = { ClientChannel::FilterBasedCallData::StartTransportStreamOpBatch, nullptr, + /* init_call: */ nullptr, ClientChannel::StartTransportOp, sizeof(ClientChannel::FilterBasedCallData), ClientChannel::FilterBasedCallData::Init, @@ -570,6 +572,7 @@ class DynamicTerminationFilter::CallData { const grpc_channel_filter DynamicTerminationFilter::kFilterVtable = { DynamicTerminationFilter::CallData::StartTransportStreamOpBatch, DynamicTerminationFilter::MakeCallPromise, + /* init_call: */ nullptr, DynamicTerminationFilter::StartTransportOp, sizeof(DynamicTerminationFilter::CallData), DynamicTerminationFilter::CallData::Init, diff --git a/src/core/ext/filters/client_channel/retry_filter.cc b/src/core/ext/filters/client_channel/retry_filter.cc index cb29fbee2a48f..f2d393f9484cb 100644 --- a/src/core/ext/filters/client_channel/retry_filter.cc +++ b/src/core/ext/filters/client_channel/retry_filter.cc @@ -143,6 +143,7 @@ const RetryMethodConfig* RetryFilter::GetRetryPolicy( const grpc_channel_filter RetryFilter::kVtable = { RetryFilter::LegacyCallData::StartTransportStreamOpBatch, nullptr, + /* init_call: */ nullptr, RetryFilter::StartTransportOp, sizeof(RetryFilter::LegacyCallData), RetryFilter::LegacyCallData::Init, diff --git a/src/core/ext/filters/deadline/deadline_filter.cc b/src/core/ext/filters/deadline/deadline_filter.cc index 94a4f65225e4e..50ce988173edb 100644 --- a/src/core/ext/filters/deadline/deadline_filter.cc +++ b/src/core/ext/filters/deadline/deadline_filter.cc @@ -343,6 +343,7 @@ const grpc_channel_filter grpc_client_deadline_filter = { grpc_core::NextPromiseFactory next_promise_factory) { return next_promise_factory(std::move(call_args)); }, + /* init_call: */ nullptr, grpc_channel_next_op, sizeof(grpc_deadline_state), deadline_init_call_elem, @@ -368,6 +369,7 @@ const grpc_channel_filter grpc_server_deadline_filter = { } return next_promise_factory(std::move(call_args)); }, + /* init_call: */ nullptr, grpc_channel_next_op, sizeof(server_call_data), deadline_init_call_elem, diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h index 918628856b03a..5b6649a9eac87 100644 --- a/src/core/lib/channel/channel_stack.h +++ b/src/core/lib/channel/channel_stack.h @@ -128,6 +128,12 @@ struct grpc_channel_filter { grpc_core::ArenaPromise (*make_call_promise)( grpc_channel_element* elem, grpc_core::CallArgs call_args, grpc_core::NextPromiseFactory next_promise_factory); + // Register interceptors into a call. + // If this is non-null it may be used in preference to make_call_promise. + // There is an on-going migration to move all filters to providing this, and + // then to drop start_transport_stream_op_batch. + void (*init_call)(grpc_channel_element* elem, + grpc_core::CallSpineInterface* call_spine); // Called to handle channel level operations - e.g. new calls, or transport // closure. // See grpc_channel_next_op on how to call the next element in the stack diff --git a/src/core/lib/channel/connected_channel.cc b/src/core/lib/channel/connected_channel.cc index afca6eda5fc18..0ceba07e07567 100644 --- a/src/core/lib/channel/connected_channel.cc +++ b/src/core/lib/channel/connected_channel.cc @@ -857,6 +857,7 @@ grpc_channel_filter MakeConnectedFilter() { return { connected_channel_start_transport_stream_op_batch, make_call_promise != nullptr ? make_call_wrapper : nullptr, + /* init_call: */ nullptr, connected_channel_start_transport_op, sizeof(call_data), connected_channel_init_call_elem, diff --git a/src/core/lib/channel/promise_based_filter.h b/src/core/lib/channel/promise_based_filter.h index a94b79bbd0c0a..fa015fc6d3d56 100644 --- a/src/core/lib/channel/promise_based_filter.h +++ b/src/core/lib/channel/promise_based_filter.h @@ -345,15 +345,77 @@ inline auto RunCall(void (Derived::Call::*fn)(ClientMetadata& md, } inline void InterceptClientToServerMessage(const NoInterceptor*, void*, - CallArgs&) {} + const CallArgs&) {} +inline void InterceptClientToServerMessage(const NoInterceptor*, void*, void*, + CallSpineInterface*) {} + +inline void InterceptClientInitialMetadata(const NoInterceptor*, void*, void*, + CallSpineInterface*) {} + +template +inline void InterceptClientInitialMetadata( + void (Derived::Call::*fn)(ClientMetadata& md), typename Derived::Call* call, + Derived*, CallSpineInterface* call_spine) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnClientInitialMetadata); + call_spine->client_initial_metadata().receiver.InterceptAndMap( + [call](ClientMetadataHandle md) { + call->OnClientInitialMetadata(*md); + return md; + }); +} + +template +inline void InterceptClientInitialMetadata( + void (Derived::Call::*fn)(ClientMetadata& md, Derived* channel), + typename Derived::Call* call, Derived* channel, + CallSpineInterface* call_spine) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnClientInitialMetadata); + call_spine->client_initial_metadata().receiver.InterceptAndMap( + [call, channel](ClientMetadataHandle md) { + call->OnClientInitialMetadata(*md, channel); + return md; + }); +} + +template +inline void InterceptClientInitialMetadata( + ServerMetadataHandle (Derived::Call::*fn)(ClientMetadata& md), + typename Derived::Call* call, Derived*, CallSpineInterface* call_spine) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnClientInitialMetadata); + call_spine->client_initial_metadata().receiver.InterceptAndMap( + [call_spine, + call](ClientMetadataHandle md) -> absl::optional { + auto return_md = call->OnClientInitialMetadata(*md); + if (return_md == nullptr) return std::move(md); + return call_spine->Cancel(std::move(return_md)); + }); +} + +template +inline void InterceptClientInitialMetadata( + ServerMetadataHandle (Derived::Call::*fn)(ClientMetadata& md, + Derived* channel), + typename Derived::Call* call, Derived* channel, + CallSpineInterface* call_spine) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnClientInitialMetadata); + call_spine->client_initial_metadata().receiver.InterceptAndMap( + [call_spine, call, channel]( + ClientMetadataHandle md) -> absl::optional { + auto return_md = call->OnClientInitialMetadata(*md, channel); + if (return_md == nullptr) return std::move(md); + return call_spine->Cancel(std::move(return_md)); + }); +} + +template inline void InterceptServerInitialMetadata(const NoInterceptor*, void*, - CallArgs&) {} + const CallArgs&) {} template inline void InterceptServerInitialMetadata( void (Derived::Call::*fn)(ServerMetadata&), - FilterCallData* call_data, CallArgs& call_args) { + FilterCallData* call_data, const CallArgs& call_args) { GPR_DEBUG_ASSERT(fn == &Derived::Call::OnServerInitialMetadata); call_args.server_initial_metadata->InterceptAndMap( [call_data](ServerMetadataHandle md) { @@ -365,7 +427,7 @@ inline void InterceptServerInitialMetadata( template inline void InterceptServerInitialMetadata( absl::Status (Derived::Call::*fn)(ServerMetadata&), - FilterCallData* call_data, CallArgs& call_args) { + FilterCallData* call_data, const CallArgs& call_args) { GPR_DEBUG_ASSERT(fn == &Derived::Call::OnServerInitialMetadata); call_args.server_initial_metadata->InterceptAndMap( [call_data]( @@ -379,8 +441,69 @@ inline void InterceptServerInitialMetadata( }); } +template +inline void InterceptServerInitialMetadata(const NoInterceptor*, void*, void*, + CallSpineInterface*) {} + +template +inline void InterceptServerInitialMetadata( + void (Derived::Call::*fn)(ServerMetadata&), typename Derived::Call* call, + Derived*, CallSpineInterface* call_spine) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnServerInitialMetadata); + call_spine->server_initial_metadata().sender.InterceptAndMap( + [call](ServerMetadataHandle md) { + call->OnServerInitialMetadata(*md); + return md; + }); +} + +template +inline void InterceptServerInitialMetadata( + absl::Status (Derived::Call::*fn)(ServerMetadata&), + typename Derived::Call* call, Derived*, CallSpineInterface* call_spine) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnServerInitialMetadata); + call_spine->server_initial_metadata().sender.InterceptAndMap( + [call, call_spine]( + ServerMetadataHandle md) -> absl::optional { + auto status = call->OnServerInitialMetadata(*md); + if (status.ok()) return std::move(md); + return call_spine->Cancel(ServerMetadataFromStatus(status)); + }); +} + inline void InterceptServerToClientMessage(const NoInterceptor*, void*, - CallArgs&) {} + const CallArgs&) {} + +inline void InterceptServerToClientMessage(const NoInterceptor*, void*, void*, + CallSpineInterface*) {} + +inline void InterceptServerTrailingMetadata(const NoInterceptor*, void*, void*, + CallSpineInterface*) {} + +template +inline void InterceptServerTrailingMetadata( + void (Derived::Call::*fn)(ServerMetadata&), typename Derived::Call* call, + Derived*, CallSpineInterface* call_spine) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnServerTrailingMetadata); + call_spine->server_trailing_metadata().sender.InterceptAndMap( + [call](ServerMetadataHandle md) { + call->OnServerTrailingMetadata(*md); + return md; + }); +} + +template +inline void InterceptServerTrailingMetadata( + absl::Status (Derived::Call::*fn)(ServerMetadata&), + typename Derived::Call* call, Derived*, CallSpineInterface* call_spine) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnServerTrailingMetadata); + call_spine->server_trailing_metadata().sender.InterceptAndMap( + [call](ServerMetadataHandle md) -> absl::optional { + auto status = call->OnServerTrailingMetadata(*md); + if (status.ok()) return std::move(md); + return ServerMetadataFromStatus(status); + }); +} template absl::enable_if_t>::value, @@ -449,6 +572,29 @@ MakeFilterCall(Derived* derived) { template class ImplementChannelFilter : public ChannelFilter { public: + // Natively construct a v3 call. + void InitCall(CallSpineInterface* call_spine) { + auto* call = GetContext()->ManagedNew(); + promise_filter_detail::InterceptClientInitialMetadata( + &Derived::Call::OnClientInitialMetadata, call, + static_cast(this), call_spine); + promise_filter_detail::InterceptClientToServerMessage( + &Derived::Call::OnClientToServerMessage, call, + static_cast(this), call_spine); + promise_filter_detail::InterceptServerInitialMetadata( + &Derived::Call::OnServerInitialMetadata, call, + static_cast(this), call_spine); + promise_filter_detail::InterceptServerToClientMessage( + &Derived::Call::OnServerToClientMessage, call, + static_cast(this), call_spine); + promise_filter_detail::InterceptServerTrailingMetadata( + &Derived::Call::OnServerTrailingMetadata, call, + static_cast(this), call_spine); + } + + // Polyfill for the original promise scheme. + // Allows writing v3 filters that work with v2 stacks. + // (and consequently also v1 stacks since we can polyfill back to that too). ArenaPromise MakeCallPromise( CallArgs call_args, NextPromiseFactory next_promise_factory) final { auto* call = promise_filter_detail::MakeFilterCall( @@ -1262,7 +1408,49 @@ struct ChannelFilterWithFlagsMethods { // ChannelArgs channel_args, ChannelFilter::Args filter_args); // }; template -absl::enable_if_t::value, grpc_channel_filter> +absl::enable_if_t::value && + !std::is_base_of, F>::value, + grpc_channel_filter> +MakePromiseBasedFilter(const char* name) { + using CallData = promise_filter_detail::CallData; + + return grpc_channel_filter{ + // start_transport_stream_op_batch + promise_filter_detail::BaseCallDataMethods::StartTransportStreamOpBatch, + // make_call_promise + promise_filter_detail::ChannelFilterMethods::MakeCallPromise, + nullptr, + // start_transport_op + promise_filter_detail::ChannelFilterMethods::StartTransportOp, + // sizeof_call_data + sizeof(CallData), + // init_call_elem + promise_filter_detail::CallDataFilterWithFlagsMethods< + CallData, kFlags>::InitCallElem, + // set_pollset_or_pollset_set + promise_filter_detail::BaseCallDataMethods::SetPollsetOrPollsetSet, + // destroy_call_elem + promise_filter_detail::CallDataFilterWithFlagsMethods< + CallData, kFlags>::DestroyCallElem, + // sizeof_channel_data + sizeof(F), + // init_channel_elem + promise_filter_detail::ChannelFilterWithFlagsMethods< + F, kFlags>::InitChannelElem, + // post_init_channel_elem + promise_filter_detail::ChannelFilterMethods::PostInitChannelElem, + // destroy_channel_elem + promise_filter_detail::ChannelFilterMethods::DestroyChannelElem, + // get_channel_info + promise_filter_detail::ChannelFilterMethods::GetChannelInfo, + // name + name, + }; +} + +template +absl::enable_if_t, F>::value, + grpc_channel_filter> MakePromiseBasedFilter(const char* name) { using CallData = promise_filter_detail::CallData; @@ -1271,6 +1459,9 @@ MakePromiseBasedFilter(const char* name) { promise_filter_detail::BaseCallDataMethods::StartTransportStreamOpBatch, // make_call_promise promise_filter_detail::ChannelFilterMethods::MakeCallPromise, + [](grpc_channel_element* elem, CallSpineInterface* args) { + static_cast(elem->channel_data)->InitCall(args); + }, // start_transport_op promise_filter_detail::ChannelFilterMethods::StartTransportOp, // sizeof_call_data diff --git a/src/core/lib/surface/call_trace.cc b/src/core/lib/surface/call_trace.cc index 163418f5083fb..d9b544ee1f9d6 100644 --- a/src/core/lib/surface/call_trace.cc +++ b/src/core/lib/surface/call_trace.cc @@ -77,7 +77,8 @@ const grpc_channel_filter* PromiseTracingFilterFor( return r; }; }, - grpc_channel_next_op, /* sizeof_call_data: */ 0, + /* init_call: */ nullptr, grpc_channel_next_op, + /* sizeof_call_data: */ 0, // init_call_elem: [](grpc_call_element*, const grpc_call_element_args*) { return absl::OkStatus(); diff --git a/src/core/lib/surface/server.cc b/src/core/lib/surface/server.cc index 2402f45e9da37..a56f58d98e4bf 100644 --- a/src/core/lib/surface/server.cc +++ b/src/core/lib/surface/server.cc @@ -757,6 +757,7 @@ class ChannelBroadcaster { const grpc_channel_filter Server::kServerTopFilter = { Server::CallData::StartTransportStreamOpBatch, Server::ChannelData::MakeCallPromise, + /* init_call: */ nullptr, grpc_channel_next_op, sizeof(Server::CallData), Server::CallData::InitCallElement, diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h index 6f451a9ae4be4..fea659ff7e952 100644 --- a/src/core/lib/transport/transport.h +++ b/src/core/lib/transport/transport.h @@ -55,6 +55,7 @@ #include "src/core/lib/promise/context.h" #include "src/core/lib/promise/detail/status.h" #include "src/core/lib/promise/latch.h" +#include "src/core/lib/promise/party.h" #include "src/core/lib/promise/pipe.h" #include "src/core/lib/resource_quota/arena.h" #include "src/core/lib/slice/slice_buffer.h" @@ -228,6 +229,75 @@ struct CallArgs { using NextPromiseFactory = std::function(CallArgs)>; +// The common middle part of a call - a reference is held by each of +// CallInitiator and CallHandler - which provide interfaces that are appropriate +// for each side of a call. +// The spine will ultimately host the pipes, filters, and context for one part +// of a call: ie top-half client channel, sub channel call, server call. +// TODO(ctiller): eventually drop this when we don't need to reference into +// legacy promise calls anymore +class CallSpineInterface { + public: + virtual ~CallSpineInterface() = default; + virtual Pipe& client_initial_metadata() = 0; + virtual Pipe& server_initial_metadata() = 0; + virtual Pipe& client_to_server_messages() = 0; + virtual Pipe& server_to_client_messages() = 0; + virtual Pipe& server_trailing_metadata() = 0; + // Cancel the call with the given metadata. + // Regarding the `MUST_USE_RESULT absl::nullopt_t`: + // Most cancellation calls right now happen in pipe interceptors; + // there `nullopt` indicates terminate processing of this pipe and close with + // error. + // It's convenient then to have the Cancel operation (setting the latch to + // terminate the call) be the last thing that occurs in a pipe interceptor, + // and this construction supports that (and has helped the author not write + // some bugs). + GRPC_MUST_USE_RESULT virtual absl::nullopt_t Cancel( + ServerMetadataHandle metadata) = 0; + virtual Party& party() = 0; +}; + +class CallSpine final : public CallSpineInterface { + public: + Pipe& client_initial_metadata() override { + return client_initial_metadata_; + } + Pipe& server_initial_metadata() override { + return server_initial_metadata_; + } + Pipe& client_to_server_messages() override { + return client_to_server_messages_; + } + Pipe& server_to_client_messages() override { + return server_to_client_messages_; + } + Pipe& server_trailing_metadata() override { + return server_trailing_metadata_; + } + absl::nullopt_t Cancel(ServerMetadataHandle metadata) override { + GPR_DEBUG_ASSERT(Activity::current() == &party()); + if (cancel_latch_.is_set()) return absl::nullopt; + cancel_latch_.Set(std::move(metadata)); + return absl::nullopt; + } + Party& party() override { Crash("unimplemented"); } + + private: + // Initial metadata from client to server + Pipe client_initial_metadata_; + // Initial metadata from server to client + Pipe server_initial_metadata_; + // Messages travelling from the application to the transport. + Pipe client_to_server_messages_; + // Messages travelling from the transport to the application. + Pipe server_to_client_messages_; + // Trailing metadata from server to client + Pipe server_trailing_metadata_; + // Latch that can be set to terminate the call + Latch cancel_latch_; +}; + } // namespace grpc_core // forward declarations diff --git a/test/core/channel/channel_stack_builder_test.cc b/test/core/channel/channel_stack_builder_test.cc index 4e253b832d0f6..65d4466eff9bd 100644 --- a/test/core/channel/channel_stack_builder_test.cc +++ b/test/core/channel/channel_stack_builder_test.cc @@ -62,8 +62,8 @@ const grpc_channel_filter* FilterNamed(const char* name) { ->emplace( name, new grpc_channel_filter{ - grpc_call_next_op, nullptr, grpc_channel_next_op, 0, CallInitFunc, - grpc_call_stack_ignore_set_pollset_or_pollset_set, + grpc_call_next_op, nullptr, nullptr, grpc_channel_next_op, 0, + CallInitFunc, grpc_call_stack_ignore_set_pollset_or_pollset_set, CallDestroyFunc, 0, ChannelInitFunc, [](grpc_channel_stack*, grpc_channel_element*) {}, ChannelDestroyFunc, grpc_channel_next_get_info, name}) diff --git a/test/core/channel/channel_stack_test.cc b/test/core/channel/channel_stack_test.cc index 7ed34f60b6419..4054e6a8844f2 100644 --- a/test/core/channel/channel_stack_test.cc +++ b/test/core/channel/channel_stack_test.cc @@ -83,6 +83,7 @@ TEST(ChannelStackTest, CreateChannelStack) { const grpc_channel_filter filter = { call_func, nullptr, + nullptr, channel_func, sizeof(int), call_init_func, diff --git a/test/core/end2end/tests/filter_causes_close.cc b/test/core/end2end/tests/filter_causes_close.cc index 751507495de05..91b917ced3b74 100644 --- a/test/core/end2end/tests/filter_causes_close.cc +++ b/test/core/end2end/tests/filter_causes_close.cc @@ -102,6 +102,7 @@ const grpc_channel_filter test_filter = { return Immediate(ServerMetadataFromStatus( absl::PermissionDeniedError("Failure that's not preventable."))); }, + nullptr, grpc_channel_next_op, sizeof(call_data), init_call_elem, diff --git a/test/core/end2end/tests/filter_context.cc b/test/core/end2end/tests/filter_context.cc index 8156384fbd64d..1da07e814e965 100644 --- a/test/core/end2end/tests/filter_context.cc +++ b/test/core/end2end/tests/filter_context.cc @@ -82,7 +82,7 @@ grpc_error_handle init_channel_elem(grpc_channel_element* /*elem*/, void destroy_channel_elem(grpc_channel_element* /*elem*/) {} const grpc_channel_filter test_filter = { - start_transport_stream_op_batch, nullptr, grpc_channel_next_op, + start_transport_stream_op_batch, nullptr, nullptr, grpc_channel_next_op, sizeof(call_data), init_call_elem, grpc_call_stack_ignore_set_pollset_or_pollset_set, destroy_call_elem, 0, init_channel_elem, grpc_channel_stack_no_post_init, destroy_channel_elem, diff --git a/test/core/end2end/tests/filter_init_fails.cc b/test/core/end2end/tests/filter_init_fails.cc index a640bebc5f0e7..a160b38b60af6 100644 --- a/test/core/end2end/tests/filter_init_fails.cc +++ b/test/core/end2end/tests/filter_init_fails.cc @@ -80,7 +80,7 @@ const grpc_channel_filter test_filter = { return Immediate(ServerMetadataFromStatus( absl::PermissionDeniedError("access denied"))); }, - grpc_channel_next_op, 0, init_call_elem, + nullptr, grpc_channel_next_op, 0, init_call_elem, grpc_call_stack_ignore_set_pollset_or_pollset_set, destroy_call_elem, 0, init_channel_elem, grpc_channel_stack_no_post_init, destroy_channel_elem, grpc_channel_next_get_info, diff --git a/test/core/end2end/tests/retry_cancel_with_multiple_send_batches.cc b/test/core/end2end/tests/retry_cancel_with_multiple_send_batches.cc index 85948b208c508..22de5660e0553 100644 --- a/test/core/end2end/tests/retry_cancel_with_multiple_send_batches.cc +++ b/test/core/end2end/tests/retry_cancel_with_multiple_send_batches.cc @@ -159,6 +159,7 @@ class FailSendOpsFilter { grpc_channel_filter FailSendOpsFilter::kFilterVtable = { CallData::StartTransportStreamOpBatch, nullptr, + nullptr, grpc_channel_next_op, sizeof(CallData), CallData::Init, diff --git a/test/core/end2end/tests/retry_recv_message_replay.cc b/test/core/end2end/tests/retry_recv_message_replay.cc index 74e5f98bfc74c..befb2391ddea6 100644 --- a/test/core/end2end/tests/retry_recv_message_replay.cc +++ b/test/core/end2end/tests/retry_recv_message_replay.cc @@ -109,6 +109,7 @@ class FailFirstSendOpFilter { grpc_channel_filter FailFirstSendOpFilter::kFilterVtable = { CallData::StartTransportStreamOpBatch, nullptr, + nullptr, grpc_channel_next_op, sizeof(CallData), CallData::Init, diff --git a/test/core/end2end/tests/retry_recv_trailing_metadata_error.cc b/test/core/end2end/tests/retry_recv_trailing_metadata_error.cc index 8a277ff4b6dc4..7a43114ec3a2e 100644 --- a/test/core/end2end/tests/retry_recv_trailing_metadata_error.cc +++ b/test/core/end2end/tests/retry_recv_trailing_metadata_error.cc @@ -104,6 +104,7 @@ class InjectStatusFilter { grpc_channel_filter InjectStatusFilter::kFilterVtable = { CallData::StartTransportStreamOpBatch, nullptr, + nullptr, grpc_channel_next_op, sizeof(CallData), CallData::Init, diff --git a/test/core/end2end/tests/retry_send_op_fails.cc b/test/core/end2end/tests/retry_send_op_fails.cc index 3bb2715dc5ae4..2fdc38186944b 100644 --- a/test/core/end2end/tests/retry_send_op_fails.cc +++ b/test/core/end2end/tests/retry_send_op_fails.cc @@ -110,6 +110,7 @@ class FailFirstCallFilter { grpc_channel_filter FailFirstCallFilter::kFilterVtable = { CallData::StartTransportStreamOpBatch, nullptr, + nullptr, grpc_channel_next_op, sizeof(CallData), CallData::Init, diff --git a/test/core/end2end/tests/retry_transparent_goaway.cc b/test/core/end2end/tests/retry_transparent_goaway.cc index 98d3f744d18df..091a800f210ca 100644 --- a/test/core/end2end/tests/retry_transparent_goaway.cc +++ b/test/core/end2end/tests/retry_transparent_goaway.cc @@ -116,6 +116,7 @@ class FailFirstCallFilter { grpc_channel_filter FailFirstCallFilter::kFilterVtable = { CallData::StartTransportStreamOpBatch, nullptr, + nullptr, grpc_channel_next_op, sizeof(CallData), CallData::Init, diff --git a/test/core/end2end/tests/retry_transparent_not_sent_on_wire.cc b/test/core/end2end/tests/retry_transparent_not_sent_on_wire.cc index 87542064ad4b5..05bf6c1ac1210 100644 --- a/test/core/end2end/tests/retry_transparent_not_sent_on_wire.cc +++ b/test/core/end2end/tests/retry_transparent_not_sent_on_wire.cc @@ -115,6 +115,7 @@ class FailFirstTenCallsFilter { grpc_channel_filter FailFirstTenCallsFilter::kFilterVtable = { CallData::StartTransportStreamOpBatch, nullptr, + nullptr, grpc_channel_next_op, sizeof(CallData), CallData::Init, diff --git a/test/core/surface/channel_init_test.cc b/test/core/surface/channel_init_test.cc index 22fdad11da97b..bab56a38d3a6e 100644 --- a/test/core/surface/channel_init_test.cc +++ b/test/core/surface/channel_init_test.cc @@ -35,9 +35,9 @@ const grpc_channel_filter* FilterNamed(const char* name) { if (it != filters->end()) return it->second; return filters ->emplace(name, - new grpc_channel_filter{nullptr, nullptr, nullptr, 0, nullptr, - nullptr, nullptr, 0, nullptr, nullptr, - nullptr, nullptr, name}) + new grpc_channel_filter{nullptr, nullptr, nullptr, nullptr, 0, + nullptr, nullptr, nullptr, 0, nullptr, + nullptr, nullptr, nullptr, name}) .first->second; } diff --git a/test/core/transport/chttp2/streams_not_seen_test.cc b/test/core/transport/chttp2/streams_not_seen_test.cc index e38160d4b41ba..420686ea6e616 100644 --- a/test/core/transport/chttp2/streams_not_seen_test.cc +++ b/test/core/transport/chttp2/streams_not_seen_test.cc @@ -199,6 +199,7 @@ class TrailingMetadataRecordingFilter { grpc_channel_filter TrailingMetadataRecordingFilter::kFilterVtable = { CallData::StartTransportStreamOpBatch, nullptr, + nullptr, grpc_channel_next_op, sizeof(CallData), CallData::Init, diff --git a/test/core/xds/xds_channel_stack_modifier_test.cc b/test/core/xds/xds_channel_stack_modifier_test.cc index ab6c78242f054..ffd0b9f450d44 100644 --- a/test/core/xds/xds_channel_stack_modifier_test.cc +++ b/test/core/xds/xds_channel_stack_modifier_test.cc @@ -95,11 +95,11 @@ TEST(XdsChannelStackModifierTest, XdsHttpFiltersInsertion) { grpc_init(); // Add 2 test filters to XdsChannelStackModifier const grpc_channel_filter test_filter_1 = { - nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, - 0, nullptr, nullptr, nullptr, nullptr, kTestFilter1}; + nullptr, nullptr, nullptr, nullptr, 0, nullptr, nullptr, + nullptr, 0, nullptr, nullptr, nullptr, nullptr, kTestFilter1}; const grpc_channel_filter test_filter_2 = { - nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, - 0, nullptr, nullptr, nullptr, nullptr, kTestFilter2}; + nullptr, nullptr, nullptr, nullptr, 0, nullptr, nullptr, + nullptr, 0, nullptr, nullptr, nullptr, nullptr, kTestFilter2}; auto channel_stack_modifier = MakeRefCounted( std::vector{&test_filter_1, &test_filter_2}); grpc_arg arg = channel_stack_modifier->MakeChannelArg(); From 2fa8018d2a0e0d97f3b4015f5a792f24912a7d79 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 5 Dec 2023 11:11:55 -0800 Subject: [PATCH 044/127] [call-v3] Introduce some cancellation helpers to CallSpine (#35212) These will be used in upcoming changes to allow easy spawning of promises into parties that properly cancel out things when those promises fail. Closes #35212 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35212 from ctiller:cg-cancel-nicely 32fc7aa09a6de4b5dd3933ec09791f2bfdfa6a74 PiperOrigin-RevId: 588130225 --- src/core/lib/transport/transport.h | 42 ++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h index fea659ff7e952..a89b2084ba226 100644 --- a/src/core/lib/transport/transport.h +++ b/src/core/lib/transport/transport.h @@ -256,6 +256,48 @@ class CallSpineInterface { GRPC_MUST_USE_RESULT virtual absl::nullopt_t Cancel( ServerMetadataHandle metadata) = 0; virtual Party& party() = 0; + + // Wrap a promise so that if it returns failure it automatically cancels + // the rest of the call. + // The resulting (returned) promise will resolve to Empty. + template + auto CancelIfFails(Promise promise) { + GPR_DEBUG_ASSERT(Activity::current() == &party()); + using P = promise_detail::PromiseLike; + using ResultType = typename P::Result; + return Map(std::move(promise), [this](ResultType r) { + if (!IsStatusOk(r)) { + std::ignore = Cancel(StatusCast(std::move(r))); + } + return Empty{}; + }); + } + + // Spawn a promise that returns Empty{} and save some boilerplate handling + // that detail. + template + void SpawnInfallible(absl::string_view name, PromiseFactory promise_factory) { + party().Spawn(name, std::move(promise_factory), [](Empty) {}); + } + + // Spawn a promise that returns some status-like type; if the status + // represents failure automatically cancel the rest of the call. + template + void SpawnGuarded(absl::string_view name, PromiseFactory promise_factory) { + using FactoryType = + promise_detail::OncePromiseFactory; + using PromiseType = typename FactoryType::Promise; + using ResultType = typename PromiseType::Result; + static_assert( + std::is_same()))>::value, + "SpawnGuarded promise must return a status-like object"); + party().Spawn(name, std::move(promise_factory), [this](ResultType r) { + if (!IsStatusOk(r)) { + std::ignore = Cancel(StatusCast(std::move(r))); + } + }); + } }; class CallSpine final : public CallSpineInterface { From 1a086609d7083b2e6413b397fc3239adea3d66f2 Mon Sep 17 00:00:00 2001 From: Eugene Ostroukhov Date: Tue, 5 Dec 2023 12:00:25 -0800 Subject: [PATCH 045/127] [server] Fix typo in the class name (#35216) Closes #35216 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35216 from eugeneo:tasks/typo-aync d9f58bc130f4e0ce337b16826caff7daac0a55e2 PiperOrigin-RevId: 588146516 --- src/cpp/server/secure_server_credentials.cc | 20 ++++++++++---------- src/cpp/server/secure_server_credentials.h | 6 +++--- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/cpp/server/secure_server_credentials.cc b/src/cpp/server/secure_server_credentials.cc index 9ec5d24031f6e..fd198898d2f8a 100644 --- a/src/cpp/server/secure_server_credentials.cc +++ b/src/cpp/server/secure_server_credentials.cc @@ -36,15 +36,15 @@ namespace grpc { -void AuthMetadataProcessorAyncWrapper::Destroy(void* wrapper) { - auto* w = static_cast(wrapper); +void AuthMetadataProcessorAsyncWrapper::Destroy(void* wrapper) { + auto* w = static_cast(wrapper); delete w; } -void AuthMetadataProcessorAyncWrapper::Process( +void AuthMetadataProcessorAsyncWrapper::Process( void* wrapper, grpc_auth_context* context, const grpc_metadata* md, size_t num_md, grpc_process_auth_metadata_done_cb cb, void* user_data) { - auto* w = static_cast(wrapper); + auto* w = static_cast(wrapper); if (!w->processor_) { // Early exit. cb(user_data, nullptr, 0, nullptr, 0, GRPC_STATUS_OK, nullptr); @@ -52,8 +52,8 @@ void AuthMetadataProcessorAyncWrapper::Process( } if (w->processor_->IsBlocking()) { w->thread_pool_->Add([w, context, md, num_md, cb, user_data] { - w->AuthMetadataProcessorAyncWrapper::InvokeProcessor(context, md, num_md, - cb, user_data); + w->AuthMetadataProcessorAsyncWrapper::InvokeProcessor(context, md, num_md, + cb, user_data); }); } else { // invoke directly. @@ -61,7 +61,7 @@ void AuthMetadataProcessorAyncWrapper::Process( } } -void AuthMetadataProcessorAyncWrapper::InvokeProcessor( +void AuthMetadataProcessorAsyncWrapper::InvokeProcessor( grpc_auth_context* context, const grpc_metadata* md, size_t num_md, grpc_process_auth_metadata_done_cb cb, void* user_data) { AuthMetadataProcessor::InputMetadata metadata; @@ -104,10 +104,10 @@ int SecureServerCredentials::AddPortToServer(const std::string& addr, void SecureServerCredentials::SetAuthMetadataProcessor( const std::shared_ptr& processor) { - auto* wrapper = new grpc::AuthMetadataProcessorAyncWrapper(processor); + auto* wrapper = new grpc::AuthMetadataProcessorAsyncWrapper(processor); grpc_server_credentials_set_auth_metadata_processor( - creds_, {grpc::AuthMetadataProcessorAyncWrapper::Process, - grpc::AuthMetadataProcessorAyncWrapper::Destroy, wrapper}); + creds_, {grpc::AuthMetadataProcessorAsyncWrapper::Process, + grpc::AuthMetadataProcessorAsyncWrapper::Destroy, wrapper}); } std::shared_ptr SslServerCredentials( diff --git a/src/cpp/server/secure_server_credentials.h b/src/cpp/server/secure_server_credentials.h index ca90a25f4f245..a62e51f2c24e3 100644 --- a/src/cpp/server/secure_server_credentials.h +++ b/src/cpp/server/secure_server_credentials.h @@ -35,7 +35,7 @@ namespace grpc { class SecureServerCredentials; -class AuthMetadataProcessorAyncWrapper final { +class AuthMetadataProcessorAsyncWrapper final { public: static void Destroy(void* wrapper); @@ -43,7 +43,7 @@ class AuthMetadataProcessorAyncWrapper final { const grpc_metadata* md, size_t num_md, grpc_process_auth_metadata_done_cb cb, void* user_data); - explicit AuthMetadataProcessorAyncWrapper( + explicit AuthMetadataProcessorAsyncWrapper( const std::shared_ptr& processor) : processor_(processor) { if (processor && processor->IsBlocking()) { @@ -78,7 +78,7 @@ class SecureServerCredentials final : public ServerCredentials { SecureServerCredentials* AsSecureServerCredentials() override { return this; } grpc_server_credentials* creds_; - std::unique_ptr processor_; + std::unique_ptr processor_; }; } // namespace grpc From e8d9f222f551427d4c65cc37002de70f16982664 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 5 Dec 2023 15:05:31 -0800 Subject: [PATCH 046/127] [server] Make SetRegisteredMethodOnMetadata a method, not a static member fn (#35221) As part of the call-v3 work I'll be making a call to this code via a different path shortly, and separating the C-style callback piece out helps that work Closes #35221 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35221 from ctiller:cg-registered-method 4b6d80ee7f202cb083e2a3cb9811ce2d6a2cd269 PiperOrigin-RevId: 588200784 --- src/core/lib/surface/server.cc | 22 ++++++++++++---------- src/core/lib/surface/server.h | 3 +-- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/core/lib/surface/server.cc b/src/core/lib/surface/server.cc index a56f58d98e4bf..037e2b59e0b06 100644 --- a/src/core/lib/surface/server.cc +++ b/src/core/lib/surface/server.cc @@ -1331,7 +1331,10 @@ void Server::ChannelData::InitTransport(RefCountedPtr server, op->set_accept_stream = true; op->set_accept_stream_fn = AcceptStream; if (IsRegisteredMethodLookupInTransportEnabled()) { - op->set_registered_method_matcher_fn = SetRegisteredMethodOnMetadata; + op->set_registered_method_matcher_fn = [](void* arg, + ClientMetadata* metadata) { + static_cast(arg)->SetRegisteredMethodOnMetadata(*metadata); + }; } // op->set_registered_method_matcher_fn = Registered op->set_accept_stream_user_data = this; @@ -1387,30 +1390,29 @@ Server::ChannelRegisteredMethod* Server::ChannelData::GetRegisteredMethod( } void Server::ChannelData::SetRegisteredMethodOnMetadata( - void* arg, ServerMetadata* metadata) { - auto* chand = static_cast(arg); - auto* authority = metadata->get_pointer(HttpAuthorityMetadata()); + ClientMetadata& metadata) { + auto* authority = metadata.get_pointer(HttpAuthorityMetadata()); if (authority == nullptr) { - authority = metadata->get_pointer(HostMetadata()); + authority = metadata.get_pointer(HostMetadata()); if (authority == nullptr) { // Authority not being set is an RPC error. return; } } - auto* path = metadata->get_pointer(HttpPathMetadata()); + auto* path = metadata.get_pointer(HttpPathMetadata()); if (path == nullptr) { // Path not being set would result in an RPC error. return; } ChannelRegisteredMethod* method; if (!IsRegisteredMethodsMapEnabled()) { - method = chand->GetRegisteredMethod(authority->c_slice(), path->c_slice()); + method = GetRegisteredMethod(authority->c_slice(), path->c_slice()); } else { - method = chand->GetRegisteredMethod(authority->as_string_view(), - path->as_string_view()); + method = GetRegisteredMethod(authority->as_string_view(), + path->as_string_view()); } // insert in metadata - metadata->Set(GrpcRegisteredMethod(), method); + metadata.Set(GrpcRegisteredMethod(), method); } void Server::ChannelData::AcceptStream(void* arg, Transport* /*transport*/, diff --git a/src/core/lib/surface/server.h b/src/core/lib/surface/server.h index f5999bcda30ed..4e181c8bb379c 100644 --- a/src/core/lib/surface/server.h +++ b/src/core/lib/surface/server.h @@ -268,8 +268,7 @@ class Server : public InternallyRefCounted, static void AcceptStream(void* arg, Transport* /*transport*/, const void* transport_server_data); - static void SetRegisteredMethodOnMetadata(void* arg, - ServerMetadata* metadata); + void SetRegisteredMethodOnMetadata(ClientMetadata& metadata); void Destroy() ABSL_EXCLUSIVE_LOCKS_REQUIRED(server_->mu_global_); From e497eed25169d19e8bd9a39ea6526a861ead1ec7 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Wed, 6 Dec 2023 08:47:35 -0800 Subject: [PATCH 047/127] [XdsCertificateProvider] clean up some cruft (#35227) - Remove old-style channel args utility methods, which are unused. - Change `ChannelArgsCompare()` to delegate to the `Compare()` method. Closes #35227 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35227 from markdroth:xds_cert_provider_cleanup 57dc0c0757cb447880b88a27319ae80ad2b41894 PiperOrigin-RevId: 588440245 --- src/core/ext/xds/xds_certificate_provider.cc | 39 -------------------- src/core/ext/xds/xds_certificate_provider.h | 23 ++++-------- 2 files changed, 7 insertions(+), 55 deletions(-) diff --git a/src/core/ext/xds/xds_certificate_provider.cc b/src/core/ext/xds/xds_certificate_provider.cc index 0ca497939eed3..439921c648aae 100644 --- a/src/core/ext/xds/xds_certificate_provider.cc +++ b/src/core/ext/xds/xds_certificate_provider.cc @@ -374,43 +374,4 @@ void XdsCertificateProvider::WatchStatusCallback(std::string cert_name, if (it->second->IsSafeToRemove()) certificate_state_map_.erase(it); } -namespace { - -void* XdsCertificateProviderArgCopy(void* p) { - XdsCertificateProvider* xds_certificate_provider = - static_cast(p); - return xds_certificate_provider->Ref().release(); -} - -void XdsCertificateProviderArgDestroy(void* p) { - XdsCertificateProvider* xds_certificate_provider = - static_cast(p); - xds_certificate_provider->Unref(); -} - -int XdsCertificateProviderArgCmp(void* p, void* q) { - return QsortCompare(p, q); -} - -const grpc_arg_pointer_vtable kChannelArgVtable = { - XdsCertificateProviderArgCopy, XdsCertificateProviderArgDestroy, - XdsCertificateProviderArgCmp}; - -} // namespace - -grpc_arg XdsCertificateProvider::MakeChannelArg() const { - return grpc_channel_arg_pointer_create( - const_cast(GRPC_ARG_XDS_CERTIFICATE_PROVIDER), - const_cast(this), &kChannelArgVtable); -} - -RefCountedPtr -XdsCertificateProvider::GetFromChannelArgs(const grpc_channel_args* args) { - XdsCertificateProvider* xds_certificate_provider = - grpc_channel_args_find_pointer( - args, GRPC_ARG_XDS_CERTIFICATE_PROVIDER); - return xds_certificate_provider != nullptr ? xds_certificate_provider->Ref() - : nullptr; -} - } // namespace grpc_core diff --git a/src/core/ext/xds/xds_certificate_provider.h b/src/core/ext/xds/xds_certificate_provider.h index c17a7fa5cb728..44eb2421d8985 100644 --- a/src/core/ext/xds/xds_certificate_provider.h +++ b/src/core/ext/xds/xds_certificate_provider.h @@ -40,9 +40,6 @@ #include "src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h" #include "src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h" -#define GRPC_ARG_XDS_CERTIFICATE_PROVIDER \ - "grpc.internal.xds_certificate_provider" - namespace grpc_core { class XdsCertificateProvider : public grpc_tls_certificate_provider { @@ -50,15 +47,6 @@ class XdsCertificateProvider : public grpc_tls_certificate_provider { XdsCertificateProvider(); ~XdsCertificateProvider() override; - static absl::string_view ChannelArgName() { - return GRPC_ARG_XDS_CERTIFICATE_PROVIDER; - } - - static int ChannelArgsCompare(const XdsCertificateProvider* a, - const XdsCertificateProvider* b) { - return QsortCompare(a, b); - } - RefCountedPtr distributor() const override { return distributor_; } @@ -86,10 +74,13 @@ class XdsCertificateProvider : public grpc_tls_certificate_provider { void UpdateSubjectAlternativeNameMatchers( const std::string& cluster, std::vector matchers); - grpc_arg MakeChannelArg() const; - - static RefCountedPtr GetFromChannelArgs( - const grpc_channel_args* args); + static absl::string_view ChannelArgName() { + return "grpc.internal.xds_certificate_provider"; + } + static int ChannelArgsCompare(const XdsCertificateProvider* a, + const XdsCertificateProvider* b) { + return a->Compare(b); + } private: class ClusterCertificateState { From 295b665a183291194fa16a100735b145ff21d9ff Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 6 Dec 2023 10:58:32 -0800 Subject: [PATCH 048/127] [call-v3] Add CallInitiator, CallHandler wrappers around CallSpine (#35223) Closes #35223 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35223 from ctiller:cg-initiator 78826d99c54deab982a4dd2693f56924ed95989b PiperOrigin-RevId: 588481455 --- BUILD | 1 + Package.swift | 1 + build_autogenerated.yaml | 4 + gRPC-C++.podspec | 2 + gRPC-Core.podspec | 2 + grpc.gemspec | 1 + package.xml | 1 + src/core/lib/channel/connected_channel.cc | 4 +- src/core/lib/transport/transport.h | 180 +++++++++++++++++++--- tools/doxygen/Doxyfile.c++.internal | 1 + tools/doxygen/Doxyfile.core.internal | 1 + 11 files changed, 172 insertions(+), 26 deletions(-) diff --git a/BUILD b/BUILD index 6e02ac04d5297..d07866b8b9cd3 100644 --- a/BUILD +++ b/BUILD @@ -1604,6 +1604,7 @@ grpc_cc_library( "//src/core:slice_refcount", "//src/core:socket_mutator", "//src/core:stats_data", + "//src/core:status_flag", "//src/core:status_helper", "//src/core:strerror", "//src/core:thread_quota", diff --git a/Package.swift b/Package.swift index 210d9bc8f5682..65543f68046a5 100644 --- a/Package.swift +++ b/Package.swift @@ -1652,6 +1652,7 @@ let package = Package( "src/core/lib/promise/seq.h", "src/core/lib/promise/sleep.cc", "src/core/lib/promise/sleep.h", + "src/core/lib/promise/status_flag.h", "src/core/lib/promise/trace.cc", "src/core/lib/promise/trace.h", "src/core/lib/promise/try_seq.h", diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index 7eba4bf9d53ba..5ed752b05e055 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -1050,6 +1050,7 @@ libs: - src/core/lib/promise/race.h - src/core/lib/promise/seq.h - src/core/lib/promise/sleep.h + - src/core/lib/promise/status_flag.h - src/core/lib/promise/trace.h - src/core/lib/promise/try_seq.h - src/core/lib/resolver/endpoint_addresses.h @@ -2498,6 +2499,7 @@ libs: - src/core/lib/promise/race.h - src/core/lib/promise/seq.h - src/core/lib/promise/sleep.h + - src/core/lib/promise/status_flag.h - src/core/lib/promise/trace.h - src/core/lib/promise/try_seq.h - src/core/lib/resolver/endpoint_addresses.h @@ -4623,6 +4625,7 @@ libs: - src/core/lib/promise/promise.h - src/core/lib/promise/race.h - src/core/lib/promise/seq.h + - src/core/lib/promise/status_flag.h - src/core/lib/promise/trace.h - src/core/lib/promise/try_seq.h - src/core/lib/resolver/endpoint_addresses.h @@ -16950,6 +16953,7 @@ targets: - src/core/lib/promise/promise.h - src/core/lib/promise/race.h - src/core/lib/promise/seq.h + - src/core/lib/promise/status_flag.h - src/core/lib/promise/trace.h - src/core/lib/promise/try_seq.h - src/core/lib/resolver/endpoint_addresses.h diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index 1d2d74a278292..5e8485aad7503 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -1147,6 +1147,7 @@ Pod::Spec.new do |s| 'src/core/lib/promise/race.h', 'src/core/lib/promise/seq.h', 'src/core/lib/promise/sleep.h', + 'src/core/lib/promise/status_flag.h', 'src/core/lib/promise/trace.h', 'src/core/lib/promise/try_seq.h', 'src/core/lib/resolver/endpoint_addresses.h', @@ -2378,6 +2379,7 @@ Pod::Spec.new do |s| 'src/core/lib/promise/race.h', 'src/core/lib/promise/seq.h', 'src/core/lib/promise/sleep.h', + 'src/core/lib/promise/status_flag.h', 'src/core/lib/promise/trace.h', 'src/core/lib/promise/try_seq.h', 'src/core/lib/resolver/endpoint_addresses.h', diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 2e78799064665..0fd3d2636283f 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -1755,6 +1755,7 @@ Pod::Spec.new do |s| 'src/core/lib/promise/seq.h', 'src/core/lib/promise/sleep.cc', 'src/core/lib/promise/sleep.h', + 'src/core/lib/promise/status_flag.h', 'src/core/lib/promise/trace.cc', 'src/core/lib/promise/trace.h', 'src/core/lib/promise/try_seq.h', @@ -3140,6 +3141,7 @@ Pod::Spec.new do |s| 'src/core/lib/promise/race.h', 'src/core/lib/promise/seq.h', 'src/core/lib/promise/sleep.h', + 'src/core/lib/promise/status_flag.h', 'src/core/lib/promise/trace.h', 'src/core/lib/promise/try_seq.h', 'src/core/lib/resolver/endpoint_addresses.h', diff --git a/grpc.gemspec b/grpc.gemspec index ffcdbc601fcad..c7248f3c6b210 100644 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -1658,6 +1658,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/promise/seq.h ) s.files += %w( src/core/lib/promise/sleep.cc ) s.files += %w( src/core/lib/promise/sleep.h ) + s.files += %w( src/core/lib/promise/status_flag.h ) s.files += %w( src/core/lib/promise/trace.cc ) s.files += %w( src/core/lib/promise/trace.h ) s.files += %w( src/core/lib/promise/try_seq.h ) diff --git a/package.xml b/package.xml index 4ff9ece3cdd35..38b4ade03a121 100644 --- a/package.xml +++ b/package.xml @@ -1640,6 +1640,7 @@ + diff --git a/src/core/lib/channel/connected_channel.cc b/src/core/lib/channel/connected_channel.cc index 0ceba07e07567..9ea8faeb507d0 100644 --- a/src/core/lib/channel/connected_channel.cc +++ b/src/core/lib/channel/connected_channel.cc @@ -883,8 +883,8 @@ grpc_channel_filter MakeConnectedFilter() { } ArenaPromise MakeTransportCallPromise( - Transport* transport, CallArgs call_args, NextPromiseFactory) { - return transport->client_transport()->MakeCallPromise(std::move(call_args)); + Transport*, CallArgs, NextPromiseFactory) { + Crash("unimplemented"); } const grpc_channel_filter kPromiseBasedTransportFilter = diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h index a89b2084ba226..8fe728bb97800 100644 --- a/src/core/lib/transport/transport.h +++ b/src/core/lib/transport/transport.h @@ -57,6 +57,8 @@ #include "src/core/lib/promise/latch.h" #include "src/core/lib/promise/party.h" #include "src/core/lib/promise/pipe.h" +#include "src/core/lib/promise/race.h" +#include "src/core/lib/promise/status_flag.h" #include "src/core/lib/resource_quota/arena.h" #include "src/core/lib/slice/slice_buffer.h" #include "src/core/lib/transport/connectivity_state.h" @@ -244,18 +246,23 @@ class CallSpineInterface { virtual Pipe& client_to_server_messages() = 0; virtual Pipe& server_to_client_messages() = 0; virtual Pipe& server_trailing_metadata() = 0; - // Cancel the call with the given metadata. - // Regarding the `MUST_USE_RESULT absl::nullopt_t`: - // Most cancellation calls right now happen in pipe interceptors; - // there `nullopt` indicates terminate processing of this pipe and close with - // error. - // It's convenient then to have the Cancel operation (setting the latch to - // terminate the call) be the last thing that occurs in a pipe interceptor, - // and this construction supports that (and has helped the author not write - // some bugs). - GRPC_MUST_USE_RESULT virtual absl::nullopt_t Cancel( - ServerMetadataHandle metadata) = 0; + virtual Latch& cancel_latch() = 0; virtual Party& party() = 0; + virtual void IncrementRefCount() = 0; + virtual void Unref() = 0; + + GRPC_MUST_USE_RESULT absl::nullopt_t Cancel(ServerMetadataHandle metadata) { + GPR_DEBUG_ASSERT(Activity::current() == &party()); + auto& c = cancel_latch(); + if (c.is_set()) return absl::nullopt; + c.Set(std::move(metadata)); + return absl::nullopt; + } + + auto WaitForCancel() { + GPR_DEBUG_ASSERT(Activity::current() == &party()); + return cancel_latch().Wait(); + } // Wrap a promise so that if it returns failure it automatically cancels // the rest of the call. @@ -317,13 +324,10 @@ class CallSpine final : public CallSpineInterface { Pipe& server_trailing_metadata() override { return server_trailing_metadata_; } - absl::nullopt_t Cancel(ServerMetadataHandle metadata) override { - GPR_DEBUG_ASSERT(Activity::current() == &party()); - if (cancel_latch_.is_set()) return absl::nullopt; - cancel_latch_.Set(std::move(metadata)); - return absl::nullopt; - } + Latch& cancel_latch() override { return cancel_latch_; } Party& party() override { Crash("unimplemented"); } + void IncrementRefCount() override { Crash("unimplemented"); } + void Unref() override { Crash("unimplemented"); } private: // Initial metadata from client to server @@ -340,6 +344,132 @@ class CallSpine final : public CallSpineInterface { Latch cancel_latch_; }; +class CallInitiator { + public: + explicit CallInitiator(RefCountedPtr spine) + : spine_(std::move(spine)) {} + + auto PushClientInitialMetadata(ClientMetadataHandle md) { + GPR_DEBUG_ASSERT(Activity::current() == &spine_->party()); + return Map(spine_->client_initial_metadata().sender.Push(std::move(md)), + [](bool ok) { return StatusFlag(ok); }); + } + + auto PullServerInitialMetadata() { + GPR_DEBUG_ASSERT(Activity::current() == &spine_->party()); + return Map(spine_->server_initial_metadata().receiver.Next(), + [](NextResult md) + -> ValueOrFailure { + if (!md.has_value()) return Failure{}; + return std::move(*md); + }); + } + + auto PullServerTrailingMetadata() { + GPR_DEBUG_ASSERT(Activity::current() == &spine_->party()); + return Race(spine_->WaitForCancel(), + Map(spine_->server_trailing_metadata().receiver.Next(), + [spine = spine_](NextResult md) + -> ServerMetadataHandle { + GPR_ASSERT(md.has_value()); + return std::move(*md); + })); + } + + auto PullMessage() { + GPR_DEBUG_ASSERT(Activity::current() == &spine_->party()); + return spine_->server_to_client_messages().receiver.Next(); + } + + auto PushMessage(MessageHandle message) { + GPR_DEBUG_ASSERT(Activity::current() == &spine_->party()); + return spine_->client_to_server_messages().sender.Push(std::move(message)); + } + + template + auto CancelIfFails(Promise promise) { + return spine_->CancelIfFails(std::move(promise)); + } + + template + void SpawnGuarded(absl::string_view name, PromiseFactory promise_factory) { + spine_->SpawnGuarded(name, std::move(promise_factory)); + } + + template + void SpawnInfallible(absl::string_view name, PromiseFactory promise_factory) { + spine_->SpawnInfallible(name, std::move(promise_factory)); + } + + private: + const RefCountedPtr spine_; +}; + +class CallHandler { + public: + explicit CallHandler(RefCountedPtr spine) + : spine_(std::move(spine)) {} + + auto PullClientInitialMetadata() { + GPR_DEBUG_ASSERT(Activity::current() == &spine_->party()); + return Map(spine_->client_initial_metadata().receiver.Next(), + [](NextResult md) + -> ValueOrFailure { + if (!md.has_value()) return Failure{}; + return std::move(*md); + }); + } + + auto PushServerInitialMetadata(ClientMetadataHandle md) { + GPR_DEBUG_ASSERT(Activity::current() == &spine_->party()); + return Map(spine_->server_initial_metadata().sender.Push(std::move(md)), + [](bool ok) { return StatusFlag(ok); }); + } + + auto PushServerTrailingMetadata(ClientMetadataHandle md) { + GPR_DEBUG_ASSERT(Activity::current() == &spine_->party()); + return Map(spine_->server_initial_metadata().sender.Push(std::move(md)), + [](bool ok) { return StatusFlag(ok); }); + } + + auto PullMessage() { + GPR_DEBUG_ASSERT(Activity::current() == &spine_->party()); + return spine_->client_to_server_messages().receiver.Next(); + } + + auto PushMessage(MessageHandle message) { + GPR_DEBUG_ASSERT(Activity::current() == &spine_->party()); + return spine_->server_to_client_messages().sender.Push(std::move(message)); + } + + template + auto CancelIfFails(Promise promise) { + return spine_->CancelIfFails(std::move(promise)); + } + + template + void SpawnGuarded(absl::string_view name, PromiseFactory promise_factory) { + spine_->SpawnGuarded(name, std::move(promise_factory)); + } + + template + void SpawnInfallible(absl::string_view name, PromiseFactory promise_factory) { + spine_->SpawnInfallible(name, std::move(promise_factory)); + } + + private: + const RefCountedPtr spine_; +}; + +template +auto OutgoingMessages(CallHalf& h) { + struct Wrapper { + CallHalf& h; + auto Next() { return h.PullMessage(); } + }; + return Wrapper{h}; +} + } // namespace grpc_core // forward declarations @@ -745,9 +875,7 @@ class FilterStackTransport { class ClientTransport { public: - // Create a promise to execute one client call. - virtual ArenaPromise MakeCallPromise( - CallArgs call_args) = 0; + virtual void StartCall(CallHandler call_handler) = 0; protected: ~ClientTransport() = default; @@ -755,10 +883,14 @@ class ClientTransport { class ServerTransport { public: - // Register the factory function for the filter stack part of a call - // promise. - void SetCallPromiseFactory( - absl::AnyInvocable(CallArgs) const>); + // AcceptFunction takes initial metadata for a new call and returns a + // CallInitiator object for it, for the transport to use to communicate with + // the CallHandler object passed to the application. + using AcceptFunction = + absl::AnyInvocable(ClientMetadata&) const>; + + // Called once slightly after transport setup to register the accept function. + virtual void SetAcceptFunction(AcceptFunction accept_function) = 0; protected: ~ServerTransport() = default; diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 5905f239563cf..03508b982b85f 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -2657,6 +2657,7 @@ src/core/lib/promise/race.h \ src/core/lib/promise/seq.h \ src/core/lib/promise/sleep.cc \ src/core/lib/promise/sleep.h \ +src/core/lib/promise/status_flag.h \ src/core/lib/promise/trace.cc \ src/core/lib/promise/trace.h \ src/core/lib/promise/try_seq.h \ diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index aa35ecb50b374..681c20500de01 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -2436,6 +2436,7 @@ src/core/lib/promise/race.h \ src/core/lib/promise/seq.h \ src/core/lib/promise/sleep.cc \ src/core/lib/promise/sleep.h \ +src/core/lib/promise/status_flag.h \ src/core/lib/promise/trace.cc \ src/core/lib/promise/trace.h \ src/core/lib/promise/try_seq.h \ From 8c378461c368c43d591190b63973f6a8d8a0fbd9 Mon Sep 17 00:00:00 2001 From: AJ Heller Date: Wed, 6 Dec 2023 11:21:11 -0800 Subject: [PATCH 049/127] [example] C++ Debugging (#35222) --- examples/cpp/debugging/BUILD | 42 ++++++ examples/cpp/debugging/README.md | 132 ++++++++++++++++++ .../cpp/debugging/crashing_greeter_client.cc | 92 ++++++++++++ .../greeter_callback_server_admin.cc | 86 ++++++++++++ 4 files changed, 352 insertions(+) create mode 100644 examples/cpp/debugging/BUILD create mode 100644 examples/cpp/debugging/README.md create mode 100644 examples/cpp/debugging/crashing_greeter_client.cc create mode 100644 examples/cpp/debugging/greeter_callback_server_admin.cc diff --git a/examples/cpp/debugging/BUILD b/examples/cpp/debugging/BUILD new file mode 100644 index 0000000000000..c75995395d159 --- /dev/null +++ b/examples/cpp/debugging/BUILD @@ -0,0 +1,42 @@ +# Copyright 2023 the gRPC authors. +# +# Licensed 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. + +licenses(["notice"]) + +cc_binary( + name = "crashing_greeter_client", + srcs = ["crashing_greeter_client.cc"], + defines = ["BAZEL_BUILD"], + deps = [ + "//:grpc++", + "//examples/protos:helloworld_cc_grpc", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/flags:parse", + ], +) + +cc_binary( + name = "greeter_callback_server_admin", + srcs = ["greeter_callback_server_admin.cc"], + defines = ["BAZEL_BUILD"], + deps = [ + "//:grpc++", + "//:grpc++_reflection", + "//:grpcpp_admin", + "//examples/protos:helloworld_cc_grpc", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/flags:parse", + "@com_google_absl//absl/strings:str_format", + ], +) diff --git a/examples/cpp/debugging/README.md b/examples/cpp/debugging/README.md new file mode 100644 index 0000000000000..09a75146d467c --- /dev/null +++ b/examples/cpp/debugging/README.md @@ -0,0 +1,132 @@ +# gRPC C++ Debugging Example + +This example demonstrates a handful of ways you can debug your gRPC C++ applications. + +## Enabling Trace Logs + +gRPC allows you to configure more detailed log output for various aspects of gRPC behavior. The tracing log generation might have a large overhead and result in significantly larger log file sizes, especially when you try to trace transport or timer_check. But it is a powerful tool in your debugging toolkit. + +### The Most Verbose Logging + +Specify environment variables, then run your application: + +``` +GRPC_VERBOSITY=debug +GRPC_TRACE=all +``` + +For more granularity, please see +[environment_variables](https://github.com/grpc/grpc/blob/master/doc/environment_variables.md). + +### Debug Transport Protocol + +``` +GRPC_VERBOSITY=debug +GRPC_TRACE=tcp,http,secure_endpoint,transport_security +``` + +### Debug Connection Behavior + +``` +GRPC_VERBOSITY=debug +GRPC_TRACE=call_error,connectivity_state,pick_first,round_robin,glb +``` + +## GDB and other debuggers + +`gdb` (and the like) are tools that lets you inspect your application while it is running, view stack traces on exceptions, pause and step through code at specified points or under certain conditions, etc. See https://www.sourceware.org/gdb/ + +### Inspecting errors + +``` +bazel build --config=dbg examples/cpp/debugging:crashing_greeter_client +gdb -ex run \ + --args ./bazel-bin/examples/cpp/debugging/crashing_greeter_client \ + --crash_on_errors=true \ + --target=localhork:50051 +``` + +Once the exception is thrown, you can use `bt` to see the stack trace and examine the crash, `info threads` to get the set of threads, etc. See the [GDB documentation](https://sourceware.org/gdb/current/onlinedocs/gdb.html/) for a more complete list of available features and commands. + +### Breaking inside a function + +After building the application above, this will break inside gRPC generated stub code: + +``` +gdb -ex 'b helloworld::Greeter::Stub::SayHello' \ + -ex run \ + --args ./bazel-bin/examples/cpp/debugging/crashing_greeter_client \ + --crash_on_errors=true \ + --target=localhork:50051 +``` + +## gRPC Admin Interface: Live Channel Tracing + +The [gRPC Admin Service](https://github.com/grpc/proposal/blob/master/A38-admin-interface-api.md) +provides a convenient API in each gRPC language to improve the usability of +creating a gRPC server with admin services to expose states in the gRPC library. +This includes channelz, which is a channel tracing feature; it tracks statistics +like how many messages have been sent, how many of them failed, what are the +connected sockets. See the [Channelz design doc](https://github.com/grpc/proposal/blob/master/A14-channelz.md). + +### Integrating the gRPC Admin Service Into Your Server + +As seen in the `greeter_callback_admin_server` target, you canenable admin services by using the `AddAdminServices` method. + +``` +grpc::ServerBuilder builder; +grpc::AddAdminServices(&builder); +builder.AddListeningPort(":50051", grpc::ServerCredentials(...)); +std::unique_ptr server(builder.BuildAndStart()); +``` + +### Using grpcdebug + +grpcdebug is a tool created to access the metrics from channelz and health services. + +#### Installing the grpcdebug tool + +The source code is located in a github project +[grpc-ecosystem/grpcdebug](https://github.com/grpc-ecosystem/grpcdebug). You +can either download [the latest built version] +(https://github.com/grpc-ecosystem/grpcdebug/releases/latest) (recommended) or +follow the README.md to build it yourself. + +#### Running the grpcdebug tool +##### Usage +`grpcdebug [flags] channelz [argument]` + + +| Command | Argument | Description | +| :--------- | :------------------: | :------------------------------------------------ | +| channel | \ | Display channel states in a human readable way. | +| channels | | Lists client channels for the target application. | +| server | \ | Displays server state in a human readable way. | +| servers | | Lists servers in a human readable way. | +| socket | \ | Displays socket states in a human readable way. | +| subchannel | \ | Display subchannel states in human readable way. | + +Generally, you will start with either `servers` or `channels` and then work down +to the details + +##### Getting overall server info + +To begin with, build and run the server binary in the background + +``` +bazel build --config=dbg examples/cpp/debugging:all +./bazel-bin/examples/cpp/debugging/greeter_callback_server_admin& +``` + +You can then inspect the server +```bash +grpcdebug localhost:50051 channelz servers +``` + +This will show you the server ids with their activity +```text +Server ID Listen Addresses Calls(Started/Succeeded/Failed) Last Call Started +1 [[::]:50051] 38/34/3 now +``` + +For more information about `grpcdebug` features, please see [the grpcdebug documentation](https://github.com/grpc-ecosystem/grpcdebug) diff --git a/examples/cpp/debugging/crashing_greeter_client.cc b/examples/cpp/debugging/crashing_greeter_client.cc new file mode 100644 index 0000000000000..732535539f153 --- /dev/null +++ b/examples/cpp/debugging/crashing_greeter_client.cc @@ -0,0 +1,92 @@ +// Copyright 2023 The gRPC Authors +// +// Licensed 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. + +#include +#include +#include + +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" + +#include + +#ifdef BAZEL_BUILD +#include "examples/protos/helloworld.grpc.pb.h" +#else +#include "helloworld.grpc.pb.h" +#endif + +ABSL_FLAG(bool, crash_on_errors, false, + "Crash the application on client errors"); +ABSL_FLAG(std::string, target, "localhost:50051", "Server address"); + +using grpc::Channel; +using grpc::ClientContext; +using grpc::Status; +using helloworld::Greeter; +using helloworld::HelloReply; +using helloworld::HelloRequest; + +class GreeterClient { + public: + GreeterClient(std::shared_ptr channel) + : stub_(Greeter::NewStub(channel)) {} + + // Assembles the client's payload, sends it and presents the response back + // from the server. + std::string SayHello(const std::string& user) { + // Data we are sending to the server. + HelloRequest request; + request.set_name(user); + + // Container for the data we expect from the server. + HelloReply reply; + + // Context for the client. It could be used to convey extra information to + // the server and/or tweak certain RPC behaviors. + ClientContext context; + + // The actual RPC. + Status status = stub_->SayHello(&context, request, &reply); + + // Act upon the status of the actual RPC. + if (absl::GetFlag(FLAGS_crash_on_errors)) { + assert(status.ok()); + } + if (status.ok()) { + return reply.message(); + } else { + return "RPC failed"; + } + } + + private: + std::unique_ptr stub_; +}; + +int main(int argc, char** argv) { + absl::ParseCommandLine(argc, argv); + // Instantiate the client. It requires a channel, out of which the actual RPCs + // are created. This channel models a connection to an endpoint specified by + // the argument "--target=" which is the only expected argument. + // We indicate that the channel isn't authenticated (use of + // InsecureChannelCredentials()). + GreeterClient greeter(grpc::CreateChannel( + absl::GetFlag(FLAGS_target), grpc::InsecureChannelCredentials())); + std::string user("world"); + std::string reply = greeter.SayHello(user); + std::cout << "Greeter received: " << reply << std::endl; + + return 0; +} diff --git a/examples/cpp/debugging/greeter_callback_server_admin.cc b/examples/cpp/debugging/greeter_callback_server_admin.cc new file mode 100644 index 0000000000000..397503f4e6d95 --- /dev/null +++ b/examples/cpp/debugging/greeter_callback_server_admin.cc @@ -0,0 +1,86 @@ +// Copyright 2023 The gRPC Authors +// +// Licensed 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. + +#include +#include +#include + +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "absl/strings/str_format.h" + +#include +#include +#include +#include + +#ifdef BAZEL_BUILD +#include "examples/protos/helloworld.grpc.pb.h" +#else +#include "helloworld.grpc.pb.h" +#endif + +ABSL_FLAG(uint16_t, port, 50051, "Server port for the service"); + +using grpc::CallbackServerContext; +using grpc::Server; +using grpc::ServerBuilder; +using grpc::ServerUnaryReactor; +using grpc::Status; +using helloworld::Greeter; +using helloworld::HelloReply; +using helloworld::HelloRequest; + +// Logic and data behind the server's behavior. +class GreeterServiceImpl final : public Greeter::CallbackService { + ServerUnaryReactor* SayHello(CallbackServerContext* context, + const HelloRequest* request, + HelloReply* reply) override { + std::string prefix("Hello "); + reply->set_message(prefix + request->name()); + + ServerUnaryReactor* reactor = context->DefaultReactor(); + reactor->Finish(Status::OK); + return reactor; + } +}; + +void RunServer(uint16_t port) { + std::string server_address = absl::StrFormat("0.0.0.0:%d", port); + GreeterServiceImpl service; + + grpc::EnableDefaultHealthCheckService(true); + grpc::reflection::InitProtoReflectionServerBuilderPlugin(); + ServerBuilder builder; + // Enable gRPC Admin Services + grpc::AddAdminServices(&builder); + // Listen on the given address without any authentication mechanism. + builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); + // Register "service" as the instance through which we'll communicate with + // clients. In this case it corresponds to an *synchronous* service. + builder.RegisterService(&service); + // Finally assemble the server. + std::unique_ptr server(builder.BuildAndStart()); + std::cout << "Server listening on " << server_address << std::endl; + + // Wait for the server to shutdown. Note that some other thread must be + // responsible for shutting down the server for this call to ever return. + server->Wait(); +} + +int main(int argc, char** argv) { + absl::ParseCommandLine(argc, argv); + RunServer(absl::GetFlag(FLAGS_port)); + return 0; +} From 626bf5351b6af8aa10e18f14c4eba3b8e1ade1c4 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Wed, 6 Dec 2023 12:51:17 -0800 Subject: [PATCH 050/127] [experiments] extend a bunch of experiments for a few months (#35230) Closes #35230 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35230 from markdroth:experiments_extend ea733a48407ae575438ea2835da82b3a3ab846be PiperOrigin-RevId: 588514902 --- src/core/lib/experiments/experiments.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/lib/experiments/experiments.yaml b/src/core/lib/experiments/experiments.yaml index 9bd319f2b282f..e3b89572e4388 100644 --- a/src/core/lib/experiments/experiments.yaml +++ b/src/core/lib/experiments/experiments.yaml @@ -53,7 +53,7 @@ allow_in_fuzzing_config: false - name: client_idleness description: If enabled, client channel idleness is enabled by default. - expiry: 2023/12/15 + expiry: 2024/03/15 owner: roth@google.com test_tags: [] - name: client_privacy @@ -152,7 +152,7 @@ - name: pick_first_happy_eyeballs description: Use Happy Eyeballs in pick_first. - expiry: 2024/01/15 + expiry: 2024/03/15 owner: roth@google.com test_tags: ["lb_unit_test", "cpp_lb_end2end_test", "xds_end2end_test"] - name: promise_based_client_call @@ -207,7 +207,7 @@ description: Change round_robin code to delegate to pick_first as per dualstack backend design. - expiry: 2023/12/15 + expiry: 2024/03/15 owner: roth@google.com test_tags: ["lb_unit_test", "cpp_lb_end2end_test", "xds_end2end_test"] - name: rstpit @@ -283,6 +283,6 @@ description: Change WRR code to delegate to pick_first as per dualstack backend design. - expiry: 2023/12/15 + expiry: 2024/03/15 owner: roth@google.com test_tags: ["lb_unit_test", "cpp_lb_end2end_test", "xds_end2end_test"] From a58f3f2df531c3fae2afaef39d37186cf9206778 Mon Sep 17 00:00:00 2001 From: Anirudh Ramachandra Date: Wed, 6 Dec 2023 12:51:29 -0800 Subject: [PATCH 051/127] [core] Add support for RefIfNonZero in InternallyRefCounted. (#34869) The support already exists in RefCounted and DualRefcounted, so expose similar API for InternallyRefCounted class Closes #34869 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/34869 from anicr7:orphanable_ref_if_nonzero f57c64dc6224f64450ff3438b0b22d55a3d931bb PiperOrigin-RevId: 588514955 --- src/core/lib/gprpp/orphanable.h | 11 +++++++++++ test/core/gprpp/orphanable_test.cc | 26 ++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/core/lib/gprpp/orphanable.h b/src/core/lib/gprpp/orphanable.h index 86319429e5c2d..5a77ad46b452c 100644 --- a/src/core/lib/gprpp/orphanable.h +++ b/src/core/lib/gprpp/orphanable.h @@ -108,6 +108,17 @@ class InternallyRefCounted : public Orphanable { } } + GRPC_MUST_USE_RESULT RefCountedPtr RefIfNonZero() { + return RefCountedPtr(refs_.RefIfNonZero() ? static_cast(this) + : nullptr); + } + GRPC_MUST_USE_RESULT RefCountedPtr RefIfNonZero( + const DebugLocation& location, const char* reason) { + return RefCountedPtr(refs_.RefIfNonZero(location, reason) + ? static_cast(this) + : nullptr); + } + private: void IncrementRefCount() { refs_.Ref(); } void IncrementRefCount(const DebugLocation& location, const char* reason) { diff --git a/test/core/gprpp/orphanable_test.cc b/test/core/gprpp/orphanable_test.cc index e5b741466614e..cea10b748f778 100644 --- a/test/core/gprpp/orphanable_test.cc +++ b/test/core/gprpp/orphanable_test.cc @@ -103,6 +103,32 @@ TEST(OrphanablePtr, InternallyRefCountedWithTracing) { baz->FinishWork(); } +class Qux : public InternallyRefCounted { + public: + Qux() : Qux(0) {} + explicit Qux(int value) : InternallyRefCounted("Qux"), value_(value) {} + ~Qux() override { self_ref_ = RefIfNonZero(DEBUG_LOCATION, "extra_work"); } + void Orphan() override { Unref(); } + int value() const { return value_; } + + void StartWork() { self_ref_ = RefIfNonZero(DEBUG_LOCATION, "work"); } + void FinishWork() { + // This is a little ugly, but it makes the logged ref and unref match up. + self_ref_.release(); + Unref(DEBUG_LOCATION, "work"); + } + + private: + int value_; + RefCountedPtr self_ref_; +}; + +TEST(OrphanablePtr, InternallyRefCountedIfNonZero) { + auto qux = MakeOrphanable(); + qux->StartWork(); + qux->FinishWork(); +} + } // namespace } // namespace testing } // namespace grpc_core From 1abfc9750225a7779ae6ceccf813bed257bec41d Mon Sep 17 00:00:00 2001 From: Yijie Ma Date: Wed, 6 Dec 2023 14:24:11 -0800 Subject: [PATCH 052/127] [EventEngine] Posix NativeDNSResolver implementation (#35153) Closes #35153 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35153 from yijiem:native_dns_resolver a4107f7d812c5f9986b1160e20b4ae9fee6e6e62 PiperOrigin-RevId: 588543137 --- CMakeLists.txt | 49 +++++++ Makefile | 2 + Package.swift | 3 + build_autogenerated.yaml | 39 ++++++ config.m4 | 1 + config.w32 | 1 + gRPC-C++.podspec | 4 + gRPC-Core.podspec | 5 + grpc.gemspec | 3 + grpc.gyp | 3 + package.xml | 3 + src/core/BUILD | 39 ++++++ src/core/lib/event_engine/ares_resolver.cc | 25 ++-- src/core/lib/event_engine/ares_resolver.h | 19 ++- .../posix_engine/native_dns_resolver.cc | 131 ++++++++++++++++++ .../posix_engine/native_dns_resolver.h | 61 ++++++++ .../event_engine/posix_engine/posix_engine.cc | 64 ++++++--- .../event_engine/posix_engine/posix_engine.h | 11 +- .../ref_counted_dns_resolver_interface.h | 55 ++++++++ .../event_engine/windows/windows_engine.cc | 6 +- src/python/grpcio/grpc_core_dependencies.py | 1 + test/core/event_engine/test_suite/BUILD | 18 +++ .../posix_event_engine_native_dns_test.cc | 51 +++++++ .../event_engine/test_suite/tests/dns_test.cc | 20 +++ tools/doxygen/Doxyfile.c++.internal | 3 + tools/doxygen/Doxyfile.core.internal | 3 + tools/run_tests/generated/tests.json | 20 +++ 27 files changed, 585 insertions(+), 55 deletions(-) create mode 100644 src/core/lib/event_engine/posix_engine/native_dns_resolver.cc create mode 100644 src/core/lib/event_engine/posix_engine/native_dns_resolver.h create mode 100644 src/core/lib/event_engine/ref_counted_dns_resolver_interface.h create mode 100644 test/core/event_engine/test_suite/posix_event_engine_native_dns_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d2a53f4ed695..9782163ed81af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1212,6 +1212,9 @@ if(gRPC_BUILD_TESTS) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) add_dependencies(buildtests_cxx posix_event_engine_connect_test) endif() + if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) + add_dependencies(buildtests_cxx posix_event_engine_native_dns_test) + endif() if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) add_dependencies(buildtests_cxx posix_event_engine_test) endif() @@ -2245,6 +2248,7 @@ add_library(grpc src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc src/core/lib/event_engine/posix_engine/internal_errqueue.cc src/core/lib/event_engine/posix_engine/lockfree_event.cc + src/core/lib/event_engine/posix_engine/native_dns_resolver.cc src/core/lib/event_engine/posix_engine/posix_endpoint.cc src/core/lib/event_engine/posix_engine/posix_engine.cc src/core/lib/event_engine/posix_engine/posix_engine_listener.cc @@ -2973,6 +2977,7 @@ add_library(grpc_unsecure src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc src/core/lib/event_engine/posix_engine/internal_errqueue.cc src/core/lib/event_engine/posix_engine/lockfree_event.cc + src/core/lib/event_engine/posix_engine/native_dns_resolver.cc src/core/lib/event_engine/posix_engine/posix_endpoint.cc src/core/lib/event_engine/posix_engine/posix_engine.cc src/core/lib/event_engine/posix_engine/posix_engine_listener.cc @@ -4961,6 +4966,7 @@ add_library(grpc_authorization_provider src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc src/core/lib/event_engine/posix_engine/internal_errqueue.cc src/core/lib/event_engine/posix_engine/lockfree_event.cc + src/core/lib/event_engine/posix_engine/native_dns_resolver.cc src/core/lib/event_engine/posix_engine/posix_endpoint.cc src/core/lib/event_engine/posix_engine/posix_engine.cc src/core/lib/event_engine/posix_engine/posix_engine_listener.cc @@ -18275,6 +18281,48 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) ) +endif() +endif() +if(gRPC_BUILD_TESTS) +if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) + + add_executable(posix_event_engine_native_dns_test + test/core/event_engine/event_engine_test_utils.cc + test/core/event_engine/test_suite/event_engine_test_framework.cc + test/core/event_engine/test_suite/posix/oracle_event_engine_posix.cc + test/core/event_engine/test_suite/posix_event_engine_native_dns_test.cc + test/core/event_engine/test_suite/tests/dns_test.cc + test/core/util/fake_udp_and_tcp_server.cc + test/cpp/util/get_grpc_test_runfile_dir.cc + test/cpp/util/windows/manifest_file.cc + ) + target_compile_features(posix_event_engine_native_dns_test PUBLIC cxx_std_14) + target_include_directories(posix_event_engine_native_dns_test + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + ${_gRPC_RE2_INCLUDE_DIR} + ${_gRPC_SSL_INCLUDE_DIR} + ${_gRPC_UPB_GENERATED_DIR} + ${_gRPC_UPB_GRPC_GENERATED_DIR} + ${_gRPC_UPB_INCLUDE_DIR} + ${_gRPC_XXHASH_INCLUDE_DIR} + ${_gRPC_ZLIB_INCLUDE_DIR} + third_party/googletest/googletest/include + third_party/googletest/googletest + third_party/googletest/googlemock/include + third_party/googletest/googlemock + ${_gRPC_PROTO_GENS_DIR} + ) + + target_link_libraries(posix_event_engine_native_dns_test + ${_gRPC_ALLTARGETS_LIBRARIES} + gtest + grpc++_test_util + ) + + endif() endif() if(gRPC_BUILD_TESTS) @@ -24603,6 +24651,7 @@ add_executable(test_core_transport_chaotic_good_frame_test src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc src/core/lib/event_engine/posix_engine/internal_errqueue.cc src/core/lib/event_engine/posix_engine/lockfree_event.cc + src/core/lib/event_engine/posix_engine/native_dns_resolver.cc src/core/lib/event_engine/posix_engine/posix_endpoint.cc src/core/lib/event_engine/posix_engine/posix_engine.cc src/core/lib/event_engine/posix_engine/posix_engine_listener.cc diff --git a/Makefile b/Makefile index 4833a2944fea3..224e74adc5e3b 100644 --- a/Makefile +++ b/Makefile @@ -1450,6 +1450,7 @@ LIBGRPC_SRC = \ src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc \ src/core/lib/event_engine/posix_engine/internal_errqueue.cc \ src/core/lib/event_engine/posix_engine/lockfree_event.cc \ + src/core/lib/event_engine/posix_engine/native_dns_resolver.cc \ src/core/lib/event_engine/posix_engine/posix_endpoint.cc \ src/core/lib/event_engine/posix_engine/posix_engine.cc \ src/core/lib/event_engine/posix_engine/posix_engine_listener.cc \ @@ -2028,6 +2029,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc \ src/core/lib/event_engine/posix_engine/internal_errqueue.cc \ src/core/lib/event_engine/posix_engine/lockfree_event.cc \ + src/core/lib/event_engine/posix_engine/native_dns_resolver.cc \ src/core/lib/event_engine/posix_engine/posix_endpoint.cc \ src/core/lib/event_engine/posix_engine/posix_engine.cc \ src/core/lib/event_engine/posix_engine/posix_engine_listener.cc \ diff --git a/Package.swift b/Package.swift index 65543f68046a5..9e501b405fd12 100644 --- a/Package.swift +++ b/Package.swift @@ -1277,6 +1277,8 @@ let package = Package( "src/core/lib/event_engine/posix_engine/internal_errqueue.h", "src/core/lib/event_engine/posix_engine/lockfree_event.cc", "src/core/lib/event_engine/posix_engine/lockfree_event.h", + "src/core/lib/event_engine/posix_engine/native_dns_resolver.cc", + "src/core/lib/event_engine/posix_engine/native_dns_resolver.h", "src/core/lib/event_engine/posix_engine/posix_endpoint.cc", "src/core/lib/event_engine/posix_engine/posix_endpoint.h", "src/core/lib/event_engine/posix_engine/posix_engine.cc", @@ -1303,6 +1305,7 @@ let package = Package( "src/core/lib/event_engine/posix_engine/wakeup_fd_posix.h", "src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.cc", "src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.h", + "src/core/lib/event_engine/ref_counted_dns_resolver_interface.h", "src/core/lib/event_engine/resolved_address.cc", "src/core/lib/event_engine/resolved_address_internal.h", "src/core/lib/event_engine/shim.cc", diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index 5ed752b05e055..392481ce4ccfe 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -877,6 +877,7 @@ libs: - src/core/lib/event_engine/posix_engine/grpc_polled_fd_posix.h - src/core/lib/event_engine/posix_engine/internal_errqueue.h - src/core/lib/event_engine/posix_engine/lockfree_event.h + - src/core/lib/event_engine/posix_engine/native_dns_resolver.h - src/core/lib/event_engine/posix_engine/posix_endpoint.h - src/core/lib/event_engine/posix_engine/posix_engine.h - src/core/lib/event_engine/posix_engine/posix_engine_closure.h @@ -891,6 +892,7 @@ libs: - src/core/lib/event_engine/posix_engine/wakeup_fd_pipe.h - src/core/lib/event_engine/posix_engine/wakeup_fd_posix.h - src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.h + - src/core/lib/event_engine/ref_counted_dns_resolver_interface.h - src/core/lib/event_engine/resolved_address_internal.h - src/core/lib/event_engine/shim.h - src/core/lib/event_engine/tcp_socket_utils.h @@ -1699,6 +1701,7 @@ libs: - src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc - src/core/lib/event_engine/posix_engine/internal_errqueue.cc - src/core/lib/event_engine/posix_engine/lockfree_event.cc + - src/core/lib/event_engine/posix_engine/native_dns_resolver.cc - src/core/lib/event_engine/posix_engine/posix_endpoint.cc - src/core/lib/event_engine/posix_engine/posix_engine.cc - src/core/lib/event_engine/posix_engine/posix_engine_listener.cc @@ -2331,6 +2334,7 @@ libs: - src/core/lib/event_engine/posix_engine/grpc_polled_fd_posix.h - src/core/lib/event_engine/posix_engine/internal_errqueue.h - src/core/lib/event_engine/posix_engine/lockfree_event.h + - src/core/lib/event_engine/posix_engine/native_dns_resolver.h - src/core/lib/event_engine/posix_engine/posix_endpoint.h - src/core/lib/event_engine/posix_engine/posix_engine.h - src/core/lib/event_engine/posix_engine/posix_engine_closure.h @@ -2345,6 +2349,7 @@ libs: - src/core/lib/event_engine/posix_engine/wakeup_fd_pipe.h - src/core/lib/event_engine/posix_engine/wakeup_fd_posix.h - src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.h + - src/core/lib/event_engine/ref_counted_dns_resolver_interface.h - src/core/lib/event_engine/resolved_address_internal.h - src/core/lib/event_engine/shim.h - src/core/lib/event_engine/tcp_socket_utils.h @@ -2777,6 +2782,7 @@ libs: - src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc - src/core/lib/event_engine/posix_engine/internal_errqueue.cc - src/core/lib/event_engine/posix_engine/lockfree_event.cc + - src/core/lib/event_engine/posix_engine/native_dns_resolver.cc - src/core/lib/event_engine/posix_engine/posix_endpoint.cc - src/core/lib/event_engine/posix_engine/posix_engine.cc - src/core/lib/event_engine/posix_engine/posix_engine_listener.cc @@ -4465,6 +4471,7 @@ libs: - src/core/lib/event_engine/posix_engine/grpc_polled_fd_posix.h - src/core/lib/event_engine/posix_engine/internal_errqueue.h - src/core/lib/event_engine/posix_engine/lockfree_event.h + - src/core/lib/event_engine/posix_engine/native_dns_resolver.h - src/core/lib/event_engine/posix_engine/posix_endpoint.h - src/core/lib/event_engine/posix_engine/posix_engine.h - src/core/lib/event_engine/posix_engine/posix_engine_closure.h @@ -4479,6 +4486,7 @@ libs: - src/core/lib/event_engine/posix_engine/wakeup_fd_pipe.h - src/core/lib/event_engine/posix_engine/wakeup_fd_posix.h - src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.h + - src/core/lib/event_engine/ref_counted_dns_resolver_interface.h - src/core/lib/event_engine/resolved_address_internal.h - src/core/lib/event_engine/shim.h - src/core/lib/event_engine/tcp_socket_utils.h @@ -4818,6 +4826,7 @@ libs: - src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc - src/core/lib/event_engine/posix_engine/internal_errqueue.cc - src/core/lib/event_engine/posix_engine/lockfree_event.cc + - src/core/lib/event_engine/posix_engine/native_dns_resolver.cc - src/core/lib/event_engine/posix_engine/posix_endpoint.cc - src/core/lib/event_engine/posix_engine/posix_engine.cc - src/core/lib/event_engine/posix_engine/posix_engine_listener.cc @@ -12970,6 +12979,33 @@ targets: platforms: - linux - posix +- name: posix_event_engine_native_dns_test + gtest: true + build: test + language: c++ + headers: + - test/core/event_engine/event_engine_test_utils.h + - test/core/event_engine/test_suite/event_engine_test_framework.h + - test/core/event_engine/test_suite/posix/oracle_event_engine_posix.h + - test/core/event_engine/test_suite/tests/dns_test.h + - test/core/util/fake_udp_and_tcp_server.h + - test/cpp/util/get_grpc_test_runfile_dir.h + - test/cpp/util/windows/manifest_file.h + src: + - test/core/event_engine/event_engine_test_utils.cc + - test/core/event_engine/test_suite/event_engine_test_framework.cc + - test/core/event_engine/test_suite/posix/oracle_event_engine_posix.cc + - test/core/event_engine/test_suite/posix_event_engine_native_dns_test.cc + - test/core/event_engine/test_suite/tests/dns_test.cc + - test/core/util/fake_udp_and_tcp_server.cc + - test/cpp/util/get_grpc_test_runfile_dir.cc + - test/cpp/util/windows/manifest_file.cc + deps: + - gtest + - grpc++_test_util + platforms: + - linux + - posix - name: posix_event_engine_test gtest: true build: test @@ -16795,6 +16831,7 @@ targets: - src/core/lib/event_engine/posix_engine/grpc_polled_fd_posix.h - src/core/lib/event_engine/posix_engine/internal_errqueue.h - src/core/lib/event_engine/posix_engine/lockfree_event.h + - src/core/lib/event_engine/posix_engine/native_dns_resolver.h - src/core/lib/event_engine/posix_engine/posix_endpoint.h - src/core/lib/event_engine/posix_engine/posix_engine.h - src/core/lib/event_engine/posix_engine/posix_engine_closure.h @@ -16809,6 +16846,7 @@ targets: - src/core/lib/event_engine/posix_engine/wakeup_fd_pipe.h - src/core/lib/event_engine/posix_engine/wakeup_fd_posix.h - src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.h + - src/core/lib/event_engine/ref_counted_dns_resolver_interface.h - src/core/lib/event_engine/resolved_address_internal.h - src/core/lib/event_engine/shim.h - src/core/lib/event_engine/tcp_socket_utils.h @@ -17129,6 +17167,7 @@ targets: - src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc - src/core/lib/event_engine/posix_engine/internal_errqueue.cc - src/core/lib/event_engine/posix_engine/lockfree_event.cc + - src/core/lib/event_engine/posix_engine/native_dns_resolver.cc - src/core/lib/event_engine/posix_engine/posix_endpoint.cc - src/core/lib/event_engine/posix_engine/posix_engine.cc - src/core/lib/event_engine/posix_engine/posix_engine_listener.cc diff --git a/config.m4 b/config.m4 index 01455fdd842ca..894bef129aa1c 100644 --- a/config.m4 +++ b/config.m4 @@ -540,6 +540,7 @@ if test "$PHP_GRPC" != "no"; then src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc \ src/core/lib/event_engine/posix_engine/internal_errqueue.cc \ src/core/lib/event_engine/posix_engine/lockfree_event.cc \ + src/core/lib/event_engine/posix_engine/native_dns_resolver.cc \ src/core/lib/event_engine/posix_engine/posix_endpoint.cc \ src/core/lib/event_engine/posix_engine/posix_engine.cc \ src/core/lib/event_engine/posix_engine/posix_engine_listener.cc \ diff --git a/config.w32 b/config.w32 index 0025913ecd7d3..f778ae8e4b05f 100644 --- a/config.w32 +++ b/config.w32 @@ -505,6 +505,7 @@ if (PHP_GRPC != "no") { "src\\core\\lib\\event_engine\\posix_engine\\event_poller_posix_default.cc " + "src\\core\\lib\\event_engine\\posix_engine\\internal_errqueue.cc " + "src\\core\\lib\\event_engine\\posix_engine\\lockfree_event.cc " + + "src\\core\\lib\\event_engine\\posix_engine\\native_dns_resolver.cc " + "src\\core\\lib\\event_engine\\posix_engine\\posix_endpoint.cc " + "src\\core\\lib\\event_engine\\posix_engine\\posix_engine.cc " + "src\\core\\lib\\event_engine\\posix_engine\\posix_engine_listener.cc " + diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index 5e8485aad7503..14b9978f503b6 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -951,6 +951,7 @@ Pod::Spec.new do |s| 'src/core/lib/event_engine/posix_engine/grpc_polled_fd_posix.h', 'src/core/lib/event_engine/posix_engine/internal_errqueue.h', 'src/core/lib/event_engine/posix_engine/lockfree_event.h', + 'src/core/lib/event_engine/posix_engine/native_dns_resolver.h', 'src/core/lib/event_engine/posix_engine/posix_endpoint.h', 'src/core/lib/event_engine/posix_engine/posix_engine.h', 'src/core/lib/event_engine/posix_engine/posix_engine_closure.h', @@ -965,6 +966,7 @@ Pod::Spec.new do |s| 'src/core/lib/event_engine/posix_engine/wakeup_fd_pipe.h', 'src/core/lib/event_engine/posix_engine/wakeup_fd_posix.h', 'src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.h', + 'src/core/lib/event_engine/ref_counted_dns_resolver_interface.h', 'src/core/lib/event_engine/resolved_address_internal.h', 'src/core/lib/event_engine/shim.h', 'src/core/lib/event_engine/tcp_socket_utils.h', @@ -2183,6 +2185,7 @@ Pod::Spec.new do |s| 'src/core/lib/event_engine/posix_engine/grpc_polled_fd_posix.h', 'src/core/lib/event_engine/posix_engine/internal_errqueue.h', 'src/core/lib/event_engine/posix_engine/lockfree_event.h', + 'src/core/lib/event_engine/posix_engine/native_dns_resolver.h', 'src/core/lib/event_engine/posix_engine/posix_endpoint.h', 'src/core/lib/event_engine/posix_engine/posix_engine.h', 'src/core/lib/event_engine/posix_engine/posix_engine_closure.h', @@ -2197,6 +2200,7 @@ Pod::Spec.new do |s| 'src/core/lib/event_engine/posix_engine/wakeup_fd_pipe.h', 'src/core/lib/event_engine/posix_engine/wakeup_fd_posix.h', 'src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.h', + 'src/core/lib/event_engine/ref_counted_dns_resolver_interface.h', 'src/core/lib/event_engine/resolved_address_internal.h', 'src/core/lib/event_engine/shim.h', 'src/core/lib/event_engine/tcp_socket_utils.h', diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 0fd3d2636283f..a1a61b62611bf 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -1380,6 +1380,8 @@ Pod::Spec.new do |s| 'src/core/lib/event_engine/posix_engine/internal_errqueue.h', 'src/core/lib/event_engine/posix_engine/lockfree_event.cc', 'src/core/lib/event_engine/posix_engine/lockfree_event.h', + 'src/core/lib/event_engine/posix_engine/native_dns_resolver.cc', + 'src/core/lib/event_engine/posix_engine/native_dns_resolver.h', 'src/core/lib/event_engine/posix_engine/posix_endpoint.cc', 'src/core/lib/event_engine/posix_engine/posix_endpoint.h', 'src/core/lib/event_engine/posix_engine/posix_engine.cc', @@ -1406,6 +1408,7 @@ Pod::Spec.new do |s| 'src/core/lib/event_engine/posix_engine/wakeup_fd_posix.h', 'src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.cc', 'src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.h', + 'src/core/lib/event_engine/ref_counted_dns_resolver_interface.h', 'src/core/lib/event_engine/resolved_address.cc', 'src/core/lib/event_engine/resolved_address_internal.h', 'src/core/lib/event_engine/shim.cc', @@ -2945,6 +2948,7 @@ Pod::Spec.new do |s| 'src/core/lib/event_engine/posix_engine/grpc_polled_fd_posix.h', 'src/core/lib/event_engine/posix_engine/internal_errqueue.h', 'src/core/lib/event_engine/posix_engine/lockfree_event.h', + 'src/core/lib/event_engine/posix_engine/native_dns_resolver.h', 'src/core/lib/event_engine/posix_engine/posix_endpoint.h', 'src/core/lib/event_engine/posix_engine/posix_engine.h', 'src/core/lib/event_engine/posix_engine/posix_engine_closure.h', @@ -2959,6 +2963,7 @@ Pod::Spec.new do |s| 'src/core/lib/event_engine/posix_engine/wakeup_fd_pipe.h', 'src/core/lib/event_engine/posix_engine/wakeup_fd_posix.h', 'src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.h', + 'src/core/lib/event_engine/ref_counted_dns_resolver_interface.h', 'src/core/lib/event_engine/resolved_address_internal.h', 'src/core/lib/event_engine/shim.h', 'src/core/lib/event_engine/tcp_socket_utils.h', diff --git a/grpc.gemspec b/grpc.gemspec index c7248f3c6b210..aef58159c38c5 100644 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -1283,6 +1283,8 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/event_engine/posix_engine/internal_errqueue.h ) s.files += %w( src/core/lib/event_engine/posix_engine/lockfree_event.cc ) s.files += %w( src/core/lib/event_engine/posix_engine/lockfree_event.h ) + s.files += %w( src/core/lib/event_engine/posix_engine/native_dns_resolver.cc ) + s.files += %w( src/core/lib/event_engine/posix_engine/native_dns_resolver.h ) s.files += %w( src/core/lib/event_engine/posix_engine/posix_endpoint.cc ) s.files += %w( src/core/lib/event_engine/posix_engine/posix_endpoint.h ) s.files += %w( src/core/lib/event_engine/posix_engine/posix_engine.cc ) @@ -1309,6 +1311,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/event_engine/posix_engine/wakeup_fd_posix.h ) s.files += %w( src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.cc ) s.files += %w( src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.h ) + s.files += %w( src/core/lib/event_engine/ref_counted_dns_resolver_interface.h ) s.files += %w( src/core/lib/event_engine/resolved_address.cc ) s.files += %w( src/core/lib/event_engine/resolved_address_internal.h ) s.files += %w( src/core/lib/event_engine/shim.cc ) diff --git a/grpc.gyp b/grpc.gyp index f81c129017235..7a29bd04e941e 100644 --- a/grpc.gyp +++ b/grpc.gyp @@ -770,6 +770,7 @@ 'src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc', 'src/core/lib/event_engine/posix_engine/internal_errqueue.cc', 'src/core/lib/event_engine/posix_engine/lockfree_event.cc', + 'src/core/lib/event_engine/posix_engine/native_dns_resolver.cc', 'src/core/lib/event_engine/posix_engine/posix_endpoint.cc', 'src/core/lib/event_engine/posix_engine/posix_engine.cc', 'src/core/lib/event_engine/posix_engine/posix_engine_listener.cc', @@ -1290,6 +1291,7 @@ 'src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc', 'src/core/lib/event_engine/posix_engine/internal_errqueue.cc', 'src/core/lib/event_engine/posix_engine/lockfree_event.cc', + 'src/core/lib/event_engine/posix_engine/native_dns_resolver.cc', 'src/core/lib/event_engine/posix_engine/posix_endpoint.cc', 'src/core/lib/event_engine/posix_engine/posix_engine.cc', 'src/core/lib/event_engine/posix_engine/posix_engine_listener.cc', @@ -2069,6 +2071,7 @@ 'src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc', 'src/core/lib/event_engine/posix_engine/internal_errqueue.cc', 'src/core/lib/event_engine/posix_engine/lockfree_event.cc', + 'src/core/lib/event_engine/posix_engine/native_dns_resolver.cc', 'src/core/lib/event_engine/posix_engine/posix_endpoint.cc', 'src/core/lib/event_engine/posix_engine/posix_engine.cc', 'src/core/lib/event_engine/posix_engine/posix_engine_listener.cc', diff --git a/package.xml b/package.xml index 38b4ade03a121..988766820114c 100644 --- a/package.xml +++ b/package.xml @@ -1265,6 +1265,8 @@ + + @@ -1291,6 +1293,7 @@ + diff --git a/src/core/BUILD b/src/core/BUILD index e6a4457ac0fb2..ffae458b39a18 100644 --- a/src/core/BUILD +++ b/src/core/BUILD @@ -2141,6 +2141,7 @@ grpc_cc_library( "forkable", "init_internally", "iomgr_port", + "native_dns_resolver", "no_destruct", "posix_event_engine_base_hdrs", "posix_event_engine_closure", @@ -2151,7 +2152,9 @@ grpc_cc_library( "posix_event_engine_tcp_socket_utils", "posix_event_engine_timer", "posix_event_engine_timer_manager", + "ref_counted_dns_resolver_interface", "useful", + "//:config_vars", "//:event_engine_base_hdrs", "//:gpr", "//:grpc_trace", @@ -2472,6 +2475,41 @@ grpc_cc_library( ], ) +grpc_cc_library( + name = "ref_counted_dns_resolver_interface", + hdrs = ["lib/event_engine/ref_counted_dns_resolver_interface.h"], + external_deps = ["absl/strings"], + deps = [ + "//:event_engine_base_hdrs", + "//:gpr_platform", + "//:orphanable", + ], +) + +grpc_cc_library( + name = "native_dns_resolver", + srcs = [ + "lib/event_engine/posix_engine/native_dns_resolver.cc", + ], + hdrs = [ + "lib/event_engine/posix_engine/native_dns_resolver.h", + ], + external_deps = [ + "absl/functional:any_invocable", + "absl/status", + "absl/status:statusor", + "absl/strings", + "absl/strings:str_format", + ], + deps = [ + "iomgr_port", + "ref_counted_dns_resolver_interface", + "useful", + "//:event_engine_base_hdrs", + "//:gpr", + ], +) + grpc_cc_library( name = "ares_resolver", srcs = [ @@ -2507,6 +2545,7 @@ grpc_cc_library( "posix_event_engine_closure", "posix_event_engine_event_poller", "posix_event_engine_tcp_socket_utils", + "ref_counted_dns_resolver_interface", "resolved_address", "slice", "windows_iocp", diff --git a/src/core/lib/event_engine/ares_resolver.cc b/src/core/lib/event_engine/ares_resolver.cc index d88f0a9c2450b..70813eb649a7d 100644 --- a/src/core/lib/event_engine/ares_resolver.cc +++ b/src/core/lib/event_engine/ares_resolver.cc @@ -193,7 +193,7 @@ AresResolver::CreateAresResolver( AresResolver::AresResolver( std::unique_ptr polled_fd_factory, std::shared_ptr event_engine, ares_channel channel) - : grpc_core::InternallyRefCounted( + : RefCountedDNSResolverInterface( GRPC_TRACE_FLAG_ENABLED(grpc_trace_ares_resolver) ? "AresResolver" : nullptr), channel_(channel), @@ -230,8 +230,8 @@ void AresResolver::Orphan() { } void AresResolver::LookupHostname( - absl::string_view name, absl::string_view default_port, - EventEngine::DNSResolver::LookupHostnameCallback callback) { + EventEngine::DNSResolver::LookupHostnameCallback callback, + absl::string_view name, absl::string_view default_port) { absl::string_view host; absl::string_view port_string; if (!grpc_core::SplitHostPort(name, &host, &port_string)) { @@ -296,8 +296,8 @@ void AresResolver::LookupHostname( } void AresResolver::LookupSRV( - absl::string_view name, - EventEngine::DNSResolver::LookupSRVCallback callback) { + EventEngine::DNSResolver::LookupSRVCallback callback, + absl::string_view name) { absl::string_view host; absl::string_view port; if (!grpc_core::SplitHostPort(name, &host, &port)) { @@ -325,8 +325,8 @@ void AresResolver::LookupSRV( } void AresResolver::LookupTXT( - absl::string_view name, - EventEngine::DNSResolver::LookupTXTCallback callback) { + EventEngine::DNSResolver::LookupTXTCallback callback, + absl::string_view name) { absl::string_view host; absl::string_view port; if (!grpc_core::SplitHostPort(name, &host, &port)) { @@ -387,7 +387,8 @@ void AresResolver::CheckSocketsLocked() { event_engine_->Run( [self = Ref(DEBUG_LOCATION, "CheckSocketsLocked"), fd_node]() mutable { - self->OnReadable(fd_node, absl::OkStatus()); + static_cast(self.get()) + ->OnReadable(fd_node, absl::OkStatus()); }); } else { // Otherwise register with the poller for readable event. @@ -396,7 +397,8 @@ void AresResolver::CheckSocketsLocked() { fd_node->polled_fd->RegisterForOnReadableLocked( [self = Ref(DEBUG_LOCATION, "CheckSocketsLocked"), fd_node](absl::Status status) mutable { - self->OnReadable(fd_node, status); + static_cast(self.get()) + ->OnReadable(fd_node, status); }); } } @@ -410,7 +412,8 @@ void AresResolver::CheckSocketsLocked() { fd_node->polled_fd->RegisterForOnWriteableLocked( [self = Ref(DEBUG_LOCATION, "CheckSocketsLocked"), fd_node](absl::Status status) mutable { - self->OnWritable(fd_node, status); + static_cast(self.get()) + ->OnWritable(fd_node, status); }); } } @@ -453,7 +456,7 @@ void AresResolver::MaybeStartTimerLocked() { ares_backup_poll_alarm_handle_ = event_engine_->RunAfter( kAresBackupPollAlarmDuration, [self = Ref(DEBUG_LOCATION, "MaybeStartTimerLocked")]() { - self->OnAresBackupPollAlarm(); + static_cast(self.get())->OnAresBackupPollAlarm(); }); } diff --git a/src/core/lib/event_engine/ares_resolver.h b/src/core/lib/event_engine/ares_resolver.h index df394ca69dc20..a1837f2ccf066 100644 --- a/src/core/lib/event_engine/ares_resolver.h +++ b/src/core/lib/event_engine/ares_resolver.h @@ -39,6 +39,7 @@ #include #include "src/core/lib/event_engine/grpc_polled_fd.h" +#include "src/core/lib/event_engine/ref_counted_dns_resolver_interface.h" #include "src/core/lib/gprpp/orphanable.h" #include "src/core/lib/gprpp/sync.h" @@ -54,7 +55,7 @@ extern grpc_core::TraceFlag grpc_trace_ares_resolver; } \ } while (0) -class AresResolver : public grpc_core::InternallyRefCounted { +class AresResolver : public RefCountedDNSResolverInterface { public: static absl::StatusOr> CreateAresResolver(absl::string_view dns_server, @@ -67,15 +68,13 @@ class AresResolver : public grpc_core::InternallyRefCounted { ~AresResolver() override; void Orphan() override ABSL_LOCKS_EXCLUDED(mutex_); - void LookupHostname(absl::string_view name, absl::string_view default_port, - EventEngine::DNSResolver::LookupHostnameCallback callback) - ABSL_LOCKS_EXCLUDED(mutex_); - void LookupSRV(absl::string_view name, - EventEngine::DNSResolver::LookupSRVCallback callback) - ABSL_LOCKS_EXCLUDED(mutex_); - void LookupTXT(absl::string_view name, - EventEngine::DNSResolver::LookupTXTCallback callback) - ABSL_LOCKS_EXCLUDED(mutex_); + void LookupHostname(EventEngine::DNSResolver::LookupHostnameCallback callback, + absl::string_view name, absl::string_view default_port) + ABSL_LOCKS_EXCLUDED(mutex_) override; + void LookupSRV(EventEngine::DNSResolver::LookupSRVCallback callback, + absl::string_view name) ABSL_LOCKS_EXCLUDED(mutex_) override; + void LookupTXT(EventEngine::DNSResolver::LookupTXTCallback callback, + absl::string_view name) ABSL_LOCKS_EXCLUDED(mutex_) override; private: // A FdNode saves (not owns) a live socket/fd which c-ares creates, and owns a diff --git a/src/core/lib/event_engine/posix_engine/native_dns_resolver.cc b/src/core/lib/event_engine/posix_engine/native_dns_resolver.cc new file mode 100644 index 0000000000000..79a9489d66189 --- /dev/null +++ b/src/core/lib/event_engine/posix_engine/native_dns_resolver.cc @@ -0,0 +1,131 @@ +// Copyright 2023 The gRPC Authors. +// +// Licensed 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. + +#include + +#include "src/core/lib/iomgr/port.h" + +#ifdef GRPC_POSIX_SOCKET_RESOLVE_ADDRESS + +#include +#include +#include + +#include +#include +#include +#include + +#include "absl/functional/any_invocable.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" + +#include "src/core/lib/event_engine/posix_engine/native_dns_resolver.h" +#include "src/core/lib/gpr/useful.h" +#include "src/core/lib/gprpp/host_port.h" + +namespace grpc_event_engine { +namespace experimental { +namespace { + +absl::StatusOr> +LookupHostnameBlocking(absl::string_view name, absl::string_view default_port) { + struct addrinfo hints; + struct addrinfo *result = nullptr, *resp; + std::string host; + std::string port; + // parse name, splitting it into host and port parts + grpc_core::SplitHostPort(name, &host, &port); + if (host.empty()) { + return absl::InvalidArgumentError(absl::StrCat("Unparseable name: ", name)); + } + if (port.empty()) { + if (default_port.empty()) { + return absl::InvalidArgumentError( + absl::StrFormat("No port in name %s or default_port argument", name)); + } + port = std::string(default_port); + } + // Call getaddrinfo + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; // ipv4 or ipv6 + hints.ai_socktype = SOCK_STREAM; // stream socket + hints.ai_flags = AI_PASSIVE; // for wildcard IP address + int s = getaddrinfo(host.c_str(), port.c_str(), &hints, &result); + if (s != 0) { + // Retry if well-known service name is recognized + const char* svc[][2] = {{"http", "80"}, {"https", "443"}}; + for (size_t i = 0; i < GPR_ARRAY_SIZE(svc); i++) { + if (port == svc[i][0]) { + s = getaddrinfo(host.c_str(), svc[i][1], &hints, &result); + break; + } + } + } + if (s != 0) { + return absl::UnknownError(absl::StrFormat( + "Address lookup failed for %s os_error: %s syscall: getaddrinfo", name, + gai_strerror(s))); + } + // Success path: fill in addrs + std::vector addresses; + for (resp = result; resp != nullptr; resp = resp->ai_next) { + addresses.emplace_back(resp->ai_addr, resp->ai_addrlen); + } + if (result) { + freeaddrinfo(result); + } + return addresses; +} + +} // namespace + +NativeDNSResolver::NativeDNSResolver(std::shared_ptr event_engine) + : event_engine_(std::move(event_engine)) {} + +void NativeDNSResolver::LookupHostname( + EventEngine::DNSResolver::LookupHostnameCallback on_resolved, + absl::string_view name, absl::string_view default_port) { + event_engine_->Run( + [name, default_port, on_resolved = std::move(on_resolved)]() mutable { + on_resolved(LookupHostnameBlocking(name, default_port)); + }); +} + +void NativeDNSResolver::LookupSRV( + EventEngine::DNSResolver::LookupSRVCallback on_resolved, + absl::string_view /* name */) { + // Not supported + event_engine_->Run([on_resolved = std::move(on_resolved)]() mutable { + on_resolved(absl::UnimplementedError( + "The Native resolver does not support looking up SRV records")); + }); +} + +void NativeDNSResolver::LookupTXT( + EventEngine::DNSResolver::LookupTXTCallback on_resolved, + absl::string_view /* name */) { + // Not supported + event_engine_->Run([on_resolved = std::move(on_resolved)]() mutable { + on_resolved(absl::UnimplementedError( + "The Native resolver does not support looking up TXT records")); + }); +} + +} // namespace experimental +} // namespace grpc_event_engine + +#endif // GRPC_POSIX_SOCKET_RESOLVE_ADDRESS diff --git a/src/core/lib/event_engine/posix_engine/native_dns_resolver.h b/src/core/lib/event_engine/posix_engine/native_dns_resolver.h new file mode 100644 index 0000000000000..411b090ab64e2 --- /dev/null +++ b/src/core/lib/event_engine/posix_engine/native_dns_resolver.h @@ -0,0 +1,61 @@ +// Copyright 2023 The gRPC Authors. +// +// Licensed 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 GRPC_SRC_CORE_LIB_EVENT_ENGINE_POSIX_ENGINE_NATIVE_DNS_RESOLVER_H +#define GRPC_SRC_CORE_LIB_EVENT_ENGINE_POSIX_ENGINE_NATIVE_DNS_RESOLVER_H + +#include + +#include + +#include "absl/strings/string_view.h" + +#include "src/core/lib/iomgr/port.h" + +#ifdef GRPC_POSIX_SOCKET_RESOLVE_ADDRESS + +#include + +#include "src/core/lib/event_engine/ref_counted_dns_resolver_interface.h" + +namespace grpc_event_engine { +namespace experimental { + +// An asynchronous DNS resolver which uses the native platform's getaddrinfo +// API. Only supports A/AAAA records. +class NativeDNSResolver : public RefCountedDNSResolverInterface { + public: + explicit NativeDNSResolver(std::shared_ptr event_engine); + + void LookupHostname( + EventEngine::DNSResolver::LookupHostnameCallback on_resolved, + absl::string_view name, absl::string_view default_port) override; + + void LookupSRV(EventEngine::DNSResolver::LookupSRVCallback on_resolved, + absl::string_view name) override; + + void LookupTXT(EventEngine::DNSResolver::LookupTXTCallback on_resolved, + absl::string_view name) override; + + void Orphan() override { delete this; } + + private: + std::shared_ptr event_engine_; +}; + +} // namespace experimental +} // namespace grpc_event_engine + +#endif // GRPC_POSIX_SOCKET_RESOLVE_ADDRESS +#endif // GRPC_SRC_CORE_LIB_EVENT_ENGINE_POSIX_ENGINE_NATIVE_DNS_RESOLVER_H diff --git a/src/core/lib/event_engine/posix_engine/posix_engine.cc b/src/core/lib/event_engine/posix_engine/posix_engine.cc index f7e9a035f6393..dad5bd03a6c8a 100644 --- a/src/core/lib/event_engine/posix_engine/posix_engine.cc +++ b/src/core/lib/event_engine/posix_engine/posix_engine.cc @@ -28,6 +28,7 @@ #include "absl/cleanup/cleanup.h" #include "absl/functional/any_invocable.h" #include "absl/status/status.h" +#include "absl/strings/match.h" #include "absl/strings/str_cat.h" #include @@ -36,12 +37,15 @@ #include #include +#include "src/core/lib/config/config_vars.h" #include "src/core/lib/debug/trace.h" +#include "src/core/lib/event_engine/ares_resolver.h" #include "src/core/lib/event_engine/forkable.h" #include "src/core/lib/event_engine/grpc_polled_fd.h" #include "src/core/lib/event_engine/poller.h" #include "src/core/lib/event_engine/posix.h" #include "src/core/lib/event_engine/posix_engine/grpc_polled_fd_posix.h" +#include "src/core/lib/event_engine/posix_engine/native_dns_resolver.h" #include "src/core/lib/event_engine/posix_engine/tcp_socket_utils.h" #include "src/core/lib/event_engine/posix_engine/timer.h" #include "src/core/lib/event_engine/tcp_socket_utils.h" @@ -90,6 +94,15 @@ class TimerForkCallbackMethods { static void PostforkChild() { g_timer_fork_manager->PostforkChild(); } }; +bool ShouldUseAresDnsResolver() { +#if GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_ARES_EV_DRIVER) + auto resolver_env = grpc_core::ConfigVars::Get().DnsResolver(); + return resolver_env.empty() || absl::EqualsIgnoreCase(resolver_env, "ares"); +#else // GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_ARES_EV_DRIVER) + return false; +#endif // GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_ARES_EV_DRIVER) +} + } // namespace #ifdef GRPC_POSIX_SOCKET_TCP @@ -517,49 +530,54 @@ EventEngine::TaskHandle PosixEventEngine::RunAfterInternal( return handle; } -#if GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_TCP) - PosixEventEngine::PosixDNSResolver::PosixDNSResolver( - grpc_core::OrphanablePtr ares_resolver) - : ares_resolver_(std::move(ares_resolver)) {} + grpc_core::OrphanablePtr dns_resolver) + : dns_resolver_(std::move(dns_resolver)) {} void PosixEventEngine::PosixDNSResolver::LookupHostname( LookupHostnameCallback on_resolve, absl::string_view name, absl::string_view default_port) { - ares_resolver_->LookupHostname(name, default_port, std::move(on_resolve)); + dns_resolver_->LookupHostname(std::move(on_resolve), name, default_port); } void PosixEventEngine::PosixDNSResolver::LookupSRV(LookupSRVCallback on_resolve, absl::string_view name) { - ares_resolver_->LookupSRV(name, std::move(on_resolve)); + dns_resolver_->LookupSRV(std::move(on_resolve), name); } void PosixEventEngine::PosixDNSResolver::LookupTXT(LookupTXTCallback on_resolve, absl::string_view name) { - ares_resolver_->LookupTXT(name, std::move(on_resolve)); + dns_resolver_->LookupTXT(std::move(on_resolve), name); } -#endif // GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_TCP) - absl::StatusOr> PosixEventEngine::GetDNSResolver( const EventEngine::DNSResolver::ResolverOptions& options) { -#if GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_TCP) - auto ares_resolver = AresResolver::CreateAresResolver( - options.dns_server, - std::make_unique(poller_manager_->Poller()), - shared_from_this()); - if (!ares_resolver.ok()) { - return ares_resolver.status(); +#ifndef GRPC_POSIX_SOCKET_RESOLVE_ADDRESS + grpc_core::Crash("Unable to get DNS resolver for this platform."); +#else // GRPC_POSIX_SOCKET_RESOLVE_ADDRESS + // If c-ares is supported on the platform, build according to user's + // configuration. + if (ShouldUseAresDnsResolver()) { +#if GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_ARES_EV_DRIVER) + GRPC_EVENT_ENGINE_DNS_TRACE("PosixEventEngine:%p creating AresResolver", + this); + auto ares_resolver = AresResolver::CreateAresResolver( + options.dns_server, + std::make_unique(poller_manager_->Poller()), + shared_from_this()); + if (!ares_resolver.ok()) { + return ares_resolver.status(); + } + return std::make_unique( + std::move(*ares_resolver)); +#endif // GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_ARES_EV_DRIVER) } + GRPC_EVENT_ENGINE_DNS_TRACE("PosixEventEngine:%p creating NativeDNSResolver", + this); return std::make_unique( - std::move(*ares_resolver)); -#else // GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_TCP) - // TODO(yijiem): Implement a basic A/AAAA-only native resolver in - // PosixEventEngine. - (void)options; - grpc_core::Crash("unimplemented"); -#endif // GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_TCP) + grpc_core::MakeOrphanable(shared_from_this())); +#endif // GRPC_POSIX_SOCKET_RESOLVE_ADDRESS } bool PosixEventEngine::IsWorkerThread() { grpc_core::Crash("unimplemented"); } diff --git a/src/core/lib/event_engine/posix_engine/posix_engine.h b/src/core/lib/event_engine/posix_engine/posix_engine.h index 50810a53b0875..e38479854e044 100644 --- a/src/core/lib/event_engine/posix_engine/posix_engine.h +++ b/src/core/lib/event_engine/posix_engine/posix_engine.h @@ -34,11 +34,11 @@ #include #include -#include "src/core/lib/event_engine/ares_resolver.h" #include "src/core/lib/event_engine/handle_containers.h" #include "src/core/lib/event_engine/posix.h" #include "src/core/lib/event_engine/posix_engine/event_poller.h" #include "src/core/lib/event_engine/posix_engine/timer_manager.h" +#include "src/core/lib/event_engine/ref_counted_dns_resolver_interface.h" #include "src/core/lib/event_engine/thread_pool/thread_pool.h" #include "src/core/lib/gprpp/orphanable.h" #include "src/core/lib/gprpp/sync.h" @@ -141,11 +141,8 @@ class PosixEventEngine final : public PosixEventEngineWithFdSupport, public: class PosixDNSResolver : public EventEngine::DNSResolver { public: - PosixDNSResolver() = delete; -#if GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_TCP) explicit PosixDNSResolver( - grpc_core::OrphanablePtr ares_resolver); -#endif // GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_TCP) + grpc_core::OrphanablePtr dns_resolver); void LookupHostname(LookupHostnameCallback on_resolve, absl::string_view name, absl::string_view default_port) override; @@ -154,10 +151,8 @@ class PosixEventEngine final : public PosixEventEngineWithFdSupport, void LookupTXT(LookupTXTCallback on_resolve, absl::string_view name) override; -#if GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_TCP) private: - grpc_core::OrphanablePtr ares_resolver_; -#endif // GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_TCP) + grpc_core::OrphanablePtr dns_resolver_; }; #ifdef GRPC_POSIX_SOCKET_TCP diff --git a/src/core/lib/event_engine/ref_counted_dns_resolver_interface.h b/src/core/lib/event_engine/ref_counted_dns_resolver_interface.h new file mode 100644 index 0000000000000..645788e9a833f --- /dev/null +++ b/src/core/lib/event_engine/ref_counted_dns_resolver_interface.h @@ -0,0 +1,55 @@ +// Copyright 2023 The gRPC Authors. +// +// Licensed 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 GRPC_SRC_CORE_LIB_EVENT_ENGINE_REF_COUNTED_DNS_RESOLVER_INTERFACE_H +#define GRPC_SRC_CORE_LIB_EVENT_ENGINE_REF_COUNTED_DNS_RESOLVER_INTERFACE_H + +#include + +#include + +#include "absl/strings/string_view.h" + +#include + +#include "src/core/lib/gprpp/orphanable.h" + +namespace grpc_event_engine { +namespace experimental { + +class RefCountedDNSResolverInterface + : public grpc_core::InternallyRefCounted { + public: + explicit RefCountedDNSResolverInterface(const char* trace = nullptr, + intptr_t initial_refcount = 1) + : grpc_core::InternallyRefCounted( + trace, initial_refcount) {} + + virtual void LookupHostname( + EventEngine::DNSResolver::LookupHostnameCallback on_resolved, + absl::string_view name, absl::string_view default_port) = 0; + + virtual void LookupSRV( + EventEngine::DNSResolver::LookupSRVCallback on_resolved, + absl::string_view name) = 0; + + virtual void LookupTXT( + EventEngine::DNSResolver::LookupTXTCallback on_resolved, + absl::string_view name) = 0; +}; + +} // namespace experimental +} // namespace grpc_event_engine + +#endif // GRPC_SRC_CORE_LIB_EVENT_ENGINE_REF_COUNTED_DNS_RESOLVER_INTERFACE_H diff --git a/src/core/lib/event_engine/windows/windows_engine.cc b/src/core/lib/event_engine/windows/windows_engine.cc index 24b5c8898e683..2512026703945 100644 --- a/src/core/lib/event_engine/windows/windows_engine.cc +++ b/src/core/lib/event_engine/windows/windows_engine.cc @@ -204,17 +204,17 @@ WindowsEventEngine::WindowsDNSResolver::WindowsDNSResolver( void WindowsEventEngine::WindowsDNSResolver::LookupHostname( LookupHostnameCallback on_resolve, absl::string_view name, absl::string_view default_port) { - ares_resolver_->LookupHostname(name, default_port, std::move(on_resolve)); + ares_resolver_->LookupHostname(std::move(on_resolve), name, default_port); } void WindowsEventEngine::WindowsDNSResolver::LookupSRV( LookupSRVCallback on_resolve, absl::string_view name) { - ares_resolver_->LookupSRV(name, std::move(on_resolve)); + ares_resolver_->LookupSRV(std::move(on_resolve), name); } void WindowsEventEngine::WindowsDNSResolver::LookupTXT( LookupTXTCallback on_resolve, absl::string_view name) { - ares_resolver_->LookupTXT(name, std::move(on_resolve)); + ares_resolver_->LookupTXT(std::move(on_resolve), name); } #endif // GRPC_ARES == 1 && defined(GRPC_WINDOWS_SOCKET_ARES_EV_DRIVER) diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index 1d2fdd5bacc37..afbe5ec3ef000 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -514,6 +514,7 @@ 'src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc', 'src/core/lib/event_engine/posix_engine/internal_errqueue.cc', 'src/core/lib/event_engine/posix_engine/lockfree_event.cc', + 'src/core/lib/event_engine/posix_engine/native_dns_resolver.cc', 'src/core/lib/event_engine/posix_engine/posix_endpoint.cc', 'src/core/lib/event_engine/posix_engine/posix_engine.cc', 'src/core/lib/event_engine/posix_engine/posix_engine_listener.cc', diff --git a/test/core/event_engine/test_suite/BUILD b/test/core/event_engine/test_suite/BUILD index 63c37eb70ac6f..7abf2c2bf9b09 100644 --- a/test/core/event_engine/test_suite/BUILD +++ b/test/core/event_engine/test_suite/BUILD @@ -56,6 +56,24 @@ grpc_cc_test( ], ) +grpc_cc_test( + name = "posix_event_engine_native_dns_test", + srcs = ["posix_event_engine_native_dns_test.cc"], + tags = [ + "no_mac", + "no_windows", + ], + uses_event_engine = True, + uses_polling = True, + deps = [ + "//:config_vars", + "//src/core:posix_event_engine", + "//test/core/event_engine:event_engine_test_utils", + "//test/core/event_engine/test_suite/posix:oracle_event_engine_posix", + "//test/core/event_engine/test_suite/tests:dns", + ], +) + grpc_cc_test( name = "thready_posix_event_engine_test", srcs = ["thready_posix_event_engine_test.cc"], diff --git a/test/core/event_engine/test_suite/posix_event_engine_native_dns_test.cc b/test/core/event_engine/test_suite/posix_event_engine_native_dns_test.cc new file mode 100644 index 0000000000000..0f4ff26720bd5 --- /dev/null +++ b/test/core/event_engine/test_suite/posix_event_engine_native_dns_test.cc @@ -0,0 +1,51 @@ +// Copyright 2023 The gRPC Authors +// +// Licensed 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. +#include +#include +#include + +#include + +#include + +#include "src/core/lib/config/config_vars.h" +#include "src/core/lib/event_engine/posix_engine/posix_engine.h" +#include "test/core/event_engine/test_suite/event_engine_test_framework.h" +#include "test/core/event_engine/test_suite/posix/oracle_event_engine_posix.h" +#include "test/core/event_engine/test_suite/tests/dns_test.h" +#include "test/core/util/test_config.h" + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + grpc::testing::TestEnvironment env(&argc, argv); + SetEventEngineFactories( + []() { + return std::make_unique< + grpc_event_engine::experimental::PosixEventEngine>(); + }, + []() { + return std::make_unique< + grpc_event_engine::experimental::PosixOracleEventEngine>(); + }); + // TODO(ctiller): EventEngine temporarily needs grpc to be initialized first + // until we clear out the iomgr shutdown code. + grpc_core::ConfigVars::Overrides overrides; + overrides.dns_resolver = "native"; + grpc_core::ConfigVars::SetOverrides(overrides); + grpc_event_engine::experimental::InitDNSTests(); + grpc_init(); + int r = RUN_ALL_TESTS(); + grpc_shutdown(); + return r; +} diff --git a/test/core/event_engine/test_suite/tests/dns_test.cc b/test/core/event_engine/test_suite/tests/dns_test.cc index 4e585b59a7d6f..587b7094f975e 100644 --- a/test/core/event_engine/test_suite/tests/dns_test.cc +++ b/test/core/event_engine/test_suite/tests/dns_test.cc @@ -35,6 +35,7 @@ #include +#include "src/core/lib/config/config_vars.h" #include "src/core/lib/event_engine/tcp_socket_utils.h" #include "src/core/lib/gprpp/crash.h" // IWYU pragma: keep #include "src/core/lib/gprpp/notification.h" @@ -96,6 +97,15 @@ MATCHER(StatusCodeEq, "") { return std::get<0>(arg).code() == std::get<1>(arg); } +#define SKIP_TEST_FOR_NATIVE_DNS_RESOLVER() \ + do { \ + if (grpc_core::ConfigVars::Get().DnsResolver() == "native") { \ + GTEST_SKIP() \ + << "This test specifies a target DNS server which the native " \ + "DNS resolver does not support."; \ + } \ + } while (0) + } // namespace class EventEngineDNSTest : public EventEngineTest { @@ -227,6 +237,7 @@ EventEngineDNSTest::DNSServer EventEngineDNSTest::dns_server_; #ifndef GRPC_IOS_EVENT_ENGINE_CLIENT TEST_F(EventEngineDNSTest, QueryNXHostname) { + SKIP_TEST_FOR_NATIVE_DNS_RESOLVER(); auto dns_resolver = CreateDefaultDNSResolver(); dns_resolver->LookupHostname( [this](auto result) { @@ -242,6 +253,7 @@ TEST_F(EventEngineDNSTest, QueryNXHostname) { } TEST_F(EventEngineDNSTest, QueryWithIPLiteral) { + SKIP_TEST_FOR_NATIVE_DNS_RESOLVER(); auto dns_resolver = CreateDefaultDNSResolver(); dns_resolver->LookupHostname( [this](auto result) { @@ -257,6 +269,7 @@ TEST_F(EventEngineDNSTest, QueryWithIPLiteral) { } TEST_F(EventEngineDNSTest, QueryARecord) { + SKIP_TEST_FOR_NATIVE_DNS_RESOLVER(); auto dns_resolver = CreateDefaultDNSResolver(); dns_resolver->LookupHostname( [this](auto result) { @@ -274,6 +287,7 @@ TEST_F(EventEngineDNSTest, QueryARecord) { } TEST_F(EventEngineDNSTest, QueryAAAARecord) { + SKIP_TEST_FOR_NATIVE_DNS_RESOLVER(); auto dns_resolver = CreateDefaultDNSResolver(); dns_resolver->LookupHostname( [this](auto result) { @@ -294,6 +308,7 @@ TEST_F(EventEngineDNSTest, QueryAAAARecord) { } TEST_F(EventEngineDNSTest, TestAddressSorting) { + SKIP_TEST_FOR_NATIVE_DNS_RESOLVER(); auto dns_resolver = CreateDefaultDNSResolver(); dns_resolver->LookupHostname( [this](auto result) { @@ -311,6 +326,7 @@ TEST_F(EventEngineDNSTest, TestAddressSorting) { } TEST_F(EventEngineDNSTest, QuerySRVRecord) { + SKIP_TEST_FOR_NATIVE_DNS_RESOLVER(); const SRVRecord kExpectedRecords[] = { {/*host=*/"ipv4-only-multi-target.dns-test.event-engine", /*port=*/1234, /*priority=*/0, /*weight=*/0}, @@ -329,6 +345,7 @@ TEST_F(EventEngineDNSTest, QuerySRVRecord) { } TEST_F(EventEngineDNSTest, QuerySRVRecordWithLocalhost) { + SKIP_TEST_FOR_NATIVE_DNS_RESOLVER(); auto dns_resolver = CreateDefaultDNSResolver(); dns_resolver->LookupSRV( [this](auto result) { @@ -341,6 +358,7 @@ TEST_F(EventEngineDNSTest, QuerySRVRecordWithLocalhost) { } TEST_F(EventEngineDNSTest, QueryTXTRecord) { + SKIP_TEST_FOR_NATIVE_DNS_RESOLVER(); // clang-format off const std::string kExpectedRecord = "grpc_config=[{" @@ -370,6 +388,7 @@ TEST_F(EventEngineDNSTest, QueryTXTRecord) { } TEST_F(EventEngineDNSTest, QueryTXTRecordWithLocalhost) { + SKIP_TEST_FOR_NATIVE_DNS_RESOLVER(); auto dns_resolver = CreateDefaultDNSResolver(); dns_resolver->LookupTXT( [this](auto result) { @@ -382,6 +401,7 @@ TEST_F(EventEngineDNSTest, QueryTXTRecordWithLocalhost) { } TEST_F(EventEngineDNSTest, TestCancelActiveDNSQuery) { + SKIP_TEST_FOR_NATIVE_DNS_RESOLVER(); const std::string name = "dont-care-since-wont-be-resolved.test.com:1234"; auto dns_resolver = CreateDNSResolverWithNonResponsiveServer(); dns_resolver->LookupHostname( diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 03508b982b85f..5ff3e2299c99d 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -2282,6 +2282,8 @@ src/core/lib/event_engine/posix_engine/internal_errqueue.cc \ src/core/lib/event_engine/posix_engine/internal_errqueue.h \ src/core/lib/event_engine/posix_engine/lockfree_event.cc \ src/core/lib/event_engine/posix_engine/lockfree_event.h \ +src/core/lib/event_engine/posix_engine/native_dns_resolver.cc \ +src/core/lib/event_engine/posix_engine/native_dns_resolver.h \ src/core/lib/event_engine/posix_engine/posix_endpoint.cc \ src/core/lib/event_engine/posix_engine/posix_endpoint.h \ src/core/lib/event_engine/posix_engine/posix_engine.cc \ @@ -2308,6 +2310,7 @@ src/core/lib/event_engine/posix_engine/wakeup_fd_pipe.h \ src/core/lib/event_engine/posix_engine/wakeup_fd_posix.h \ src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.cc \ src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.h \ +src/core/lib/event_engine/ref_counted_dns_resolver_interface.h \ src/core/lib/event_engine/resolved_address.cc \ src/core/lib/event_engine/resolved_address_internal.h \ src/core/lib/event_engine/shim.cc \ diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 681c20500de01..9ba3a65871f1a 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -2058,6 +2058,8 @@ src/core/lib/event_engine/posix_engine/internal_errqueue.cc \ src/core/lib/event_engine/posix_engine/internal_errqueue.h \ src/core/lib/event_engine/posix_engine/lockfree_event.cc \ src/core/lib/event_engine/posix_engine/lockfree_event.h \ +src/core/lib/event_engine/posix_engine/native_dns_resolver.cc \ +src/core/lib/event_engine/posix_engine/native_dns_resolver.h \ src/core/lib/event_engine/posix_engine/posix_endpoint.cc \ src/core/lib/event_engine/posix_engine/posix_endpoint.h \ src/core/lib/event_engine/posix_engine/posix_engine.cc \ @@ -2084,6 +2086,7 @@ src/core/lib/event_engine/posix_engine/wakeup_fd_pipe.h \ src/core/lib/event_engine/posix_engine/wakeup_fd_posix.h \ src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.cc \ src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.h \ +src/core/lib/event_engine/ref_counted_dns_resolver_interface.h \ src/core/lib/event_engine/resolved_address.cc \ src/core/lib/event_engine/resolved_address_internal.h \ src/core/lib/event_engine/shim.cc \ diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index d58a72accec6f..6b2a8024173cf 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -6881,6 +6881,26 @@ ], "uses_polling": true }, + { + "args": [], + "benchmark": false, + "ci_platforms": [ + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": true, + "language": "c++", + "name": "posix_event_engine_native_dns_test", + "platforms": [ + "linux", + "posix" + ], + "uses_polling": true + }, { "args": [], "benchmark": false, From 6c816a4f9934c948481cacbda36d50895eb869aa Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 6 Dec 2023 14:31:01 -0800 Subject: [PATCH 053/127] [call-v3] Re-add accidentally deleted comment (#35235) Closes #35235 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35235 from ctiller:cg-fix-comment2 5abebaaadbf12701d704ca5fb67bcedb34254386 PiperOrigin-RevId: 588544922 --- src/core/lib/transport/transport.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h index 8fe728bb97800..f34692c8ddc0a 100644 --- a/src/core/lib/transport/transport.h +++ b/src/core/lib/transport/transport.h @@ -251,6 +251,15 @@ class CallSpineInterface { virtual void IncrementRefCount() = 0; virtual void Unref() = 0; + // Cancel the call with the given metadata. + // Regarding the `MUST_USE_RESULT absl::nullopt_t`: + // Most cancellation calls right now happen in pipe interceptors; + // there `nullopt` indicates terminate processing of this pipe and close with + // error. + // It's convenient then to have the Cancel operation (setting the latch to + // terminate the call) be the last thing that occurs in a pipe interceptor, + // and this construction supports that (and has helped the author not write + // some bugs). GRPC_MUST_USE_RESULT absl::nullopt_t Cancel(ServerMetadataHandle metadata) { GPR_DEBUG_ASSERT(Activity::current() == &party()); auto& c = cancel_latch(); From 5f92a67f948ea7436d78d7bc9be9ee0de883b64b Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 7 Dec 2023 07:58:01 -0800 Subject: [PATCH 054/127] [call-v3] Convert message size filter to new API (#35233) Closes #35233 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35233 from ctiller:cg-msg-size cce51d8bd526d86290e0ac0929eb77536d4e9948 PiperOrigin-RevId: 588793125 --- .../message_size/message_size_filter.cc | 122 ++++++--------- .../message_size/message_size_filter.h | 56 ++++--- src/core/lib/channel/promise_based_filter.h | 148 +++++++++++++++++- 3 files changed, 228 insertions(+), 98 deletions(-) diff --git a/src/core/ext/filters/message_size/message_size_filter.cc b/src/core/ext/filters/message_size/message_size_filter.cc index dcfc162ab62c5..fcd5677ff51dc 100644 --- a/src/core/ext/filters/message_size/message_size_filter.cc +++ b/src/core/ext/filters/message_size/message_size_filter.cc @@ -50,6 +50,13 @@ namespace grpc_core { +const NoInterceptor ClientMessageSizeFilter::Call::OnClientInitialMetadata; +const NoInterceptor ClientMessageSizeFilter::Call::OnServerInitialMetadata; +const NoInterceptor ClientMessageSizeFilter::Call::OnServerTrailingMetadata; +const NoInterceptor ServerMessageSizeFilter::Call::OnClientInitialMetadata; +const NoInterceptor ServerMessageSizeFilter::Call::OnServerInitialMetadata; +const NoInterceptor ServerMessageSizeFilter::Call::OnServerTrailingMetadata; + // // MessageSizeParsedConfig // @@ -138,60 +145,6 @@ const grpc_channel_filter ServerMessageSizeFilter::kFilter = kFilterExaminesOutboundMessages | kFilterExaminesInboundMessages>("message_size"); -class MessageSizeFilter::CallBuilder { - private: - auto Interceptor(uint32_t max_length, bool is_send) { - return [max_length, is_send, - err = err_](MessageHandle msg) -> absl::optional { - if (grpc_call_trace.enabled()) { - gpr_log(GPR_INFO, "%s[message_size] %s len:%" PRIdPTR " max:%d", - Activity::current()->DebugTag().c_str(), - is_send ? "send" : "recv", msg->payload()->Length(), - max_length); - } - if (msg->payload()->Length() > max_length) { - if (err->is_set()) return std::move(msg); - auto r = GetContext()->MakePooled( - GetContext()); - r->Set(GrpcStatusMetadata(), GRPC_STATUS_RESOURCE_EXHAUSTED); - r->Set(GrpcMessageMetadata(), - Slice::FromCopiedString( - absl::StrFormat("%s message larger than max (%u vs. %d)", - is_send ? "Sent" : "Received", - msg->payload()->Length(), max_length))); - err->Set(std::move(r)); - return absl::nullopt; - } - return std::move(msg); - }; - } - - public: - explicit CallBuilder(const MessageSizeParsedConfig& limits) - : limits_(limits) {} - - template - void AddSend(T* pipe_end) { - if (!limits_.max_send_size().has_value()) return; - pipe_end->InterceptAndMap(Interceptor(*limits_.max_send_size(), true)); - } - template - void AddRecv(T* pipe_end) { - if (!limits_.max_recv_size().has_value()) return; - pipe_end->InterceptAndMap(Interceptor(*limits_.max_recv_size(), false)); - } - - ArenaPromise Run( - CallArgs call_args, NextPromiseFactory next_promise_factory) { - return Race(err_->Wait(), next_promise_factory(std::move(call_args))); - } - - private: - Latch* const err_ = - GetContext()->ManagedNew>(); - MessageSizeParsedConfig limits_; -}; - absl::StatusOr ClientMessageSizeFilter::Create( const ChannelArgs& args, ChannelFilter::Args) { return ClientMessageSizeFilter(args); @@ -202,20 +155,40 @@ absl::StatusOr ServerMessageSizeFilter::Create( return ServerMessageSizeFilter(args); } -ArenaPromise ClientMessageSizeFilter::MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) { +namespace { +ServerMetadataHandle CheckPayload(const Message& msg, + absl::optional max_length, + bool is_send) { + if (!max_length.has_value()) return nullptr; + if (GRPC_TRACE_FLAG_ENABLED(grpc_call_trace)) { + gpr_log(GPR_INFO, "%s[message_size] %s len:%" PRIdPTR " max:%d", + Activity::current()->DebugTag().c_str(), is_send ? "send" : "recv", + msg.payload()->Length(), *max_length); + } + if (msg.payload()->Length() <= *max_length) return nullptr; + auto r = GetContext()->MakePooled(GetContext()); + r->Set(GrpcStatusMetadata(), GRPC_STATUS_RESOURCE_EXHAUSTED); + r->Set(GrpcMessageMetadata(), Slice::FromCopiedString(absl::StrFormat( + "%s message larger than max (%u vs. %d)", + is_send ? "Sent" : "Received", + msg.payload()->Length(), *max_length))); + return r; +} +} // namespace + +ClientMessageSizeFilter::Call::Call(ClientMessageSizeFilter* filter) + : limits_(filter->parsed_config_) { // Get max sizes from channel data, then merge in per-method config values. // Note: Per-method config is only available on the client, so we // apply the max request size to the send limit and the max response // size to the receive limit. - MessageSizeParsedConfig limits = this->limits(); const MessageSizeParsedConfig* config_from_call_context = MessageSizeParsedConfig::GetFromCallContext( GetContext(), - service_config_parser_index_); + filter->service_config_parser_index_); if (config_from_call_context != nullptr) { - absl::optional max_send_size = limits.max_send_size(); - absl::optional max_recv_size = limits.max_recv_size(); + absl::optional max_send_size = limits_.max_send_size(); + absl::optional max_recv_size = limits_.max_recv_size(); if (config_from_call_context->max_send_size().has_value() && (!max_send_size.has_value() || *config_from_call_context->max_send_size() < *max_send_size)) { @@ -226,21 +199,28 @@ ArenaPromise ClientMessageSizeFilter::MakeCallPromise( *config_from_call_context->max_recv_size() < *max_recv_size)) { max_recv_size = *config_from_call_context->max_recv_size(); } - limits = MessageSizeParsedConfig(max_send_size, max_recv_size); + limits_ = MessageSizeParsedConfig(max_send_size, max_recv_size); } +} + +ServerMetadataHandle ServerMessageSizeFilter::Call::OnClientToServerMessage( + const Message& message, ServerMessageSizeFilter* filter) { + return CheckPayload(message, filter->parsed_config_.max_recv_size(), false); +} + +ServerMetadataHandle ServerMessageSizeFilter::Call::OnServerToClientMessage( + const Message& message, ServerMessageSizeFilter* filter) { + return CheckPayload(message, filter->parsed_config_.max_send_size(), true); +} - CallBuilder b(limits); - b.AddSend(call_args.client_to_server_messages); - b.AddRecv(call_args.server_to_client_messages); - return b.Run(std::move(call_args), std::move(next_promise_factory)); +ServerMetadataHandle ClientMessageSizeFilter::Call::OnClientToServerMessage( + const Message& message) { + return CheckPayload(message, limits_.max_send_size(), true); } -ArenaPromise ServerMessageSizeFilter::MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) { - CallBuilder b(limits()); - b.AddSend(call_args.server_to_client_messages); - b.AddRecv(call_args.client_to_server_messages); - return b.Run(std::move(call_args), std::move(next_promise_factory)); +ServerMetadataHandle ClientMessageSizeFilter::Call::OnServerToClientMessage( + const Message& message) { + return CheckPayload(message, limits_.max_recv_size(), false); } namespace { diff --git a/src/core/ext/filters/message_size/message_size_filter.h b/src/core/ext/filters/message_size/message_size_filter.h index 75135a1b75e04..fdfba2fa788b2 100644 --- a/src/core/ext/filters/message_size/message_size_filter.h +++ b/src/core/ext/filters/message_size/message_size_filter.h @@ -86,48 +86,58 @@ class MessageSizeParser : public ServiceConfigParser::Parser { absl::optional GetMaxRecvSizeFromChannelArgs(const ChannelArgs& args); absl::optional GetMaxSendSizeFromChannelArgs(const ChannelArgs& args); -class MessageSizeFilter : public ChannelFilter { - protected: - explicit MessageSizeFilter(const ChannelArgs& args) - : limits_(MessageSizeParsedConfig::GetFromChannelArgs(args)) {} - - class CallBuilder; - - const MessageSizeParsedConfig& limits() const { return limits_; } - - private: - MessageSizeParsedConfig limits_; -}; - -class ServerMessageSizeFilter final : public MessageSizeFilter { +class ServerMessageSizeFilter final + : public ImplementChannelFilter { public: static const grpc_channel_filter kFilter; static absl::StatusOr Create( const ChannelArgs& args, ChannelFilter::Args filter_args); - // Construct a promise for one call. - ArenaPromise MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) override; + class Call { + public: + static const NoInterceptor OnClientInitialMetadata; + static const NoInterceptor OnServerInitialMetadata; + static const NoInterceptor OnServerTrailingMetadata; + ServerMetadataHandle OnClientToServerMessage( + const Message& message, ServerMessageSizeFilter* filter); + ServerMetadataHandle OnServerToClientMessage( + const Message& message, ServerMessageSizeFilter* filter); + }; private: - using MessageSizeFilter::MessageSizeFilter; + explicit ServerMessageSizeFilter(const ChannelArgs& args) + : parsed_config_(MessageSizeParsedConfig::GetFromChannelArgs(args)) {} + const MessageSizeParsedConfig parsed_config_; }; -class ClientMessageSizeFilter final : public MessageSizeFilter { +class ClientMessageSizeFilter final + : public ImplementChannelFilter { public: static const grpc_channel_filter kFilter; static absl::StatusOr Create( const ChannelArgs& args, ChannelFilter::Args filter_args); - // Construct a promise for one call. - ArenaPromise MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) override; + class Call { + public: + explicit Call(ClientMessageSizeFilter* filter); + + static const NoInterceptor OnClientInitialMetadata; + static const NoInterceptor OnServerInitialMetadata; + static const NoInterceptor OnServerTrailingMetadata; + ServerMetadataHandle OnClientToServerMessage(const Message& message); + ServerMetadataHandle OnServerToClientMessage(const Message& message); + + private: + MessageSizeParsedConfig limits_; + }; private: + explicit ClientMessageSizeFilter(const ChannelArgs& args) + : parsed_config_(MessageSizeParsedConfig::GetFromChannelArgs(args)) {} const size_t service_config_parser_index_{MessageSizeParser::ParserIndex()}; - using MessageSizeFilter::MessageSizeFilter; + const MessageSizeParsedConfig parsed_config_; }; } // namespace grpc_core diff --git a/src/core/lib/channel/promise_based_filter.h b/src/core/lib/channel/promise_based_filter.h index fa015fc6d3d56..abb9ce0fbe093 100644 --- a/src/core/lib/channel/promise_based_filter.h +++ b/src/core/lib/channel/promise_based_filter.h @@ -254,11 +254,31 @@ struct RaceAsyncCompletion { } }; +// Zero-member wrapper to make sure that Call always has a constructor +// that takes a channel pointer (even if it's thrown away) +template +class CallWrapper; + +template +class CallWrapper()))>> + : public Derived::Call { + public: + explicit CallWrapper(Derived* channel) : Derived::Call(channel) {} +}; + +template +class CallWrapper> + : public Derived::Call { + public: + explicit CallWrapper(Derived*) : Derived::Call() {} +}; + // For the original promise scheme polyfill: data associated with once call. template struct FilterCallData { - explicit FilterCallData(Derived* channel) : channel(channel) {} - GPR_NO_UNIQUE_ADDRESS typename Derived::Call call; + explicit FilterCallData(Derived* channel) : call(channel), channel(channel) {} + GPR_NO_UNIQUE_ADDRESS CallWrapper call; GPR_NO_UNIQUE_ADDRESS typename TypeIfNeeded, CallHasAsyncErrorInterceptor()>::Type @@ -347,9 +367,68 @@ inline auto RunCall(void (Derived::Call::*fn)(ClientMetadata& md, inline void InterceptClientToServerMessage(const NoInterceptor*, void*, const CallArgs&) {} +template +inline void InterceptClientToServerMessage( + ServerMetadataHandle (Derived::Call::*fn)(const Message&), + FilterCallData* call_data, const CallArgs& call_args) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnClientToServerMessage); + call_args.client_to_server_messages->InterceptAndMap( + [call_data](MessageHandle msg) -> absl::optional { + auto return_md = call_data->call.OnClientToServerMessage(*msg); + if (return_md == nullptr) return std::move(msg); + if (call_data->error_latch.is_set()) return absl::nullopt; + call_data->error_latch.Set(std::move(return_md)); + return absl::nullopt; + }); +} + +template +inline void InterceptClientToServerMessage( + ServerMetadataHandle (Derived::Call::*fn)(const Message&, Derived*), + FilterCallData* call_data, const CallArgs& call_args) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnClientToServerMessage); + call_args.client_to_server_messages->InterceptAndMap( + [call_data](MessageHandle msg) -> absl::optional { + auto return_md = + call_data->call.OnClientToServerMessage(*msg, call_data->channel); + if (return_md == nullptr) return std::move(msg); + if (call_data->error_latch.is_set()) return absl::nullopt; + call_data->error_latch.Set(std::move(return_md)); + return absl::nullopt; + }); +} + inline void InterceptClientToServerMessage(const NoInterceptor*, void*, void*, CallSpineInterface*) {} +template +inline void InterceptClientToServerMessage( + ServerMetadataHandle (Derived::Call::*fn)(const Message&), + typename Derived::Call* call, Derived*, CallSpineInterface* call_spine) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnClientToServerMessage); + call_spine->server_to_client_messages().sender.InterceptAndMap( + [call, call_spine](MessageHandle msg) -> absl::optional { + auto return_md = call->OnClientToServerMessage(*msg); + if (return_md == nullptr) return std::move(msg); + return call_spine->Cancel(std::move(return_md)); + }); +} + +template +inline void InterceptClientToServerMessage( + ServerMetadataHandle (Derived::Call::*fn)(const Message&, Derived*), + typename Derived::Call* call, Derived* channel, + CallSpineInterface* call_spine) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnClientToServerMessage); + call_spine->server_to_client_messages().sender.InterceptAndMap( + [call, call_spine, + channel](MessageHandle msg) -> absl::optional { + auto return_md = call->OnClientToServerMessage(*msg, channel); + if (return_md == nullptr) return std::move(msg); + return call_spine->Cancel(std::move(return_md)); + }); +} + inline void InterceptClientInitialMetadata(const NoInterceptor*, void*, void*, CallSpineInterface*) {} @@ -441,7 +520,6 @@ inline void InterceptServerInitialMetadata( }); } -template inline void InterceptServerInitialMetadata(const NoInterceptor*, void*, void*, CallSpineInterface*) {} @@ -474,9 +552,68 @@ inline void InterceptServerInitialMetadata( inline void InterceptServerToClientMessage(const NoInterceptor*, void*, const CallArgs&) {} +template +inline void InterceptServerToClientMessage( + ServerMetadataHandle (Derived::Call::*fn)(const Message&), + FilterCallData* call_data, const CallArgs& call_args) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnServerToClientMessage); + call_args.server_to_client_messages->InterceptAndMap( + [call_data](MessageHandle msg) -> absl::optional { + auto return_md = call_data->call.OnServerToClientMessage(*msg); + if (return_md == nullptr) return std::move(msg); + if (call_data->error_latch.is_set()) return absl::nullopt; + call_data->error_latch.Set(std::move(return_md)); + return absl::nullopt; + }); +} + +template +inline void InterceptServerToClientMessage( + ServerMetadataHandle (Derived::Call::*fn)(const Message&, Derived*), + FilterCallData* call_data, const CallArgs& call_args) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnServerToClientMessage); + call_args.server_to_client_messages->InterceptAndMap( + [call_data](MessageHandle msg) -> absl::optional { + auto return_md = + call_data->call.OnServerToClientMessage(*msg, call_data->channel); + if (return_md == nullptr) return std::move(msg); + if (call_data->error_latch.is_set()) return absl::nullopt; + call_data->error_latch.Set(std::move(return_md)); + return absl::nullopt; + }); +} + inline void InterceptServerToClientMessage(const NoInterceptor*, void*, void*, CallSpineInterface*) {} +template +inline void InterceptServerToClientMessage( + ServerMetadataHandle (Derived::Call::*fn)(const Message&), + typename Derived::Call* call, Derived*, CallSpineInterface* call_spine) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnServerToClientMessage); + call_spine->server_to_client_messages().sender.InterceptAndMap( + [call, call_spine](MessageHandle msg) -> absl::optional { + auto return_md = call->OnServerToClientMessage(*msg); + if (return_md == nullptr) return std::move(msg); + return call_spine->Cancel(std::move(return_md)); + }); +} + +template +inline void InterceptServerToClientMessage( + ServerMetadataHandle (Derived::Call::*fn)(const Message&, Derived*), + typename Derived::Call* call, Derived* channel, + CallSpineInterface* call_spine) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnServerToClientMessage); + call_spine->server_to_client_messages().sender.InterceptAndMap( + [call, call_spine, + channel](MessageHandle msg) -> absl::optional { + auto return_md = call->OnServerToClientMessage(*msg, channel); + if (return_md == nullptr) return std::move(msg); + return call_spine->Cancel(std::move(return_md)); + }); +} + inline void InterceptServerTrailingMetadata(const NoInterceptor*, void*, void*, CallSpineInterface*) {} @@ -574,7 +711,10 @@ class ImplementChannelFilter : public ChannelFilter { public: // Natively construct a v3 call. void InitCall(CallSpineInterface* call_spine) { - auto* call = GetContext()->ManagedNew(); + typename Derived::Call* call = + GetContext() + ->ManagedNew>( + static_cast(this)); promise_filter_detail::InterceptClientInitialMetadata( &Derived::Call::OnClientInitialMetadata, call, static_cast(this), call_spine); From dfa9d853fff02212ff232da5b39b76adf3ecce83 Mon Sep 17 00:00:00 2001 From: Leonardo Pistone Date: Thu, 7 Dec 2023 12:59:29 -0800 Subject: [PATCH 055/127] Fix Python DeprecationWarning: 'pipes' (#34941) Starting from Python 3.11, the pipes module produces this warning: DeprecationWarning: 'pipes' is deprecated and slated for removal in Python 3.13 Turns out that in this repo the pipes module is only used for the "quote" function which is turn directly taken from the shlex module [1]. The shlex module is not deprecated as of today and is already used in other places in this repo. The function shlex.quote has been around since the ancient Python 3.3. [1] https://github.com/python/cpython/blob/3.11/Lib/pipes.py#L64-L66 Closes #34941 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/34941 from lepistone:deprecate-python-pipes 233c54c135542178703aa700a2dddadc895fedb0 PiperOrigin-RevId: 588883480 --- tools/run_tests/run_performance_tests.py | 10 +++++----- tools/run_tests/run_tests.py | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/run_tests/run_performance_tests.py b/tools/run_tests/run_performance_tests.py index 808bc0a30bf84..064dbf3328d3c 100755 --- a/tools/run_tests/run_performance_tests.py +++ b/tools/run_tests/run_performance_tests.py @@ -21,8 +21,8 @@ import itertools import json import os -import pipes import re +import shlex import sys import time @@ -121,7 +121,7 @@ def create_scenario_jobspec( if bq_result_table: cmd += 'BQ_RESULT_TABLE="%s" ' % bq_result_table cmd += "tools/run_tests/performance/run_qps_driver.sh " - cmd += "--scenarios_json=%s " % pipes.quote( + cmd += "--scenarios_json=%s " % shlex.quote( json.dumps({"scenarios": [scenario_json]}) ) cmd += "--scenario_result_file=scenario_result.json " @@ -135,7 +135,7 @@ def create_scenario_jobspec( user_at_host = "%s@%s" % (_REMOTE_HOST_USERNAME, remote_host) cmd = 'ssh %s "cd ~/performance_workspace/grpc/ && "%s' % ( user_at_host, - pipes.quote(cmd), + shlex.quote(cmd), ) return jobset.JobSpec( @@ -157,7 +157,7 @@ def create_quit_jobspec(workers, remote_host=None): user_at_host = "%s@%s" % (_REMOTE_HOST_USERNAME, remote_host) cmd = 'ssh %s "cd ~/performance_workspace/grpc/ && "%s' % ( user_at_host, - pipes.quote(cmd), + shlex.quote(cmd), ) return jobset.JobSpec( @@ -192,7 +192,7 @@ def create_netperf_jobspec( user_at_host = "%s@%s" % (_REMOTE_HOST_USERNAME, client_host) cmd = 'ssh %s "cd ~/performance_workspace/grpc/ && "%s' % ( user_at_host, - pipes.quote(cmd), + shlex.quote(cmd), ) return jobset.JobSpec( diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index 88a9a648bbdfb..091817a065a97 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -26,10 +26,10 @@ import multiprocessing import os import os.path -import pipes import platform import random import re +import shlex import socket import subprocess import sys @@ -479,7 +479,7 @@ def test_specs(self): cmdline = [binary] + target["args"] shortname = target.get( "shortname", - " ".join(pipes.quote(arg) for arg in cmdline), + " ".join(shlex.quote(arg) for arg in cmdline), ) shortname += shortname_ext out.append( From de6c437c89ee54673e33f840eb759448abb22d13 Mon Sep 17 00:00:00 2001 From: Xuan Wang Date: Thu, 7 Dec 2023 13:06:02 -0800 Subject: [PATCH 056/127] [Python Misc] Revert change to print backtrace in server (#34877) Fix: https://github.com/grpc/grpc/issues/34853 In order to make debugging easier, we have begun printing backtraces in servers. However, this change has the unintended consequence of printing errors to stderr by default, which may not be expected by some users. This PR reverts the change. We recommend that users set up a logging sink if they want to see errors. We will add this to our documentation later. Closes #34877 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/34877 from XuanWang-Amos:revert_print_backtrace_change 8942308784b253fa6ae3f1a7dd03e4f89719cb30 PiperOrigin-RevId: 588885550 --- src/python/grpcio/grpc/_server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/grpcio/grpc/_server.py b/src/python/grpcio/grpc/_server.py index 595056136b766..4ea1d5e459784 100644 --- a/src/python/grpcio/grpc/_server.py +++ b/src/python/grpcio/grpc/_server.py @@ -579,7 +579,7 @@ def _call_behavior( exception.__traceback__, ) ) - traceback.print_exc() + traceback.print_exc() _LOGGER.exception(details) _abort( state, From 22537cb1931ef7640ad973382f63da68bd197d6b Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 7 Dec 2023 13:06:14 -0800 Subject: [PATCH 057/127] [call-v3] Convert server-call-tracer filter (#35249) Closes #35249 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35249 from ctiller:cg-server-call-tracer ad52acb64ffee39a1f8af3e803bfbd5eb134716a PiperOrigin-RevId: 588885615 --- .../filters/http/client/http_client_filter.cc | 1 + .../filters/http/client/http_client_filter.h | 1 + .../filters/http/server/http_server_filter.cc | 1 + .../filters/http/server/http_server_filter.h | 1 + .../message_size/message_size_filter.cc | 2 + .../message_size/message_size_filter.h | 2 + src/core/lib/channel/promise_based_filter.h | 31 +++++++- .../lib/channel/server_call_tracer_filter.cc | 74 ++++++++++--------- 8 files changed, 79 insertions(+), 34 deletions(-) diff --git a/src/core/ext/filters/http/client/http_client_filter.cc b/src/core/ext/filters/http/client/http_client_filter.cc index 07fcba6258171..ac8004cdd3e41 100644 --- a/src/core/ext/filters/http/client/http_client_filter.cc +++ b/src/core/ext/filters/http/client/http_client_filter.cc @@ -53,6 +53,7 @@ namespace grpc_core { const NoInterceptor HttpClientFilter::Call::OnServerToClientMessage; const NoInterceptor HttpClientFilter::Call::OnClientToServerMessage; +const NoInterceptor HttpClientFilter::Call::OnFinalize; const grpc_channel_filter HttpClientFilter::kFilter = MakePromiseBasedFilter { absl::Status OnServerTrailingMetadata(ServerMetadata& md); static const NoInterceptor OnClientToServerMessage; static const NoInterceptor OnServerToClientMessage; + static const NoInterceptor OnFinalize; }; private: diff --git a/src/core/ext/filters/http/server/http_server_filter.cc b/src/core/ext/filters/http/server/http_server_filter.cc index 830b931520f74..38c2dda0e167e 100644 --- a/src/core/ext/filters/http/server/http_server_filter.cc +++ b/src/core/ext/filters/http/server/http_server_filter.cc @@ -51,6 +51,7 @@ namespace grpc_core { const NoInterceptor HttpServerFilter::Call::OnClientToServerMessage; const NoInterceptor HttpServerFilter::Call::OnServerToClientMessage; +const NoInterceptor HttpServerFilter::Call::OnFinalize; const grpc_channel_filter HttpServerFilter::kFilter = MakePromiseBasedFilter { void OnServerTrailingMetadata(ServerMetadata& md); static const NoInterceptor OnClientToServerMessage; static const NoInterceptor OnServerToClientMessage; + static const NoInterceptor OnFinalize; }; private: diff --git a/src/core/ext/filters/message_size/message_size_filter.cc b/src/core/ext/filters/message_size/message_size_filter.cc index fcd5677ff51dc..9cfc00474c49c 100644 --- a/src/core/ext/filters/message_size/message_size_filter.cc +++ b/src/core/ext/filters/message_size/message_size_filter.cc @@ -53,9 +53,11 @@ namespace grpc_core { const NoInterceptor ClientMessageSizeFilter::Call::OnClientInitialMetadata; const NoInterceptor ClientMessageSizeFilter::Call::OnServerInitialMetadata; const NoInterceptor ClientMessageSizeFilter::Call::OnServerTrailingMetadata; +const NoInterceptor ClientMessageSizeFilter::Call::OnFinalize; const NoInterceptor ServerMessageSizeFilter::Call::OnClientInitialMetadata; const NoInterceptor ServerMessageSizeFilter::Call::OnServerInitialMetadata; const NoInterceptor ServerMessageSizeFilter::Call::OnServerTrailingMetadata; +const NoInterceptor ServerMessageSizeFilter::Call::OnFinalize; // // MessageSizeParsedConfig diff --git a/src/core/ext/filters/message_size/message_size_filter.h b/src/core/ext/filters/message_size/message_size_filter.h index fdfba2fa788b2..647aeeed94f5c 100644 --- a/src/core/ext/filters/message_size/message_size_filter.h +++ b/src/core/ext/filters/message_size/message_size_filter.h @@ -99,6 +99,7 @@ class ServerMessageSizeFilter final static const NoInterceptor OnClientInitialMetadata; static const NoInterceptor OnServerInitialMetadata; static const NoInterceptor OnServerTrailingMetadata; + static const NoInterceptor OnFinalize; ServerMetadataHandle OnClientToServerMessage( const Message& message, ServerMessageSizeFilter* filter); ServerMetadataHandle OnServerToClientMessage( @@ -126,6 +127,7 @@ class ClientMessageSizeFilter final static const NoInterceptor OnClientInitialMetadata; static const NoInterceptor OnServerInitialMetadata; static const NoInterceptor OnServerTrailingMetadata; + static const NoInterceptor OnFinalize; ServerMetadataHandle OnClientToServerMessage(const Message& message); ServerMetadataHandle OnServerToClientMessage(const Message& message); diff --git a/src/core/lib/channel/promise_based_filter.h b/src/core/lib/channel/promise_based_filter.h index abb9ce0fbe093..ad33f366378cd 100644 --- a/src/core/lib/channel/promise_based_filter.h +++ b/src/core/lib/channel/promise_based_filter.h @@ -186,6 +186,11 @@ inline constexpr bool HasChannelAccess(R (T::*)(A)) { return false; } +template +inline constexpr bool HasChannelAccess(R (T::*)()) { + return false; +} + template inline constexpr bool HasChannelAccess(R (T::*)(A, C)) { return true; @@ -208,7 +213,8 @@ inline constexpr bool CallHasChannelAccess() { &Derived::Call::OnClientToServerMessage, &Derived::Call::OnServerInitialMetadata, &Derived::Call::OnServerToClientMessage, - &Derived::Call::OnServerTrailingMetadata); + &Derived::Call::OnServerTrailingMetadata, + &Derived::Call::OnFinalize); } // Given a boolean X export a type: @@ -642,6 +648,18 @@ inline void InterceptServerTrailingMetadata( }); } +inline void InterceptFinalize(const NoInterceptor*, void*) {} + +template +inline void InterceptFinalize(void (Call::*fn)(const grpc_call_final_info*), + Call* call) { + GPR_DEBUG_ASSERT(fn == &Call::OnFinalize); + GetContext()->Add( + [call](const grpc_call_final_info* final_info) { + call->OnFinalize(final_info); + }); +} + template absl::enable_if_t>::value, FilterCallData*> @@ -674,6 +692,7 @@ MakeFilterCall(Derived* derived) { // - OnServerToClientMessage - $VALUE_TYPE = Message // - OnClientToServerMessage - $VALUE_TYPE = Message // - OnServerTrailingMetadata - $VALUE_TYPE = ServerMetadata +// - OnFinalize - special, see below // These members define an interception point for a particular event in // the call lifecycle. // The type of these members matters, and is selectable by the class @@ -706,6 +725,12 @@ MakeFilterCall(Derived* derived) { // the filter can return nullptr for success, or a metadata handle for // failure (in which case the call will be aborted). // useful for cases where the exact metadata returned needs to be customized. +// Finally, OnFinalize can be added to intecept call finalization. +// It must have one of the signatures: +// - static const NoInterceptor OnFinalize: +// the filter does not intercept call finalization. +// - void OnFinalize(const grpc_call_final_info*): +// the filter intercepts call finalization. template class ImplementChannelFilter : public ChannelFilter { public: @@ -730,6 +755,7 @@ class ImplementChannelFilter : public ChannelFilter { promise_filter_detail::InterceptServerTrailingMetadata( &Derived::Call::OnServerTrailingMetadata, call, static_cast(this), call_spine); + promise_filter_detail::InterceptFinalize(&Derived::Call::OnFinalize, call); } // Polyfill for the original promise scheme. @@ -745,6 +771,9 @@ class ImplementChannelFilter : public ChannelFilter { &Derived::Call::OnServerInitialMetadata, call, call_args); promise_filter_detail::InterceptServerToClientMessage( &Derived::Call::OnServerToClientMessage, call, call_args); + promise_filter_detail::InterceptFinalize( + &Derived::Call::OnFinalize, + static_cast(&call->call)); return promise_filter_detail::MapResult( &Derived::Call::OnServerTrailingMetadata, promise_filter_detail::RaceAsyncCompletion< diff --git a/src/core/lib/channel/server_call_tracer_filter.cc b/src/core/lib/channel/server_call_tracer_filter.cc index 026216fd59e2c..c2450a97d4c94 100644 --- a/src/core/lib/channel/server_call_tracer_filter.cc +++ b/src/core/lib/channel/server_call_tracer_filter.cc @@ -42,19 +42,55 @@ namespace grpc_core { namespace { -// TODO(yashykt): This filter is not really needed. We should be able to move -// this to the connected filter. -class ServerCallTracerFilter : public ChannelFilter { +class ServerCallTracerFilter + : public ImplementChannelFilter { public: static const grpc_channel_filter kFilter; static absl::StatusOr Create( const ChannelArgs& /*args*/, ChannelFilter::Args /*filter_args*/); - ArenaPromise MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) override; + class Call { + public: + void OnClientInitialMetadata(ClientMetadata& client_initial_metadata) { + auto* call_tracer = CallTracer(); + if (call_tracer == nullptr) return; + call_tracer->RecordReceivedInitialMetadata(&client_initial_metadata); + } + + void OnServerInitialMetadata(ServerMetadata& server_initial_metadata) { + auto* call_tracer = CallTracer(); + if (call_tracer == nullptr) return; + call_tracer->RecordSendInitialMetadata(&server_initial_metadata); + } + + void OnFinalize(const grpc_call_final_info* final_info) { + auto* call_tracer = CallTracer(); + if (call_tracer == nullptr) return; + call_tracer->RecordEnd(final_info); + } + + void OnServerTrailingMetadata(ServerMetadata& server_trailing_metadata) { + auto* call_tracer = CallTracer(); + if (call_tracer == nullptr) return; + call_tracer->RecordSendTrailingMetadata(&server_trailing_metadata); + } + + static const NoInterceptor OnClientToServerMessage; + static const NoInterceptor OnServerToClientMessage; + + private: + static ServerCallTracer* CallTracer() { + auto* call_context = GetContext(); + return static_cast( + call_context[GRPC_CONTEXT_CALL_TRACER].value); + } + }; }; +const NoInterceptor ServerCallTracerFilter::Call::OnClientToServerMessage; +const NoInterceptor ServerCallTracerFilter::Call::OnServerToClientMessage; + const grpc_channel_filter ServerCallTracerFilter::kFilter = MakePromiseBasedFilter( @@ -65,34 +101,6 @@ absl::StatusOr ServerCallTracerFilter::Create( return ServerCallTracerFilter(); } -ArenaPromise ServerCallTracerFilter::MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) { - auto* call_context = GetContext(); - auto* call_tracer = static_cast( - call_context[GRPC_CONTEXT_CALL_TRACER].value); - if (call_tracer == nullptr) { - return next_promise_factory(std::move(call_args)); - } - call_tracer->RecordReceivedInitialMetadata( - call_args.client_initial_metadata.get()); - call_args.server_initial_metadata->InterceptAndMap( - [call_tracer](ServerMetadataHandle metadata) { - call_tracer->RecordSendInitialMetadata(metadata.get()); - return metadata; - }); - GetContext()->Add( - [call_tracer](const grpc_call_final_info* final_info) { - call_tracer->RecordEnd(final_info); - }); - return OnCancel( - Map(next_promise_factory(std::move(call_args)), - [call_tracer](ServerMetadataHandle md) { - call_tracer->RecordSendTrailingMetadata(md.get()); - return md; - }), - [call_tracer]() { call_tracer->RecordCancel(absl::CancelledError()); }); -} - } // namespace void RegisterServerCallTracerFilter(CoreConfiguration::Builder* builder) { From 8cfce72868aedafe8cc98c66913dd60628aa448a Mon Sep 17 00:00:00 2001 From: Alisha Nanda Date: Thu, 7 Dec 2023 15:27:52 -0800 Subject: [PATCH 058/127] [server] Remove per-channel registered methods map (#35231) https://github.com/grpc/grpc/pull/34286 was split into two parts - the first part was submitted in https://github.com/grpc/grpc/pull/34612, to move to absl::flat_hash_map for per-channel registered methods map, and this is the second part to remove the per-channel map and switch to using per-server. Closes #35231 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35231 from ananda1066:remove_rm2 6b154545bf5acbcfbe711d23a30a4eaa25a272b6 PiperOrigin-RevId: 588928459 --- src/core/lib/surface/server.cc | 167 +++++++-------------------------- src/core/lib/surface/server.h | 68 ++++---------- 2 files changed, 54 insertions(+), 181 deletions(-) diff --git a/src/core/lib/surface/server.cc b/src/core/lib/surface/server.cc index 037e2b59e0b06..b2d1be8fea52b 100644 --- a/src/core/lib/surface/server.cc +++ b/src/core/lib/surface/server.cc @@ -839,9 +839,9 @@ void Server::Start() { if (unregistered_request_matcher_ == nullptr) { unregistered_request_matcher_ = make_real_request_matcher(); } - for (std::unique_ptr& rm : registered_methods_) { - if (rm->matcher == nullptr) { - rm->matcher = make_real_request_matcher(); + for (auto& rm : registered_methods_) { + if (rm.second->matcher == nullptr) { + rm.second->matcher = make_real_request_matcher(); } } { @@ -928,20 +928,11 @@ void Server::RegisterCompletionQueue(grpc_completion_queue* cq) { cqs_.push_back(cq); } -namespace { - -bool streq(const std::string& a, const char* b) { - return (a.empty() && b == nullptr) || - ((b != nullptr) && !strcmp(a.c_str(), b)); -} - -} // namespace - Server::RegisteredMethod* Server::RegisterMethod( const char* method, const char* host, grpc_server_register_method_payload_handling payload_handling, uint32_t flags) { - if (IsRegisteredMethodsMapEnabled() && started_) { + if (started_) { Crash("Attempting to register method after server started"); } @@ -950,21 +941,21 @@ Server::RegisteredMethod* Server::RegisterMethod( "grpc_server_register_method method string cannot be NULL"); return nullptr; } - for (std::unique_ptr& m : registered_methods_) { - if (streq(m->method, method) && streq(m->host, host)) { - gpr_log(GPR_ERROR, "duplicate registration for %s@%s", method, - host ? host : "*"); - return nullptr; - } + auto key = std::make_pair(host ? host : "", method); + if (registered_methods_.find(key) != registered_methods_.end()) { + gpr_log(GPR_ERROR, "duplicate registration for %s@%s", method, + host ? host : "*"); + return nullptr; } if (flags != 0) { gpr_log(GPR_ERROR, "grpc_server_register_method invalid flags 0x%08x", flags); return nullptr; } - registered_methods_.emplace_back(std::make_unique( - method, host, payload_handling, flags)); - return registered_methods_.back().get(); + auto it = registered_methods_.emplace( + key, std::make_unique(method, host, payload_handling, + flags)); + return it.first->second.get(); } void Server::DoneRequestEvent(void* req, grpc_cq_completion* /*c*/) { @@ -1015,9 +1006,9 @@ void Server::KillPendingWorkLocked(grpc_error_handle error) { if (started_) { unregistered_request_matcher_->KillRequests(error); unregistered_request_matcher_->ZombifyPending(); - for (std::unique_ptr& rm : registered_methods_) { - rm->matcher->KillRequests(error); - rm->matcher->ZombifyPending(); + for (auto& rm : registered_methods_) { + rm.second->matcher->KillRequests(error); + rm.second->matcher->ZombifyPending(); } } } @@ -1252,7 +1243,6 @@ class Server::ChannelData::ConnectivityWatcher // Server::ChannelData::~ChannelData() { - old_registered_methods_.reset(); if (server_ != nullptr) { if (server_->channelz_node_ != nullptr && channelz_socket_uuid_ != 0) { server_->channelz_node_->RemoveChildSocket(channelz_socket_uuid_); @@ -1276,50 +1266,6 @@ void Server::ChannelData::InitTransport(RefCountedPtr server, channel_ = channel; cq_idx_ = cq_idx; channelz_socket_uuid_ = channelz_socket_uuid; - // Build a lookup table phrased in terms of mdstr's in this channels context - // to quickly find registered methods. - size_t num_registered_methods = server_->registered_methods_.size(); - if (!IsRegisteredMethodsMapEnabled() && num_registered_methods > 0) { - uint32_t max_probes = 0; - size_t slots = 2 * num_registered_methods; - old_registered_methods_ = - std::make_unique>(slots); - for (std::unique_ptr& rm : server_->registered_methods_) { - Slice host; - Slice method = Slice::FromExternalString(rm->method); - const bool has_host = !rm->host.empty(); - if (has_host) { - host = Slice::FromExternalString(rm->host); - } - uint32_t hash = MixHash32(has_host ? host.Hash() : 0, method.Hash()); - uint32_t probes = 0; - for (probes = 0; (*old_registered_methods_)[(hash + probes) % slots] - .server_registered_method != nullptr; - probes++) { - } - if (probes > max_probes) max_probes = probes; - ChannelRegisteredMethod* crm = - &(*old_registered_methods_)[(hash + probes) % slots]; - crm->server_registered_method = rm.get(); - crm->flags = rm->flags; - crm->has_host = has_host; - if (has_host) { - crm->host = std::move(host); - } - crm->method = std::move(method); - } - GPR_ASSERT(slots <= UINT32_MAX); - registered_method_max_probes_ = max_probes; - } else if (IsRegisteredMethodsMapEnabled()) { - for (std::unique_ptr& rm : server_->registered_methods_) { - auto key = std::make_pair(!rm->host.empty() ? rm->host : "", rm->method); - registered_methods_.emplace( - key, std::make_unique( - rm.get(), rm->flags, /*has_host=*/!rm->host.empty(), - Slice::FromExternalString(rm->method), - Slice::FromExternalString(rm->host))); - } - } // Publish channel. { MutexLock lock(&server_->mu_global_); @@ -1345,45 +1291,17 @@ void Server::ChannelData::InitTransport(RefCountedPtr server, transport->PerformOp(op); } -Server::ChannelRegisteredMethod* Server::ChannelData::GetRegisteredMethod( - const grpc_slice& host, const grpc_slice& path) { - if (old_registered_methods_ == nullptr) return nullptr; - // TODO(ctiller): unify these two searches - // check for an exact match with host - uint32_t hash = MixHash32(grpc_slice_hash(host), grpc_slice_hash(path)); - for (size_t i = 0; i <= registered_method_max_probes_; i++) { - ChannelRegisteredMethod* rm = &( - *old_registered_methods_)[(hash + i) % old_registered_methods_->size()]; - if (rm->server_registered_method == nullptr) break; - if (!rm->has_host) continue; - if (rm->host != host) continue; - if (rm->method != path) continue; - return rm; - } - // check for a wildcard method definition (no host set) - hash = MixHash32(0, grpc_slice_hash(path)); - for (size_t i = 0; i <= registered_method_max_probes_; i++) { - ChannelRegisteredMethod* rm = &( - *old_registered_methods_)[(hash + i) % old_registered_methods_->size()]; - if (rm->server_registered_method == nullptr) break; - if (rm->has_host) continue; - if (rm->method != path) continue; - return rm; - } - return nullptr; -} - -Server::ChannelRegisteredMethod* Server::ChannelData::GetRegisteredMethod( +Server::RegisteredMethod* Server::ChannelData::GetRegisteredMethod( const absl::string_view& host, const absl::string_view& path) { - if (registered_methods_.empty()) return nullptr; + if (server_->registered_methods_.empty()) return nullptr; // check for an exact match with host - auto it = registered_methods_.find(std::make_pair(host, path)); - if (it != registered_methods_.end()) { + auto it = server_->registered_methods_.find(std::make_pair(host, path)); + if (it != server_->registered_methods_.end()) { return it->second.get(); } // check for wildcard method definition (no host set) - it = registered_methods_.find(std::make_pair("", path)); - if (it != registered_methods_.end()) { + it = server_->registered_methods_.find(std::make_pair("", path)); + if (it != server_->registered_methods_.end()) { return it->second.get(); } return nullptr; @@ -1404,13 +1322,8 @@ void Server::ChannelData::SetRegisteredMethodOnMetadata( // Path not being set would result in an RPC error. return; } - ChannelRegisteredMethod* method; - if (!IsRegisteredMethodsMapEnabled()) { - method = GetRegisteredMethod(authority->c_slice(), path->c_slice()); - } else { - method = GetRegisteredMethod(authority->as_string_view(), - path->as_string_view()); - } + RegisteredMethod* method = + GetRegisteredMethod(authority->as_string_view(), path->as_string_view()); // insert in metadata metadata.Set(GrpcRegisteredMethod(), method); } @@ -1481,24 +1394,20 @@ ArenaPromise Server::ChannelData::MakeCallPromise( Timestamp deadline = GetContext()->deadline(); // Find request matcher. RequestMatcherInterface* matcher; - ChannelRegisteredMethod* rm = nullptr; + RegisteredMethod* rm = nullptr; if (IsRegisteredMethodLookupInTransportEnabled()) { - rm = static_cast( + rm = static_cast( call_args.client_initial_metadata->get(GrpcRegisteredMethod()) .value_or(nullptr)); } else { - if (!IsRegisteredMethodsMapEnabled()) { - rm = chand->GetRegisteredMethod(host_ptr->c_slice(), path->c_slice()); - } else { - rm = chand->GetRegisteredMethod(host_ptr->as_string_view(), - path->as_string_view()); - } + rm = chand->GetRegisteredMethod(host_ptr->as_string_view(), + path->as_string_view()); } ArenaPromise>> maybe_read_first_message([] { return NextResult(); }); if (rm != nullptr) { - matcher = rm->server_registered_method->matcher.get(); - switch (rm->server_registered_method->payload_handling) { + matcher = rm->matcher.get(); + switch (rm->payload_handling) { case GRPC_SRM_PAYLOAD_NONE: break; case GRPC_SRM_PAYLOAD_READ_INITIAL_BYTE_BUFFER: @@ -1752,22 +1661,18 @@ void Server::CallData::StartNewRpc(grpc_call_element* elem) { grpc_server_register_method_payload_handling payload_handling = GRPC_SRM_PAYLOAD_NONE; if (path_.has_value() && host_.has_value()) { - ChannelRegisteredMethod* rm; + RegisteredMethod* rm; if (IsRegisteredMethodLookupInTransportEnabled()) { - rm = static_cast( + rm = static_cast( recv_initial_metadata_->get(GrpcRegisteredMethod()) .value_or(nullptr)); } else { - if (!IsRegisteredMethodsMapEnabled()) { - rm = chand->GetRegisteredMethod(host_->c_slice(), path_->c_slice()); - } else { - rm = chand->GetRegisteredMethod(host_->as_string_view(), - path_->as_string_view()); - } + rm = chand->GetRegisteredMethod(host_->as_string_view(), + path_->as_string_view()); } if (rm != nullptr) { - matcher_ = rm->server_registered_method->matcher.get(); - payload_handling = rm->server_registered_method->payload_handling; + matcher_ = rm->matcher.get(); + payload_handling = rm->payload_handling; } } // Start recv_message op if needed. diff --git a/src/core/lib/surface/server.h b/src/core/lib/surface/server.h index 4e181c8bb379c..226fb9fc1329a 100644 --- a/src/core/lib/surface/server.h +++ b/src/core/lib/surface/server.h @@ -211,26 +211,6 @@ class Server : public InternallyRefCounted, private: struct RequestedCall; - struct ChannelRegisteredMethod { - ChannelRegisteredMethod() = default; - ChannelRegisteredMethod(RegisteredMethod* server_registered_method_arg, - uint32_t flags_arg, bool has_host_arg, - Slice method_arg, Slice host_arg) - : server_registered_method(server_registered_method_arg), - flags(flags_arg), - has_host(has_host_arg), - method(std::move(method_arg)), - host(std::move(host_arg)) {} - - ~ChannelRegisteredMethod() = default; - - RegisteredMethod* server_registered_method = nullptr; - uint32_t flags; - bool has_host; - Slice method; - Slice host; - }; - class RequestMatcherInterface; class RealRequestMatcherFilterStack; class RealRequestMatcherPromises; @@ -251,11 +231,8 @@ class Server : public InternallyRefCounted, Channel* channel() const { return channel_.get(); } size_t cq_idx() const { return cq_idx_; } - ChannelRegisteredMethod* GetRegisteredMethod(const grpc_slice& host, - const grpc_slice& path); - - ChannelRegisteredMethod* GetRegisteredMethod(const absl::string_view& host, - const absl::string_view& path); + RegisteredMethod* GetRegisteredMethod(const absl::string_view& host, + const absl::string_view& path); // Filter vtable functions. static grpc_error_handle InitChannelElement( grpc_channel_element* elem, grpc_channel_element_args* args); @@ -274,36 +251,12 @@ class Server : public InternallyRefCounted, static void FinishDestroy(void* arg, grpc_error_handle error); - struct StringViewStringViewPairHash - : absl::flat_hash_set< - std::pair>::hasher { - using is_transparent = void; - }; - - struct StringViewStringViewPairEq - : std::equal_to> { - using is_transparent = void; - }; - RefCountedPtr server_; RefCountedPtr channel_; // The index into Server::cqs_ of the CQ used as a starting point for // where to publish new incoming calls. size_t cq_idx_; absl::optional::iterator> list_position_; - // A hash-table of the methods and hosts of the registered methods. - // TODO(vjpai): Convert this to an STL map type as opposed to a direct - // bucket implementation. (Consider performance impact, hash function to - // use, etc.) - std::unique_ptr> - old_registered_methods_; - // Map of registered methods. - absl::flat_hash_map /*host, method*/, - std::unique_ptr, - StringViewStringViewPairHash, - StringViewStringViewPairEq> - registered_methods_; - uint32_t registered_method_max_probes_; grpc_closure finish_destroy_channel_closure_; intptr_t channelz_socket_uuid_; }; @@ -412,6 +365,17 @@ class Server : public InternallyRefCounted, grpc_cq_completion completion; }; + struct StringViewStringViewPairHash + : absl::flat_hash_set< + std::pair>::hasher { + using is_transparent = void; + }; + + struct StringViewStringViewPairEq + : std::equal_to> { + using is_transparent = void; + }; + static void ListenerDestroyDone(void* arg, grpc_error_handle error); static void DoneShutdownEvent(void* server, @@ -497,7 +461,11 @@ class Server : public InternallyRefCounted, bool starting_ ABSL_GUARDED_BY(mu_global_) = false; CondVar starting_cv_; - std::vector> registered_methods_; + // Map of registered methods. + absl::flat_hash_map /*host, method*/, + std::unique_ptr, + StringViewStringViewPairHash, StringViewStringViewPairEq> + registered_methods_; // Request matcher for unregistered methods. std::unique_ptr unregistered_request_matcher_; From 70acb340cef9023cae2f864cee48d48d22b6584b Mon Sep 17 00:00:00 2001 From: Hannah Shi Date: Thu, 7 Dec 2023 16:01:06 -0800 Subject: [PATCH 059/127] [ObjC] add privacy manifests to grpc podspec (#35042) Not sure if we need to do the same for all the podspec files. Will create a separate PR for swift package. Closes #35042 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35042 from HannahShiSFB:privacy-manifests c9b19d3c202d6592e1535948d6fde2ee0bcaa562 PiperOrigin-RevId: 588937122 --- gRPC.podspec | 2 ++ src/objective-c/PrivacyInfo.xcprivacy | 23 +++++++++++++++++++++++ templates/gRPC.podspec.template | 2 ++ 3 files changed, 27 insertions(+) create mode 100644 src/objective-c/PrivacyInfo.xcprivacy diff --git a/gRPC.podspec b/gRPC.podspec index 2be61d982707f..120a23ffcbc9f 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -32,6 +32,8 @@ Pod::Spec.new do |s| :tag => "v#{version}", } + s.resource = 'src/objective-c/PrivacyInfo.xcprivacy' + name = 'GRPCClient' s.module_name = name s.header_dir = name diff --git a/src/objective-c/PrivacyInfo.xcprivacy b/src/objective-c/PrivacyInfo.xcprivacy new file mode 100644 index 0000000000000..276f7610da6df --- /dev/null +++ b/src/objective-c/PrivacyInfo.xcprivacy @@ -0,0 +1,23 @@ + + + + + NSPrivacyTracking + + NSPrivacyCollectedDataTypes + + NSPrivacyTrackingDomains + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + C617.1 + + + + + diff --git a/templates/gRPC.podspec.template b/templates/gRPC.podspec.template index 735a0ab449c68..6bba4e1aa6c6c 100644 --- a/templates/gRPC.podspec.template +++ b/templates/gRPC.podspec.template @@ -34,6 +34,8 @@ :tag => "v#{version}", } + s.resource = 'src/objective-c/PrivacyInfo.xcprivacy' + name = 'GRPCClient' s.module_name = name s.header_dir = name From 522434e4f9f0f35e222c6d692269c1295353926a Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Thu, 7 Dec 2023 16:24:11 -0800 Subject: [PATCH 060/127] docs: service_config.md: fix pb syntax, add highlighting (#35232) 1. Protobuf doesn't support `//` comments, only `#` 2. Add syntax highlighting Closes #35232 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35232 from grpc:sergiitk-service_config e17a9ef14d201c63df047ae7543b0d47942fc527 PiperOrigin-RevId: 588943566 --- doc/service_config.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/service_config.md b/doc/service_config.md index 57f5e1989e820..6312cda7f6285 100644 --- a/doc/service_config.md +++ b/doc/service_config.md @@ -62,12 +62,12 @@ DNS](https://github.com/grpc/proposal/blob/master/A2-service-configs-in-dns.md). Here is an example service config in protobuf form: -``` +```textproto { - // Use round_robin LB policy. + # Use round_robin LB policy. load_balancing_config: { round_robin: {} } - // This method config applies to method "foo/bar" and to all methods - // of service "baz". + # This method config applies to method "foo/bar" and to all methods + # of service "baz". method_config: { name: { service: "foo" @@ -76,7 +76,7 @@ Here is an example service config in protobuf form: name: { service: "baz" } - // Default timeout for matching methods. + # Default timeout for matching methods. timeout: { seconds: 1 nanos: 1 @@ -87,7 +87,7 @@ Here is an example service config in protobuf form: Here is the same example service config in JSON form: -``` +```json { "loadBalancingConfig": [ { "round_robin": {} } ], "methodConfig": [ From 25c298224a9be164c2f0fba3f8925fd733419478 Mon Sep 17 00:00:00 2001 From: Richard Belleville Date: Thu, 7 Dec 2023 17:59:05 -0800 Subject: [PATCH 061/127] Pin googleapis-common-protos (#35255) Closes #35255 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35255 from gnossen:freeze_googleapis_bazel 38fb05d8dbe05f6bf3d8e441e618d6554b7c9843 PiperOrigin-RevId: 588965912 --- requirements.bazel.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.bazel.txt b/requirements.bazel.txt index 851dbd15a38da..532562389fd8e 100644 --- a/requirements.bazel.txt +++ b/requirements.bazel.txt @@ -16,3 +16,4 @@ xds-protos==0.0.11 opencensus==0.10.0 opencensus-ext-stackdriver==0.8.0 absl-py==1.4.0 +googleapis-common-protos==1.61.0 From 257efc0375632a539c4406fceca0f1867058a875 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 7 Dec 2023 19:23:28 -0800 Subject: [PATCH 062/127] [call-v3] Add a hook to deadline filter (#35252) Still need to figure a better long term strategy here, but this 'works for now' Closes #35252 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35252 from ctiller:cg-deadline a413955afc3b3df8a54eb1a98c068c7e0428f11a PiperOrigin-RevId: 588980941 --- src/core/ext/filters/deadline/deadline_filter.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/core/ext/filters/deadline/deadline_filter.cc b/src/core/ext/filters/deadline/deadline_filter.cc index 50ce988173edb..588827b95842e 100644 --- a/src/core/ext/filters/deadline/deadline_filter.cc +++ b/src/core/ext/filters/deadline/deadline_filter.cc @@ -369,7 +369,17 @@ const grpc_channel_filter grpc_server_deadline_filter = { } return next_promise_factory(std::move(call_args)); }, - /* init_call: */ nullptr, + [](grpc_channel_element*, grpc_core::CallSpineInterface* spine) { + spine->client_initial_metadata().receiver.InterceptAndMap( + [](grpc_core::ClientMetadataHandle md) { + auto deadline = md->get(grpc_core::GrpcTimeoutMetadata()); + if (deadline.has_value()) { + grpc_core::GetContext()->UpdateDeadline( + *deadline); + } + return md; + }); + }, grpc_channel_next_op, sizeof(server_call_data), deadline_init_call_elem, From f0d7df79daadee38a1e385773f98d29a3530416e Mon Sep 17 00:00:00 2001 From: Vignesh Babu Date: Fri, 8 Dec 2023 09:30:23 -0800 Subject: [PATCH 063/127] [EventEngine] Add virtual a MakeSlice method into MemoryAllocatorImpl and move its default implementation to GrpcMemoryAllocatorImpl PiperOrigin-RevId: 589155443 --- CMakeLists.txt | 9 --- Makefile | 2 - Package.swift | 1 - build_autogenerated.yaml | 9 --- config.m4 | 1 - config.w32 | 1 - gRPC-Core.podspec | 1 - grpc.gemspec | 1 - grpc.gyp | 3 - .../internal/memory_allocator_impl.h | 6 ++ include/grpc/event_engine/memory_allocator.h | 4 +- include/grpc/impl/channel_arg_names.h | 5 ++ package.xml | 1 - src/core/BUILD | 5 +- src/core/lib/event_engine/memory_allocator.cc | 74 ------------------- .../posix_engine/tcp_socket_utils.cc | 8 ++ .../posix_engine/tcp_socket_utils.h | 7 ++ src/core/lib/resource_quota/memory_quota.cc | 54 ++++++++++++++ src/core/lib/resource_quota/memory_quota.h | 6 ++ src/python/grpcio/grpc_core_dependencies.py | 1 - tools/doxygen/Doxyfile.c++.internal | 1 - tools/doxygen/Doxyfile.core.internal | 1 - 22 files changed, 90 insertions(+), 111 deletions(-) delete mode 100644 src/core/lib/event_engine/memory_allocator.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 9782163ed81af..b9390ecccf282 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2242,7 +2242,6 @@ add_library(grpc src/core/lib/event_engine/default_event_engine_factory.cc src/core/lib/event_engine/event_engine.cc src/core/lib/event_engine/forkable.cc - src/core/lib/event_engine/memory_allocator.cc src/core/lib/event_engine/posix_engine/ev_epoll1_linux.cc src/core/lib/event_engine/posix_engine/ev_poll_posix.cc src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc @@ -2971,7 +2970,6 @@ add_library(grpc_unsecure src/core/lib/event_engine/default_event_engine_factory.cc src/core/lib/event_engine/event_engine.cc src/core/lib/event_engine/forkable.cc - src/core/lib/event_engine/memory_allocator.cc src/core/lib/event_engine/posix_engine/ev_epoll1_linux.cc src/core/lib/event_engine/posix_engine/ev_poll_posix.cc src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc @@ -4960,7 +4958,6 @@ add_library(grpc_authorization_provider src/core/lib/event_engine/default_event_engine_factory.cc src/core/lib/event_engine/event_engine.cc src/core/lib/event_engine/forkable.cc - src/core/lib/event_engine/memory_allocator.cc src/core/lib/event_engine/posix_engine/ev_epoll1_linux.cc src/core/lib/event_engine/posix_engine/ev_poll_posix.cc src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc @@ -8863,7 +8860,6 @@ add_executable(chunked_vector_test src/core/ext/upb-gen/google/protobuf/descriptor.upb_minitable.c src/core/ext/upb-gen/google/rpc/status.upb_minitable.c src/core/lib/debug/trace.cc - src/core/lib/event_engine/memory_allocator.cc src/core/lib/experiments/config.cc src/core/lib/experiments/experiments.cc src/core/lib/gprpp/status_helper.cc @@ -12160,7 +12156,6 @@ add_executable(flow_control_test src/core/ext/upb-gen/google/protobuf/descriptor.upb_minitable.c src/core/ext/upb-gen/google/rpc/status.upb_minitable.c src/core/lib/debug/trace.cc - src/core/lib/event_engine/memory_allocator.cc src/core/lib/experiments/config.cc src/core/lib/experiments/experiments.cc src/core/lib/gprpp/status_helper.cc @@ -12246,7 +12241,6 @@ add_executable(for_each_test src/core/ext/upb-gen/google/protobuf/descriptor.upb_minitable.c src/core/ext/upb-gen/google/rpc/status.upb_minitable.c src/core/lib/debug/trace.cc - src/core/lib/event_engine/memory_allocator.cc src/core/lib/experiments/config.cc src/core/lib/experiments/experiments.cc src/core/lib/gprpp/status_helper.cc @@ -15024,7 +15018,6 @@ add_executable(interceptor_list_test src/core/ext/upb-gen/google/protobuf/descriptor.upb_minitable.c src/core/ext/upb-gen/google/rpc/status.upb_minitable.c src/core/lib/debug/trace.cc - src/core/lib/event_engine/memory_allocator.cc src/core/lib/experiments/config.cc src/core/lib/experiments/experiments.cc src/core/lib/gprpp/status_helper.cc @@ -15948,7 +15941,6 @@ add_executable(map_pipe_test src/core/ext/upb-gen/google/protobuf/descriptor.upb_minitable.c src/core/ext/upb-gen/google/rpc/status.upb_minitable.c src/core/lib/debug/trace.cc - src/core/lib/event_engine/memory_allocator.cc src/core/lib/experiments/config.cc src/core/lib/experiments/experiments.cc src/core/lib/gprpp/status_helper.cc @@ -24645,7 +24637,6 @@ add_executable(test_core_transport_chaotic_good_frame_test src/core/lib/event_engine/default_event_engine_factory.cc src/core/lib/event_engine/event_engine.cc src/core/lib/event_engine/forkable.cc - src/core/lib/event_engine/memory_allocator.cc src/core/lib/event_engine/posix_engine/ev_epoll1_linux.cc src/core/lib/event_engine/posix_engine/ev_poll_posix.cc src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc diff --git a/Makefile b/Makefile index 224e74adc5e3b..6df49a7bac0ff 100644 --- a/Makefile +++ b/Makefile @@ -1444,7 +1444,6 @@ LIBGRPC_SRC = \ src/core/lib/event_engine/default_event_engine_factory.cc \ src/core/lib/event_engine/event_engine.cc \ src/core/lib/event_engine/forkable.cc \ - src/core/lib/event_engine/memory_allocator.cc \ src/core/lib/event_engine/posix_engine/ev_epoll1_linux.cc \ src/core/lib/event_engine/posix_engine/ev_poll_posix.cc \ src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc \ @@ -2023,7 +2022,6 @@ LIBGRPC_UNSECURE_SRC = \ src/core/lib/event_engine/default_event_engine_factory.cc \ src/core/lib/event_engine/event_engine.cc \ src/core/lib/event_engine/forkable.cc \ - src/core/lib/event_engine/memory_allocator.cc \ src/core/lib/event_engine/posix_engine/ev_epoll1_linux.cc \ src/core/lib/event_engine/posix_engine/ev_poll_posix.cc \ src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc \ diff --git a/Package.swift b/Package.swift index 9e501b405fd12..7c9d9ce10e9e2 100644 --- a/Package.swift +++ b/Package.swift @@ -1260,7 +1260,6 @@ let package = Package( "src/core/lib/event_engine/forkable.h", "src/core/lib/event_engine/grpc_polled_fd.h", "src/core/lib/event_engine/handle_containers.h", - "src/core/lib/event_engine/memory_allocator.cc", "src/core/lib/event_engine/memory_allocator_factory.h", "src/core/lib/event_engine/nameser.h", "src/core/lib/event_engine/poller.h", diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index 392481ce4ccfe..f5ea18449e226 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -1695,7 +1695,6 @@ libs: - src/core/lib/event_engine/default_event_engine_factory.cc - src/core/lib/event_engine/event_engine.cc - src/core/lib/event_engine/forkable.cc - - src/core/lib/event_engine/memory_allocator.cc - src/core/lib/event_engine/posix_engine/ev_epoll1_linux.cc - src/core/lib/event_engine/posix_engine/ev_poll_posix.cc - src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc @@ -2776,7 +2775,6 @@ libs: - src/core/lib/event_engine/default_event_engine_factory.cc - src/core/lib/event_engine/event_engine.cc - src/core/lib/event_engine/forkable.cc - - src/core/lib/event_engine/memory_allocator.cc - src/core/lib/event_engine/posix_engine/ev_epoll1_linux.cc - src/core/lib/event_engine/posix_engine/ev_poll_posix.cc - src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc @@ -4820,7 +4818,6 @@ libs: - src/core/lib/event_engine/default_event_engine_factory.cc - src/core/lib/event_engine/event_engine.cc - src/core/lib/event_engine/forkable.cc - - src/core/lib/event_engine/memory_allocator.cc - src/core/lib/event_engine/posix_engine/ev_epoll1_linux.cc - src/core/lib/event_engine/posix_engine/ev_poll_posix.cc - src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc @@ -7310,7 +7307,6 @@ targets: - src/core/ext/upb-gen/google/protobuf/descriptor.upb_minitable.c - src/core/ext/upb-gen/google/rpc/status.upb_minitable.c - src/core/lib/debug/trace.cc - - src/core/lib/event_engine/memory_allocator.cc - src/core/lib/experiments/config.cc - src/core/lib/experiments/experiments.cc - src/core/lib/gprpp/status_helper.cc @@ -9295,7 +9291,6 @@ targets: - src/core/ext/upb-gen/google/protobuf/descriptor.upb_minitable.c - src/core/ext/upb-gen/google/rpc/status.upb_minitable.c - src/core/lib/debug/trace.cc - - src/core/lib/event_engine/memory_allocator.cc - src/core/lib/experiments/config.cc - src/core/lib/experiments/experiments.cc - src/core/lib/gprpp/status_helper.cc @@ -9469,7 +9464,6 @@ targets: - src/core/ext/upb-gen/google/protobuf/descriptor.upb_minitable.c - src/core/ext/upb-gen/google/rpc/status.upb_minitable.c - src/core/lib/debug/trace.cc - - src/core/lib/event_engine/memory_allocator.cc - src/core/lib/experiments/config.cc - src/core/lib/experiments/experiments.cc - src/core/lib/gprpp/status_helper.cc @@ -11008,7 +11002,6 @@ targets: - src/core/ext/upb-gen/google/protobuf/descriptor.upb_minitable.c - src/core/ext/upb-gen/google/rpc/status.upb_minitable.c - src/core/lib/debug/trace.cc - - src/core/lib/event_engine/memory_allocator.cc - src/core/lib/experiments/config.cc - src/core/lib/experiments/experiments.cc - src/core/lib/gprpp/status_helper.cc @@ -11639,7 +11632,6 @@ targets: - src/core/ext/upb-gen/google/protobuf/descriptor.upb_minitable.c - src/core/ext/upb-gen/google/rpc/status.upb_minitable.c - src/core/lib/debug/trace.cc - - src/core/lib/event_engine/memory_allocator.cc - src/core/lib/experiments/config.cc - src/core/lib/experiments/experiments.cc - src/core/lib/gprpp/status_helper.cc @@ -17161,7 +17153,6 @@ targets: - src/core/lib/event_engine/default_event_engine_factory.cc - src/core/lib/event_engine/event_engine.cc - src/core/lib/event_engine/forkable.cc - - src/core/lib/event_engine/memory_allocator.cc - src/core/lib/event_engine/posix_engine/ev_epoll1_linux.cc - src/core/lib/event_engine/posix_engine/ev_poll_posix.cc - src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc diff --git a/config.m4 b/config.m4 index 894bef129aa1c..f4f52a0044c52 100644 --- a/config.m4 +++ b/config.m4 @@ -534,7 +534,6 @@ if test "$PHP_GRPC" != "no"; then src/core/lib/event_engine/default_event_engine_factory.cc \ src/core/lib/event_engine/event_engine.cc \ src/core/lib/event_engine/forkable.cc \ - src/core/lib/event_engine/memory_allocator.cc \ src/core/lib/event_engine/posix_engine/ev_epoll1_linux.cc \ src/core/lib/event_engine/posix_engine/ev_poll_posix.cc \ src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc \ diff --git a/config.w32 b/config.w32 index f778ae8e4b05f..52ac38f12049a 100644 --- a/config.w32 +++ b/config.w32 @@ -499,7 +499,6 @@ if (PHP_GRPC != "no") { "src\\core\\lib\\event_engine\\default_event_engine_factory.cc " + "src\\core\\lib\\event_engine\\event_engine.cc " + "src\\core\\lib\\event_engine\\forkable.cc " + - "src\\core\\lib\\event_engine\\memory_allocator.cc " + "src\\core\\lib\\event_engine\\posix_engine\\ev_epoll1_linux.cc " + "src\\core\\lib\\event_engine\\posix_engine\\ev_poll_posix.cc " + "src\\core\\lib\\event_engine\\posix_engine\\event_poller_posix_default.cc " + diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index a1a61b62611bf..303ac9ad5b295 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -1363,7 +1363,6 @@ Pod::Spec.new do |s| 'src/core/lib/event_engine/forkable.h', 'src/core/lib/event_engine/grpc_polled_fd.h', 'src/core/lib/event_engine/handle_containers.h', - 'src/core/lib/event_engine/memory_allocator.cc', 'src/core/lib/event_engine/memory_allocator_factory.h', 'src/core/lib/event_engine/nameser.h', 'src/core/lib/event_engine/poller.h', diff --git a/grpc.gemspec b/grpc.gemspec index aef58159c38c5..4b796f508bdcf 100644 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -1266,7 +1266,6 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/event_engine/forkable.h ) s.files += %w( src/core/lib/event_engine/grpc_polled_fd.h ) s.files += %w( src/core/lib/event_engine/handle_containers.h ) - s.files += %w( src/core/lib/event_engine/memory_allocator.cc ) s.files += %w( src/core/lib/event_engine/memory_allocator_factory.h ) s.files += %w( src/core/lib/event_engine/nameser.h ) s.files += %w( src/core/lib/event_engine/poller.h ) diff --git a/grpc.gyp b/grpc.gyp index 7a29bd04e941e..4b043c457b2a4 100644 --- a/grpc.gyp +++ b/grpc.gyp @@ -764,7 +764,6 @@ 'src/core/lib/event_engine/default_event_engine_factory.cc', 'src/core/lib/event_engine/event_engine.cc', 'src/core/lib/event_engine/forkable.cc', - 'src/core/lib/event_engine/memory_allocator.cc', 'src/core/lib/event_engine/posix_engine/ev_epoll1_linux.cc', 'src/core/lib/event_engine/posix_engine/ev_poll_posix.cc', 'src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc', @@ -1285,7 +1284,6 @@ 'src/core/lib/event_engine/default_event_engine_factory.cc', 'src/core/lib/event_engine/event_engine.cc', 'src/core/lib/event_engine/forkable.cc', - 'src/core/lib/event_engine/memory_allocator.cc', 'src/core/lib/event_engine/posix_engine/ev_epoll1_linux.cc', 'src/core/lib/event_engine/posix_engine/ev_poll_posix.cc', 'src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc', @@ -2065,7 +2063,6 @@ 'src/core/lib/event_engine/default_event_engine_factory.cc', 'src/core/lib/event_engine/event_engine.cc', 'src/core/lib/event_engine/forkable.cc', - 'src/core/lib/event_engine/memory_allocator.cc', 'src/core/lib/event_engine/posix_engine/ev_epoll1_linux.cc', 'src/core/lib/event_engine/posix_engine/ev_poll_posix.cc', 'src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc', diff --git a/include/grpc/event_engine/internal/memory_allocator_impl.h b/include/grpc/event_engine/internal/memory_allocator_impl.h index 8397b3d970643..e34ffc7f9c2a4 100644 --- a/include/grpc/event_engine/internal/memory_allocator_impl.h +++ b/include/grpc/event_engine/internal/memory_allocator_impl.h @@ -50,6 +50,12 @@ class MemoryAllocatorImpl /// request.max() inclusively. virtual size_t Reserve(MemoryRequest request) = 0; + /// Allocate a slice, using MemoryRequest to size the number of returned + /// bytes. For a variable length request, check the returned slice length to + /// verify how much memory was allocated. Takes care of reserving memory for + /// any relevant control structures also. + virtual grpc_slice MakeSlice(MemoryRequest request) = 0; + /// Release some bytes that were previously reserved. /// If more bytes are released than were reserved, we will have undefined /// behavior. diff --git a/include/grpc/event_engine/memory_allocator.h b/include/grpc/event_engine/memory_allocator.h index b3143d8dd6a79..cd14e3a93371f 100644 --- a/include/grpc/event_engine/memory_allocator.h +++ b/include/grpc/event_engine/memory_allocator.h @@ -134,7 +134,9 @@ class MemoryAllocator { /// bytes. For a variable length request, check the returned slice length to /// verify how much memory was allocated. Takes care of reserving memory for /// any relevant control structures also. - grpc_slice MakeSlice(MemoryRequest request); + grpc_slice MakeSlice(MemoryRequest request) { + return allocator_->MakeSlice(request); + } /// A C++ allocator for containers of T. template diff --git a/include/grpc/impl/channel_arg_names.h b/include/grpc/impl/channel_arg_names.h index b4cece27c9ef6..534300f22c24d 100644 --- a/include/grpc/impl/channel_arg_names.h +++ b/include/grpc/impl/channel_arg_names.h @@ -384,6 +384,11 @@ * Defaults to 250ms. */ #define GRPC_ARG_HAPPY_EYEBALLS_CONNECTION_ATTEMPT_DELAY_MS \ "grpc.happy_eyeballs_connection_attempt_delay_ms" +/** It accepts a MemoryAllocatorFactory as input and If specified, it forces + * the default event engine to use memory allocators created using the provided + * factory. */ +#define GRPC_ARG_EVENT_ENGINE_USE_MEMORY_ALLOCATOR_FACTORY \ + "grpc.event_engine_use_memory_allocator_factory" /** \} */ #endif /* GRPC_IMPL_CHANNEL_ARG_NAMES_H */ diff --git a/package.xml b/package.xml index 988766820114c..e0e276e52c71c 100644 --- a/package.xml +++ b/package.xml @@ -1248,7 +1248,6 @@ - diff --git a/src/core/BUILD b/src/core/BUILD index ffae458b39a18..449649facdcfd 100644 --- a/src/core/BUILD +++ b/src/core/BUILD @@ -1163,9 +1163,6 @@ grpc_cc_library( grpc_cc_library( name = "event_engine_memory_allocator", - srcs = [ - "lib/event_engine/memory_allocator.cc", - ], hdrs = [ "//:include/grpc/event_engine/internal/memory_allocator_impl.h", "//:include/grpc/event_engine/memory_allocator.h", @@ -1175,7 +1172,6 @@ grpc_cc_library( language = "c++", deps = [ "slice", - "slice_refcount", "//:gpr_platform", ], ) @@ -1221,6 +1217,7 @@ grpc_cc_library( "race", "resource_quota_trace", "seq", + "slice_refcount", "time", "useful", "//:gpr", diff --git a/src/core/lib/event_engine/memory_allocator.cc b/src/core/lib/event_engine/memory_allocator.cc deleted file mode 100644 index 69ece21c2944a..0000000000000 --- a/src/core/lib/event_engine/memory_allocator.cc +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2021 gRPC authors. -// -// Licensed 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. - -#include - -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include "src/core/lib/slice/slice_refcount.h" - -namespace grpc_event_engine { -namespace experimental { - -namespace { - -// Reference count for a slice allocated by MemoryAllocator::MakeSlice. -// Takes care of releasing memory back when the slice is destroyed. -class SliceRefCount : public grpc_slice_refcount { - public: - SliceRefCount(std::shared_ptr allocator, - size_t size) - : grpc_slice_refcount(Destroy), - allocator_(std::move(allocator)), - size_(size) { - // Nothing to do here. - } - ~SliceRefCount() { allocator_->Release(size_); } - - private: - static void Destroy(grpc_slice_refcount* p) { - auto* rc = static_cast(p); - rc->~SliceRefCount(); - free(rc); - } - - std::shared_ptr allocator_; - size_t size_; -}; - -} // namespace - -grpc_slice MemoryAllocator::MakeSlice(MemoryRequest request) { - auto size = Reserve(request.Increase(sizeof(SliceRefCount))); - void* p = malloc(size); - new (p) SliceRefCount(allocator_, size); - grpc_slice slice; - slice.refcount = static_cast(p); - slice.data.refcounted.bytes = - static_cast(p) + sizeof(SliceRefCount); - slice.data.refcounted.length = size - sizeof(SliceRefCount); - return slice; -} - -} // namespace experimental -} // namespace grpc_event_engine diff --git a/src/core/lib/event_engine/posix_engine/tcp_socket_utils.cc b/src/core/lib/event_engine/posix_engine/tcp_socket_utils.cc index c5b2277d6a753..76e1b0a57e199 100644 --- a/src/core/lib/event_engine/posix_engine/tcp_socket_utils.cc +++ b/src/core/lib/event_engine/posix_engine/tcp_socket_utils.cc @@ -25,6 +25,7 @@ #include "absl/types/optional.h" #include +#include #include #include "src/core/lib/gpr/useful.h" @@ -209,6 +210,13 @@ PosixTcpOptions TcpOptionsFromEndpointConfig(const EndpointConfig& config) { options.socket_mutator = grpc_socket_mutator_ref(static_cast(value)); } + value = + config.GetVoidPointer(GRPC_ARG_EVENT_ENGINE_USE_MEMORY_ALLOCATOR_FACTORY); + if (value != nullptr) { + options.memory_allocator_factory = + static_cast( + value); + } return options; } diff --git a/src/core/lib/event_engine/posix_engine/tcp_socket_utils.h b/src/core/lib/event_engine/posix_engine/tcp_socket_utils.h index 278e70ddbddbd..83b52be657c85 100644 --- a/src/core/lib/event_engine/posix_engine/tcp_socket_utils.h +++ b/src/core/lib/event_engine/posix_engine/tcp_socket_utils.h @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -75,6 +76,8 @@ struct PosixTcpOptions { int dscp = kDscpNotSet; grpc_core::RefCountedPtr resource_quota; struct grpc_socket_mutator* socket_mutator = nullptr; + grpc_event_engine::experimental::MemoryAllocatorFactory* + memory_allocator_factory = nullptr; PosixTcpOptions() = default; // Move ctor PosixTcpOptions(PosixTcpOptions&& other) noexcept { @@ -89,6 +92,8 @@ struct PosixTcpOptions { } socket_mutator = std::exchange(other.socket_mutator, nullptr); resource_quota = std::move(other.resource_quota); + memory_allocator_factory = + std::exchange(other.memory_allocator_factory, nullptr); CopyIntegerOptions(other); return *this; } @@ -98,6 +103,7 @@ struct PosixTcpOptions { socket_mutator = grpc_socket_mutator_ref(other.socket_mutator); } resource_quota = other.resource_quota; + memory_allocator_factory = other.memory_allocator_factory; CopyIntegerOptions(other); } // Copy assignment @@ -113,6 +119,7 @@ struct PosixTcpOptions { socket_mutator = grpc_socket_mutator_ref(other.socket_mutator); } resource_quota = other.resource_quota; + memory_allocator_factory = other.memory_allocator_factory; CopyIntegerOptions(other); return *this; } diff --git a/src/core/lib/resource_quota/memory_quota.cc b/src/core/lib/resource_quota/memory_quota.cc index 6335a54c484fd..0e63e45b4df6e 100644 --- a/src/core/lib/resource_quota/memory_quota.cc +++ b/src/core/lib/resource_quota/memory_quota.cc @@ -20,11 +20,19 @@ #include #include +#include +#include +#include +#include #include +#include #include "absl/status/status.h" #include "absl/strings/str_cat.h" +#include +#include + #include "src/core/lib/debug/trace.h" #include "src/core/lib/gpr/useful.h" #include "src/core/lib/gprpp/mpscq.h" @@ -34,6 +42,7 @@ #include "src/core/lib/promise/race.h" #include "src/core/lib/promise/seq.h" #include "src/core/lib/resource_quota/trace.h" +#include "src/core/lib/slice/slice_refcount.h" namespace grpc_core { @@ -90,6 +99,39 @@ class MemoryQuotaTracker { Mutex mu_; std::vector> quotas_ ABSL_GUARDED_BY(mu_); }; + +// Reference count for a slice allocated by MemoryAllocator::MakeSlice. +// Takes care of releasing memory back when the slice is destroyed. +class SliceRefCount : public grpc_slice_refcount { + public: + SliceRefCount( + std::shared_ptr< + grpc_event_engine::experimental::internal::MemoryAllocatorImpl> + allocator, + size_t size) + : grpc_slice_refcount(Destroy), + allocator_(std::move(allocator)), + size_(size) { + // Nothing to do here. + } + ~SliceRefCount() { + allocator_->Release(size_); + allocator_.reset(); + } + + private: + static void Destroy(grpc_slice_refcount* p) { + auto* rc = static_cast(p); + rc->~SliceRefCount(); + free(rc); + } + + std::shared_ptr< + grpc_event_engine::experimental::internal::MemoryAllocatorImpl> + allocator_; + size_t size_; +}; + } // namespace // @@ -337,6 +379,18 @@ void GrpcMemoryAllocatorImpl::Replenish() { free_bytes_.fetch_add(amount, std::memory_order_acq_rel); } +grpc_slice GrpcMemoryAllocatorImpl::MakeSlice(MemoryRequest request) { + auto size = Reserve(request.Increase(sizeof(SliceRefCount))); + void* p = malloc(size); + new (p) SliceRefCount(shared_from_this(), size); + grpc_slice slice; + slice.refcount = static_cast(p); + slice.data.refcounted.bytes = + static_cast(p) + sizeof(SliceRefCount); + slice.data.refcounted.length = size - sizeof(SliceRefCount); + return slice; +} + // // BasicMemoryQuota // diff --git a/src/core/lib/resource_quota/memory_quota.h b/src/core/lib/resource_quota/memory_quota.h index a76f2594d206c..4f38b8dd32d3d 100644 --- a/src/core/lib/resource_quota/memory_quota.h +++ b/src/core/lib/resource_quota/memory_quota.h @@ -400,6 +400,12 @@ class GrpcMemoryAllocatorImpl final : public EventEngineMemoryAllocatorImpl { // Returns the number of bytes reserved. size_t Reserve(MemoryRequest request) override; + /// Allocate a slice, using MemoryRequest to size the number of returned + /// bytes. For a variable length request, check the returned slice length to + /// verify how much memory was allocated. Takes care of reserving memory for + /// any relevant control structures also. + grpc_slice MakeSlice(MemoryRequest request) override; + // Release some bytes that were previously reserved. void Release(size_t n) override { // Add the released memory to our free bytes counter... if this increases diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index afbe5ec3ef000..d6304bccbdca8 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -508,7 +508,6 @@ 'src/core/lib/event_engine/default_event_engine_factory.cc', 'src/core/lib/event_engine/event_engine.cc', 'src/core/lib/event_engine/forkable.cc', - 'src/core/lib/event_engine/memory_allocator.cc', 'src/core/lib/event_engine/posix_engine/ev_epoll1_linux.cc', 'src/core/lib/event_engine/posix_engine/ev_poll_posix.cc', 'src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc', diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 5ff3e2299c99d..21666ae9e51b2 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -2265,7 +2265,6 @@ src/core/lib/event_engine/forkable.cc \ src/core/lib/event_engine/forkable.h \ src/core/lib/event_engine/grpc_polled_fd.h \ src/core/lib/event_engine/handle_containers.h \ -src/core/lib/event_engine/memory_allocator.cc \ src/core/lib/event_engine/memory_allocator_factory.h \ src/core/lib/event_engine/nameser.h \ src/core/lib/event_engine/poller.h \ diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 9ba3a65871f1a..b7b1ae5bf255a 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -2041,7 +2041,6 @@ src/core/lib/event_engine/forkable.cc \ src/core/lib/event_engine/forkable.h \ src/core/lib/event_engine/grpc_polled_fd.h \ src/core/lib/event_engine/handle_containers.h \ -src/core/lib/event_engine/memory_allocator.cc \ src/core/lib/event_engine/memory_allocator_factory.h \ src/core/lib/event_engine/nameser.h \ src/core/lib/event_engine/poller.h \ From 86d90f54b0ec6404e4142b4689e0f2a34057256e Mon Sep 17 00:00:00 2001 From: Yijie Ma Date: Fri, 8 Dec 2023 09:45:07 -0800 Subject: [PATCH 064/127] [EventEngine] Skip `dns_resolver_cooldown_test` for `event_engine_dns` experiment (#35251) Closes #35251 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35251 from yijiem:fix-dns-resolver-cooldown-test 857835200a1d9d4c02102cc8caa91d4c2366300c PiperOrigin-RevId: 589159895 --- src/core/lib/event_engine/posix_engine/posix_engine.cc | 2 +- src/core/lib/event_engine/posix_engine/posix_engine.h | 2 +- .../resolvers/dns_resolver_cooldown_test.cc | 9 +++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/core/lib/event_engine/posix_engine/posix_engine.cc b/src/core/lib/event_engine/posix_engine/posix_engine.cc index dad5bd03a6c8a..a5a4ee1b40fce 100644 --- a/src/core/lib/event_engine/posix_engine/posix_engine.cc +++ b/src/core/lib/event_engine/posix_engine/posix_engine.cc @@ -552,7 +552,7 @@ void PosixEventEngine::PosixDNSResolver::LookupTXT(LookupTXTCallback on_resolve, absl::StatusOr> PosixEventEngine::GetDNSResolver( - const EventEngine::DNSResolver::ResolverOptions& options) { + GRPC_UNUSED const EventEngine::DNSResolver::ResolverOptions& options) { #ifndef GRPC_POSIX_SOCKET_RESOLVE_ADDRESS grpc_core::Crash("Unable to get DNS resolver for this platform."); #else // GRPC_POSIX_SOCKET_RESOLVE_ADDRESS diff --git a/src/core/lib/event_engine/posix_engine/posix_engine.h b/src/core/lib/event_engine/posix_engine/posix_engine.h index e38479854e044..c025d46c6c895 100644 --- a/src/core/lib/event_engine/posix_engine/posix_engine.h +++ b/src/core/lib/event_engine/posix_engine/posix_engine.h @@ -198,7 +198,7 @@ class PosixEventEngine final : public PosixEventEngineWithFdSupport, bool CancelConnect(ConnectionHandle handle) override; bool IsWorkerThread() override; absl::StatusOr> GetDNSResolver( - const DNSResolver::ResolverOptions& options) override; + GRPC_UNUSED const DNSResolver::ResolverOptions& options) override; void Run(Closure* closure) override; void Run(absl::AnyInvocable closure) override; // Caution!! The timer implementation cannot create any fds. See #20418. diff --git a/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc b/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc index fc663837a8bf1..08f7e161a8fb0 100644 --- a/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc +++ b/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc @@ -42,6 +42,7 @@ #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/config/core_configuration.h" #include "src/core/lib/event_engine/default_event_engine.h" +#include "src/core/lib/experiments/experiments.h" #include "src/core/lib/gprpp/debug_location.h" #include "src/core/lib/gprpp/no_destruct.h" #include "src/core/lib/gprpp/notification.h" @@ -409,6 +410,14 @@ static void test_cooldown() { } TEST(DnsResolverCooldownTest, MainTest) { + // TODO(yijiem): This test tests the cooldown behavior of the PollingResolver + // interface. To do that, it overrides the grpc_dns_lookup_hostname_ares + // function and overrides the iomgr's g_dns_resolver system. We would need to + // rewrite this test for EventEngine using a custom EE DNSResolver or adding + // to the resolver_fuzzer. + if (grpc_core::IsEventEngineDnsEnabled()) { + GTEST_SKIP() << "Not with event engine dns"; + } grpc_init(); auto work_serializer = std::make_shared( From d9e4d1302e1055c1343c67c0067413b78030aa15 Mon Sep 17 00:00:00 2001 From: Eugene Ostroukhov Date: Fri, 8 Dec 2023 14:33:59 -0800 Subject: [PATCH 065/127] [examples] Implement custom metrics reporting from server (#35218) --- examples/cpp/cmake/common.cmake | 1 + examples/cpp/orca/BUILD | 29 +++++++++ examples/cpp/orca/README.md | 46 ++++++++++++++ examples/cpp/orca/orca_server.cc | 101 +++++++++++++++++++++++++++++++ 4 files changed, 177 insertions(+) create mode 100644 examples/cpp/orca/BUILD create mode 100644 examples/cpp/orca/README.md create mode 100644 examples/cpp/orca/orca_server.cc diff --git a/examples/cpp/cmake/common.cmake b/examples/cpp/cmake/common.cmake index 5c3d1053182d1..df9bc4db0f87f 100644 --- a/examples/cpp/cmake/common.cmake +++ b/examples/cpp/cmake/common.cmake @@ -51,6 +51,7 @@ if(GRPC_AS_SUBMODULE) # this build. set(_PROTOBUF_LIBPROTOBUF libprotobuf) set(_REFLECTION grpc++_reflection) + set(_ORCA_SERVICE grpcpp_orca_service) if(CMAKE_CROSSCOMPILING) find_program(_PROTOBUF_PROTOC protoc) else() diff --git a/examples/cpp/orca/BUILD b/examples/cpp/orca/BUILD new file mode 100644 index 0000000000000..f6641932a91b2 --- /dev/null +++ b/examples/cpp/orca/BUILD @@ -0,0 +1,29 @@ +# Copyright 2023 the gRPC authors. +# +# Licensed 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. + +licenses(["notice"]) + +cc_binary( + name = "orca_server", + srcs = ["orca_server.cc"], + defines = ["BAZEL_BUILD"], + deps = [ + "//:grpc++", + "//:grpcpp_orca_service", + "//examples/protos:helloworld_cc_grpc", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/flags:parse", + "@com_google_absl//absl/strings:str_format", + ], +) diff --git a/examples/cpp/orca/README.md b/examples/cpp/orca/README.md new file mode 100644 index 0000000000000..680a4970e59c7 --- /dev/null +++ b/examples/cpp/orca/README.md @@ -0,0 +1,46 @@ +# gRPC Custom Metrics Example + +You can find a complete set of instructions for building gRPC and running the +examples in the [C++ Quick Start][]. + +This example shows how to implement a server that provides custom metrics usable +by custom load balancing policies. + +Server needs to be setup with metrics recorder and Orca service for sending +these metrics to a client: + +```c++ +GreeterServiceImpl service; +// Setup custom metrics recording +auto server_metric_recorder = + grpc::experimental::ServerMetricRecorder::Create(); +grpc::experimental::OrcaService orca_service( + server_metric_recorder.get(), + grpc::experimental::OrcaService::Options().set_min_report_duration( + absl::Seconds(0.1))); +builder.RegisterService(&orca_service); +grpc::ServerBuilder::experimental_type(&builder).EnableCallMetricRecording( + nullptr); +``` + +Afterwards per-request metrics can be reported from the gRPC service +implementation using the metric recorder from the request context: + +```c++ +auto recorder = context->ExperimentalGetCallMetricRecorder(); +if (recorder == nullptr) { + return Status(grpc::StatusCode::INTERNAL, + "Unable to access metrics recorder. Make sure " + "EnableCallMetricRecording had been called."); +} +recorder->RecordCpuUtilizationMetric(0.5); +``` + +Out of band metrics can be reported using the `server_metric_recorder` +directly: + +```c++ +server_metric_recorder->SetCpuUtilization(0.75); +``` + +[C++ Quick Start]: https://grpc.io/docs/languages/cpp/quickstart diff --git a/examples/cpp/orca/orca_server.cc b/examples/cpp/orca/orca_server.cc new file mode 100644 index 0000000000000..d05d763a6a588 --- /dev/null +++ b/examples/cpp/orca/orca_server.cc @@ -0,0 +1,101 @@ +/* + * + * Copyright 2023 gRPC authors. + * + * Licensed 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. + * + */ +#include +#include +#include +#include + +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "absl/strings/str_format.h" +#include "examples/protos/helloworld.grpc.pb.h" + +#include +#include +#include +#include +#include + +using grpc::CallbackServerContext; +using grpc::Server; +using grpc::ServerBuilder; +using grpc::ServerUnaryReactor; +using grpc::Status; +using helloworld::Greeter; +using helloworld::HelloReply; +using helloworld::HelloRequest; + +ABSL_FLAG(uint16_t, port, 50051, "Server port for the service"); + +// Logic and data behind the server's behavior. +class GreeterServiceImpl final : public Greeter::CallbackService { + ServerUnaryReactor* SayHello(CallbackServerContext* context, + const HelloRequest* request, + HelloReply* reply) override { + ServerUnaryReactor* reactor = context->DefaultReactor(); + // Obtain the call metric recorder and use it to report the number of + // DB queries (custom cost metric) and CPU utilization. + auto recorder = context->ExperimentalGetCallMetricRecorder(); + if (recorder == nullptr) { + reactor->Finish({grpc::StatusCode::INTERNAL, + "Unable to access metrics recorder. Make sure " + "EnableCallMetricRecording had been called."}); + return reactor; + } + recorder->RecordRequestCostMetric("db_queries", 10); + recorder->RecordCpuUtilizationMetric(0.5); + std::string prefix("Hello "); + reply->set_message(prefix + request->name()); + reactor->Finish(Status::OK); + return reactor; + } +}; + +void RunServer(uint16_t port) { + std::string server_address = absl::StrFormat("0.0.0.0:%d", port); + ServerBuilder builder; + GreeterServiceImpl service; + // Setup custom metrics recording. Note that this recorder may be use to send + // the out-of-band metrics to the client. + auto server_metric_recorder = + grpc::experimental::ServerMetricRecorder::Create(); + grpc::experimental::OrcaService orca_service( + server_metric_recorder.get(), + grpc::experimental::OrcaService::Options().set_min_report_duration( + absl::Seconds(0.1))); + builder.RegisterService(&orca_service); + grpc::ServerBuilder::experimental_type(&builder).EnableCallMetricRecording( + server_metric_recorder.get()); + // Resume setting up gRPC server as usual + grpc::EnableDefaultHealthCheckService(true); + // Listen on the given address without any authentication mechanism. + builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); + // Register "service" as the instance through which we'll communicate with + // clients. In this case it corresponds to an *synchronous* service. + builder.RegisterService(&service); + // Finally assemble the server. + std::unique_ptr server(builder.BuildAndStart()); + std::cout << "Server listening on " << server_address << std::endl; + server->Wait(); +} + +int main(int argc, char** argv) { + absl::ParseCommandLine(argc, argv); + RunServer(absl::GetFlag(FLAGS_port)); + return 0; +} From c2261c6f280f0bda67060d0b8ffc593df852b625 Mon Sep 17 00:00:00 2001 From: Yash Tibrewal Date: Fri, 8 Dec 2023 14:34:26 -0800 Subject: [PATCH 066/127] [example] Add WAIT_FOR_READY example (#35219) --- examples/cpp/wait_for_ready/BUILD | 27 +++++ examples/cpp/wait_for_ready/CMakeLists.txt | 70 ++++++++++++ examples/cpp/wait_for_ready/README.md | 32 ++++++ .../wait_for_ready/greeter_callback_client.cc | 107 ++++++++++++++++++ 4 files changed, 236 insertions(+) create mode 100644 examples/cpp/wait_for_ready/BUILD create mode 100644 examples/cpp/wait_for_ready/CMakeLists.txt create mode 100644 examples/cpp/wait_for_ready/README.md create mode 100644 examples/cpp/wait_for_ready/greeter_callback_client.cc diff --git a/examples/cpp/wait_for_ready/BUILD b/examples/cpp/wait_for_ready/BUILD new file mode 100644 index 0000000000000..00047fa2f9bd3 --- /dev/null +++ b/examples/cpp/wait_for_ready/BUILD @@ -0,0 +1,27 @@ +# Copyright 2023 the gRPC authors. +# +# Licensed 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. + +licenses(["notice"]) + +cc_binary( + name = "greeter_callback_client", + srcs = ["greeter_callback_client.cc"], + defines = ["BAZEL_BUILD"], + deps = [ + "//:grpc++", + "//examples/protos:helloworld_cc_grpc", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/flags:parse", + ], +) diff --git a/examples/cpp/wait_for_ready/CMakeLists.txt b/examples/cpp/wait_for_ready/CMakeLists.txt new file mode 100644 index 0000000000000..06024dfbc9b8b --- /dev/null +++ b/examples/cpp/wait_for_ready/CMakeLists.txt @@ -0,0 +1,70 @@ +# Copyright 2018 gRPC authors. +# +# Licensed 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. +# +# cmake build file for C++ helloworld example. +# Assumes protobuf and gRPC have been installed using cmake. +# See cmake_externalproject/CMakeLists.txt for all-in-one cmake build +# that automatically builds all the dependencies before building helloworld. + +cmake_minimum_required(VERSION 3.8) + +project(HelloWorld C CXX) + +include(../cmake/common.cmake) + +# Proto file +get_filename_component(hw_proto "../../protos/helloworld.proto" ABSOLUTE) +get_filename_component(hw_proto_path "${hw_proto}" PATH) + +# Generated sources +set(hw_proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.pb.cc") +set(hw_proto_hdrs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.pb.h") +set(hw_grpc_srcs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.grpc.pb.cc") +set(hw_grpc_hdrs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.grpc.pb.h") +add_custom_command( + OUTPUT "${hw_proto_srcs}" "${hw_proto_hdrs}" "${hw_grpc_srcs}" "${hw_grpc_hdrs}" + COMMAND ${_PROTOBUF_PROTOC} + ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}" + --cpp_out "${CMAKE_CURRENT_BINARY_DIR}" + -I "${hw_proto_path}" + --plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}" + "${hw_proto}" + DEPENDS "${hw_proto}") + +# Include generated *.pb.h files +include_directories("${CMAKE_CURRENT_BINARY_DIR}") + +# hw_grpc_proto +add_library(hw_grpc_proto + ${hw_grpc_srcs} + ${hw_grpc_hdrs} + ${hw_proto_srcs} + ${hw_proto_hdrs}) +target_link_libraries(hw_grpc_proto + ${_REFLECTION} + ${_GRPC_GRPCPP} + ${_PROTOBUF_LIBPROTOBUF}) + +# Targets greeter_[async_](client|server) +foreach(_target + greeter_callback_client greeter_callback_server + add_executable(${_target} "${_target}.cc") + target_link_libraries(${_target} + hw_grpc_proto + absl::flags + absl::flags_parse + ${_REFLECTION} + ${_GRPC_GRPCPP} + ${_PROTOBUF_LIBPROTOBUF}) +endforeach() diff --git a/examples/cpp/wait_for_ready/README.md b/examples/cpp/wait_for_ready/README.md new file mode 100644 index 0000000000000..1de220b99a33b --- /dev/null +++ b/examples/cpp/wait_for_ready/README.md @@ -0,0 +1,32 @@ +# gRPC C++ Wait-For-Ready Example + +The Wait-For-Ready example builds on the +[Hello World Example](https://github.com/grpc/grpc/tree/master/examples/cpp/helloworld) +and changes the gRPC client and server to show how to set wait-for-ready. + +For more information on wait-for-ready in gRPC, please refer to +[gRPC Wait For Ready Semantics](https://github.com/grpc/grpc/blob/master/doc/wait-for-ready.md). + +## Running the example + +First run the client - + +``` +$ tools/bazel run examples/cpp/wait_for_ready:greeter_callback_client +``` + +On running this, we'll see 10 RPCs failed due to "Connection refused" errors. +These RPCs did not have WAIT_FOR_READY set, resulting in the RPCs not waiting +for the channel to be connected. + +The next 10 RPCs have WAIT_FOR_READY set, so the client will be waiting for the +channel to be ready before progressing. + +Now, on a separate terminal, run the server - + +``` +$ tools/bazel run examples/cpp/helloworld:greeter_callback_server +``` + +The client channel should now be able to connect to the server, and the RPCs +should succeed. diff --git a/examples/cpp/wait_for_ready/greeter_callback_client.cc b/examples/cpp/wait_for_ready/greeter_callback_client.cc new file mode 100644 index 0000000000000..1c7865ed2bfaf --- /dev/null +++ b/examples/cpp/wait_for_ready/greeter_callback_client.cc @@ -0,0 +1,107 @@ +// +// +// Copyright 2023 gRPC authors. +// +// Licensed 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. +// +// + +#include +#include +#include +#include +#include +#include + +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" + +#include + +#ifdef BAZEL_BUILD +#include "examples/protos/helloworld.grpc.pb.h" +#else +#include "helloworld.grpc.pb.h" +#endif + +ABSL_FLAG(std::string, target, "localhost:50051", "Server address"); + +using grpc::Channel; +using grpc::ClientContext; +using grpc::Status; +using helloworld::Greeter; +using helloworld::HelloReply; +using helloworld::HelloRequest; + +class GreeterClient { + public: + GreeterClient(std::shared_ptr channel) + : stub_(Greeter::NewStub(channel)) {} + + // Assembles the client's payload, sends it and presents the response back + // from the server. + std::string SayHello(const std::string& user, bool wait_for_ready) { + HelloRequest request; + request.set_name(user); + HelloReply reply; + ClientContext context; + context.set_wait_for_ready(wait_for_ready); + std::mutex mu; + std::condition_variable cv; + bool done = false; + Status status; + stub_->async()->SayHello(&context, &request, &reply, + [&mu, &cv, &done, &status](Status s) { + status = std::move(s); + std::lock_guard lock(mu); + done = true; + cv.notify_one(); + }); + + std::unique_lock lock(mu); + while (!done) { + cv.wait(lock); + } + if (status.ok()) { + return reply.message(); + } else { + std::cout << status.error_code() << ": " << status.error_message() + << "\n"; + return "RPC failed"; + } + } + + private: + std::unique_ptr stub_; +}; + +int main(int argc, char** argv) { + absl::ParseCommandLine(argc, argv); + std::string target_str = absl::GetFlag(FLAGS_target); + GreeterClient greeter( + grpc::CreateChannel(target_str, grpc::InsecureChannelCredentials())); + std::string user("world"); + // First send an RPC without wait_for_ready. If the server is not running, + // this RPC will fail immediately. + std::cout << "Greeter received: " + << greeter.SayHello(user, /*wait_for_ready=*/false) << "\n"; + std::cout << "\nWe will now send RPCs with wait_for_ready set. If the " + "server is not running already, please start it now.\n"; + // Now send RPC with wait_for_ready for set. Even if the server is not + // running, the RPC will still wait for the deadline to expire before + // failing. + std::cout << "Greeter received: " + << greeter.SayHello(user, /*wait_for_ready=*/true) << "\n"; + + return 0; +} From 16e4edcdcf6b1af0882cff554a3b547d7449e676 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Fri, 8 Dec 2023 16:03:19 -0800 Subject: [PATCH 067/127] [PSM Interop] Configure CODEOWNERS (#35254) Configures CODEOWNERS for the PSM Interop framework `/tools/run_tests/xds_k8s_test_driver/` to be @sergiitk, @XuanWang-Amos, @gnossen. We need this change to be able to prevent unexpected changes to the the framework while it's being moved to the dedicated grpc/psm-interop repo. --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index db7205ff49a25..2f76047357419 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -10,3 +10,4 @@ /src/core/lib/resolver/** @markdroth /src/core/lib/service_config/** @markdroth /tools/dockerfile/** @jtattermusch @apolcyn +/tools/run_tests/xds_k8s_test_driver/** @sergiitk @XuanWang-Amos @gnossen From 2fde70a6be978a4de9b7b119da8ca6120c5e271b Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 8 Dec 2023 16:54:07 -0800 Subject: [PATCH 068/127] [call-v3] Generic forwarder from a CallHandler to a CallInterceptor (#35256) Closes #35256 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35256 from ctiller:cg-fwd-call cdaae8bccd99d1b39c310efc42b3fe98a6723802 PiperOrigin-RevId: 589278551 --- build_autogenerated.yaml | 2 + src/core/BUILD | 2 + src/core/lib/promise/detail/status.h | 2 +- src/core/lib/promise/for_each.h | 14 +++++- src/core/lib/promise/status_flag.h | 7 +++ src/core/lib/promise/try_seq.h | 38 +++++++++++++++- src/core/lib/transport/transport.cc | 66 ++++++++++++++++++++++++++++ src/core/lib/transport/transport.h | 30 ++++++++++++- 8 files changed, 155 insertions(+), 6 deletions(-) diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index f5ea18449e226..09460f09a88fd 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -9393,6 +9393,7 @@ targets: - src/core/lib/promise/poll.h - src/core/lib/promise/race.h - src/core/lib/promise/seq.h + - src/core/lib/promise/status_flag.h - src/core/lib/promise/trace.h - src/core/lib/promise/try_seq.h - src/core/lib/resource_quota/arena.h @@ -11561,6 +11562,7 @@ targets: - src/core/lib/promise/poll.h - src/core/lib/promise/race.h - src/core/lib/promise/seq.h + - src/core/lib/promise/status_flag.h - src/core/lib/promise/trace.h - src/core/lib/promise/try_seq.h - src/core/lib/resource_quota/arena.h diff --git a/src/core/BUILD b/src/core/BUILD index 449649facdcfd..36bad285ae59c 100644 --- a/src/core/BUILD +++ b/src/core/BUILD @@ -1020,7 +1020,9 @@ grpc_cc_library( "construct_destruct", "poll", "promise_factory", + "promise_status", "promise_trace", + "status_flag", "//:gpr", "//:gpr_platform", ], diff --git a/src/core/lib/promise/detail/status.h b/src/core/lib/promise/detail/status.h index b20239de865be..1063f32919355 100644 --- a/src/core/lib/promise/detail/status.h +++ b/src/core/lib/promise/detail/status.h @@ -45,7 +45,7 @@ inline absl::Status IntoStatus(absl::Status* status) { // can participate in TrySeq as result types that affect control flow. inline bool IsStatusOk(const absl::Status& status) { return status.ok(); } -template +template struct StatusCastImpl; template diff --git a/src/core/lib/promise/for_each.h b/src/core/lib/promise/for_each.h index 1e6a829431287..2b8e9b10cc9a7 100644 --- a/src/core/lib/promise/for_each.h +++ b/src/core/lib/promise/for_each.h @@ -30,7 +30,9 @@ #include "src/core/lib/gprpp/construct_destruct.h" #include "src/core/lib/promise/activity.h" #include "src/core/lib/promise/detail/promise_factory.h" +#include "src/core/lib/promise/detail/status.h" #include "src/core/lib/promise/poll.h" +#include "src/core/lib/promise/status_flag.h" #include "src/core/lib/promise/trace.h" namespace grpc_core { @@ -48,6 +50,16 @@ struct Done { static absl::Status Make() { return absl::OkStatus(); } }; +template <> +struct Done { + static StatusFlag Make() { return StatusFlag(true); } +}; + +template <> +struct Done { + static Success Make() { return Success{}; } +}; + template class ForEach { private: @@ -139,7 +151,7 @@ class ForEach { } auto r = in_action_.promise(); if (auto* p = r.value_if_ready()) { - if (p->ok()) { + if (IsStatusOk(*p)) { Destruct(&in_action_); Construct(&reader_next_, reader_.Next()); reading_next_ = true; diff --git a/src/core/lib/promise/status_flag.h b/src/core/lib/promise/status_flag.h index 54019d387408a..1d7b09fabeacb 100644 --- a/src/core/lib/promise/status_flag.h +++ b/src/core/lib/promise/status_flag.h @@ -66,6 +66,13 @@ struct StatusCastImpl { } }; +template <> +struct StatusCastImpl { + static absl::Status Cast(StatusFlag flag) { + return flag.ok() ? absl::OkStatus() : absl::CancelledError(); + } +}; + template <> struct StatusCastImpl { static absl::Status Cast(StatusFlag flag) { diff --git a/src/core/lib/promise/try_seq.h b/src/core/lib/promise/try_seq.h index 71946e0e29029..266a09839a708 100644 --- a/src/core/lib/promise/try_seq.h +++ b/src/core/lib/promise/try_seq.h @@ -85,13 +85,23 @@ struct TrySeqTraitsWithSfinae> { return run_next(std::move(prior)); } }; +template +struct TakeValueExists { + static constexpr bool value = false; +}; +template +struct TakeValueExists()))>> { + static constexpr bool value = true; +}; // If there exists a function 'IsStatusOk(const T&) -> bool' then we assume that // T is a status type for the purposes of promise sequences, and a non-OK T // should terminate the sequence and return. template struct TrySeqTraitsWithSfinae< T, absl::enable_if_t< - std::is_same())), bool>::value, + std::is_same())), bool>::value && + !TakeValueExists::value, void>> { using UnwrappedType = void; using WrappedType = T; @@ -102,7 +112,31 @@ struct TrySeqTraitsWithSfinae< static bool IsOk(const T& status) { return IsStatusOk(status); } template static R ReturnValue(T&& status) { - return R(std::move(status)); + return StatusCast(std::move(status)); + } + template + static Poll CheckResultAndRunNext(T prior, RunNext run_next) { + if (!IsStatusOk(prior)) return Result(std::move(prior)); + return run_next(std::move(prior)); + } +}; +template +struct TrySeqTraitsWithSfinae< + T, absl::enable_if_t< + std::is_same())), bool>::value && + TakeValueExists::value, + void>> { + using UnwrappedType = decltype(TakeValue(std::declval())); + using WrappedType = T; + template + static auto CallFactory(Next* next, T&& status) { + return next->Make(TakeValue(std::forward(status))); + } + static bool IsOk(const T& status) { return IsStatusOk(status); } + template + static R ReturnValue(T&& status) { + GPR_DEBUG_ASSERT(!IsStatusOk(status)); + return StatusCast(std::move(status)); } template static Poll CheckResultAndRunNext(T prior, RunNext run_next) { diff --git a/src/core/lib/transport/transport.cc b/src/core/lib/transport/transport.cc index bbe256136495a..ab405804065e4 100644 --- a/src/core/lib/transport/transport.cc +++ b/src/core/lib/transport/transport.cc @@ -35,6 +35,9 @@ #include "src/core/lib/event_engine/default_event_engine.h" #include "src/core/lib/gprpp/time.h" #include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/promise/for_each.h" +#include "src/core/lib/promise/promise.h" +#include "src/core/lib/promise/try_seq.h" #include "src/core/lib/slice/slice.h" #include "src/core/lib/transport/error_utils.h" @@ -268,4 +271,67 @@ std::string Message::DebugString() const { return out; } +void ForwardCall(CallHandler call_handler, CallInitiator call_initiator, + ClientMetadataHandle client_initial_metadata) { + // Send initial metadata. + call_initiator.SpawnGuarded( + "send_initial_metadata", + [client_initial_metadata = std::move(client_initial_metadata), + call_initiator]() mutable { + return call_initiator.PushClientInitialMetadata( + std::move(client_initial_metadata)); + }); + // Read messages from handler into initiator. + call_handler.SpawnGuarded( + "read_messages", [call_handler, call_initiator]() mutable { + return ForEach(OutgoingMessages(call_handler), + [call_initiator](MessageHandle msg) mutable { + // Need to spawn a job into the initiator's activity to + // push the message in. + return call_initiator.SpawnWaitable( + "send_message", + [msg = std::move(msg), call_initiator]() mutable { + return call_initiator.CancelIfFails(Map( + call_initiator.PushMessage(std::move(msg)), + [](bool r) { return StatusFlag(r); })); + }); + }); + }); + call_initiator.SpawnInfallible("read_the_things", [call_initiator, + call_handler]() mutable { + return Seq( + call_initiator.CancelIfFails(TrySeq( + call_initiator.PullServerInitialMetadata(), + [call_handler](ServerMetadataHandle md) mutable { + call_handler.SpawnGuarded( + "recv_initial_metadata", + [md = std::move(md), call_handler]() mutable { + return call_handler.PushServerInitialMetadata( + std::move(md)); + }); + return Success{}; + }, + ForEach(OutgoingMessages(call_initiator), + [call_handler](MessageHandle msg) mutable { + return call_handler.SpawnWaitable( + "recv_message", + [msg = std::move(msg), call_handler]() mutable { + return call_handler.CancelIfFails( + Map(call_handler.PushMessage(std::move(msg)), + [](bool r) { return StatusFlag(r); })); + }); + }), + ImmediateOkStatus())), + call_initiator.PullServerTrailingMetadata(), + [call_handler](ServerMetadataHandle md) mutable { + call_handler.SpawnGuarded( + "recv_trailing_metadata", + [md = std::move(md), call_handler]() mutable { + return call_handler.PushServerTrailingMetadata(std::move(md)); + }); + return Empty{}; + }); + }); +} + } // namespace grpc_core diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h index f34692c8ddc0a..d35bdf5179a0b 100644 --- a/src/core/lib/transport/transport.h +++ b/src/core/lib/transport/transport.h @@ -150,6 +150,17 @@ struct StatusCastImpl { } }; +// Anything that can be first cast to absl::Status can then be cast to +// ServerMetadataHandle. +template +struct StatusCastImpl< + ServerMetadataHandle, T, + absl::void_t(std::declval()))>> { + static ServerMetadataHandle Cast(const T& m) { + return ServerMetadataFromStatus(StatusCast(m)); + } +}; + // Move only type that tracks call startup. // Allows observation of when client_initial_metadata has been processed by the // end of the local call stack. @@ -283,9 +294,9 @@ class CallSpineInterface { using ResultType = typename P::Result; return Map(std::move(promise), [this](ResultType r) { if (!IsStatusOk(r)) { - std::ignore = Cancel(StatusCast(std::move(r))); + std::ignore = Cancel(StatusCast(r)); } - return Empty{}; + return r; }); } @@ -410,6 +421,11 @@ class CallInitiator { spine_->SpawnInfallible(name, std::move(promise_factory)); } + template + auto SpawnWaitable(absl::string_view name, PromiseFactory promise_factory) { + return spine_->party().SpawnWaitable(name, std::move(promise_factory)); + } + private: const RefCountedPtr spine_; }; @@ -466,6 +482,11 @@ class CallHandler { spine_->SpawnInfallible(name, std::move(promise_factory)); } + template + auto SpawnWaitable(absl::string_view name, PromiseFactory promise_factory) { + return spine_->party().SpawnWaitable(name, std::move(promise_factory)); + } + private: const RefCountedPtr spine_; }; @@ -479,6 +500,11 @@ auto OutgoingMessages(CallHalf& h) { return Wrapper{h}; } +// Forward a call from `call_handler` to `call_initiator` (with initial metadata +// `client_initial_metadata`) +void ForwardCall(CallHandler call_handler, CallInitiator call_initiator, + ClientMetadataHandle client_initial_metadata); + } // namespace grpc_core // forward declarations From 42b57fc632cbbe9ad10ee8d65d5e8a7d1a30e248 Mon Sep 17 00:00:00 2001 From: Hannah Shi Date: Fri, 8 Dec 2023 18:55:07 -0800 Subject: [PATCH 069/127] [ObjC] Support use frameworks! (#34921) 1. add swift example configured with `use_frameworks!`. 2. fix [unable to find C++ headers](https://source.cloud.google.com/results/invocations/2100300a-0b61-4e56-8a77-113e362f2c63/targets/grpc%2Fcore%2Fpull_request%2Fmacos%2Fgrpc_basictests_objc_examples/log) by renaming `.m` files to `.mm`. `/Volumes/BuildData/tmpfs/altsrc/github/grpc/workspace_objc_macos_opt_native/src/objective-c/examples/SwiftUseFrameworks/Build/Build/Build/Products/Debug-iphoneos/gRPC-Core/grpc.framework/Headers/grpc_audit_logging.h:24:10: fatal error: 'memory' file not found #include ` 3. fix [cyclic dependency errors](https://source.cloud.google.com/results/invocations/90972079-eade-4c07-a5c4-20f139c64d4e/targets/github%2Fgrpc%2Frun_tests%2Fobjc_macos_opt_native%2Fios-buildtest-example-switftsample/tests) by making `openssl/time.h` private. `/Applications/Xcode_14.1.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/usr/include/dispatch/dispatch.h:25:10: error: cyclic dependency in module 'Darwin': Darwin -> openssl_grpc -> UIKit -> Foundation -> CoreFoundation -> Dispatch -> Darwin` "Basic Tests ObjC Examples" succeeds with this PR: https://source.cloud.google.com/results/invocations/cff74ec0-43ca-43b9-a2ff-12edabc02896/targets Closes #34921 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/34921 from HannahShiSFB:support-use-frameworks 87ddd2309064a478df4636da82be7fbc16aad3cb PiperOrigin-RevId: 589300261 --- gRPC.podspec | 34 +- src/objective-c/BUILD | 46 +-- src/objective-c/BoringSSL-GRPC.podspec | 1 + ...ll+ChannelArg.m => GRPCCall+ChannelArg.mm} | 0 ...tials.m => GRPCCall+ChannelCredentials.mm} | 0 .../{GRPCCall+Cronet.m => GRPCCall+Cronet.mm} | 0 .../{GRPCCall+GID.m => GRPCCall+GID.mm} | 0 ...+Interceptor.m => GRPCCall+Interceptor.mm} | 0 .../{GRPCCall+OAuth2.m => GRPCCall+OAuth2.mm} | 0 .../{GRPCCall+Tests.m => GRPCCall+Tests.mm} | 0 .../GRPCClient/{GRPCCall.m => GRPCCall.mm} | 0 .../{GRPCCallLegacy.m => GRPCCallLegacy.mm} | 4 +- .../{GRPCCallOptions.m => GRPCCallOptions.mm} | 0 .../{GRPCInterceptor.m => GRPCInterceptor.mm} | 0 .../{GRPCTransport.m => GRPCTransport.mm} | 0 src/objective-c/GRPCClient/GRPCTypes.h | 2 +- .../GRPCClient/{GRPCTypes.m => GRPCTypes.mm} | 0 ...ernalTests.m => GRPCCall+InternalTests.mm} | 0 .../{ChannelArgsUtil.m => ChannelArgsUtil.mm} | 0 ...GRPCCallInternal.m => GRPCCallInternal.mm} | 0 .../{GRPCChannel.m => GRPCChannel.mm} | 2 +- .../{GRPCChannelPool.m => GRPCChannelPool.mm} | 0 ...mpletionQueue.m => GRPCCompletionQueue.mm} | 0 ...onetFactory.m => GRPCCoreCronetFactory.mm} | 0 ...lFactory.m => GRPCCronetChannelFactory.mm} | 0 .../{GRPCCoreFactory.m => GRPCCoreFactory.mm} | 0 .../GRPCCore/{GRPCHost.m => GRPCHost.mm} | 0 ...actory.m => GRPCInsecureChannelFactory.mm} | 0 .../{GRPCOpBatchLog.m => GRPCOpBatchLog.mm} | 0 ...RequestHeaders.m => GRPCRequestHeaders.mm} | 0 ...lFactory.m => GRPCSecureChannelFactory.mm} | 0 .../{GRPCWrappedCall.m => GRPCWrappedCall.mm} | 12 +- .../{NSData+GRPC.m => NSData+GRPC.mm} | 0 ...Dictionary+GRPC.m => NSDictionary+GRPC.mm} | 0 .../{NSError+GRPC.m => NSError+GRPC.mm} | 0 ...ort+Private.m => GRPCTransport+Private.mm} | 0 .../examples/SwiftUseFrameworks/Podfile | 19 + .../project.pbxproj | 366 ++++++++++++++++++ .../SwiftUseFrameworks/AppDelegate.swift | 36 ++ .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 13 + .../Assets.xcassets/Contents.json | 6 + .../Base.lproj/LaunchScreen.storyboard | 25 ++ .../Base.lproj/Main.storyboard | 24 ++ .../SwiftUseFrameworks/Info.plist | 25 ++ .../SwiftUseFrameworks/SceneDelegate.swift | 52 +++ .../SwiftUseFrameworks/ViewController.swift | 19 + templates/gRPC.podspec.template | 34 +- .../BoringSSL-GRPC.podspec.template | 1 + tools/run_tests/run_tests.py | 13 + 50 files changed, 678 insertions(+), 67 deletions(-) rename src/objective-c/GRPCClient/{GRPCCall+ChannelArg.m => GRPCCall+ChannelArg.mm} (100%) rename src/objective-c/GRPCClient/{GRPCCall+ChannelCredentials.m => GRPCCall+ChannelCredentials.mm} (100%) rename src/objective-c/GRPCClient/{GRPCCall+Cronet.m => GRPCCall+Cronet.mm} (100%) rename src/objective-c/GRPCClient/{GRPCCall+GID.m => GRPCCall+GID.mm} (100%) rename src/objective-c/GRPCClient/{GRPCCall+Interceptor.m => GRPCCall+Interceptor.mm} (100%) rename src/objective-c/GRPCClient/{GRPCCall+OAuth2.m => GRPCCall+OAuth2.mm} (100%) rename src/objective-c/GRPCClient/{GRPCCall+Tests.m => GRPCCall+Tests.mm} (100%) rename src/objective-c/GRPCClient/{GRPCCall.m => GRPCCall.mm} (100%) rename src/objective-c/GRPCClient/{GRPCCallLegacy.m => GRPCCallLegacy.mm} (99%) rename src/objective-c/GRPCClient/{GRPCCallOptions.m => GRPCCallOptions.mm} (100%) rename src/objective-c/GRPCClient/{GRPCInterceptor.m => GRPCInterceptor.mm} (100%) rename src/objective-c/GRPCClient/{GRPCTransport.m => GRPCTransport.mm} (100%) rename src/objective-c/GRPCClient/{GRPCTypes.m => GRPCTypes.mm} (100%) rename src/objective-c/GRPCClient/internal_testing/{GRPCCall+InternalTests.m => GRPCCall+InternalTests.mm} (100%) rename src/objective-c/GRPCClient/private/GRPCCore/{ChannelArgsUtil.m => ChannelArgsUtil.mm} (100%) rename src/objective-c/GRPCClient/private/GRPCCore/{GRPCCallInternal.m => GRPCCallInternal.mm} (100%) rename src/objective-c/GRPCClient/private/GRPCCore/{GRPCChannel.m => GRPCChannel.mm} (99%) rename src/objective-c/GRPCClient/private/GRPCCore/{GRPCChannelPool.m => GRPCChannelPool.mm} (100%) rename src/objective-c/GRPCClient/private/GRPCCore/{GRPCCompletionQueue.m => GRPCCompletionQueue.mm} (100%) rename src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/{GRPCCoreCronetFactory.m => GRPCCoreCronetFactory.mm} (100%) rename src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/{GRPCCronetChannelFactory.m => GRPCCronetChannelFactory.mm} (100%) rename src/objective-c/GRPCClient/private/GRPCCore/{GRPCCoreFactory.m => GRPCCoreFactory.mm} (100%) rename src/objective-c/GRPCClient/private/GRPCCore/{GRPCHost.m => GRPCHost.mm} (100%) rename src/objective-c/GRPCClient/private/GRPCCore/{GRPCInsecureChannelFactory.m => GRPCInsecureChannelFactory.mm} (100%) rename src/objective-c/GRPCClient/private/GRPCCore/{GRPCOpBatchLog.m => GRPCOpBatchLog.mm} (100%) rename src/objective-c/GRPCClient/private/GRPCCore/{GRPCRequestHeaders.m => GRPCRequestHeaders.mm} (100%) rename src/objective-c/GRPCClient/private/GRPCCore/{GRPCSecureChannelFactory.m => GRPCSecureChannelFactory.mm} (100%) rename src/objective-c/GRPCClient/private/GRPCCore/{GRPCWrappedCall.m => GRPCWrappedCall.mm} (97%) rename src/objective-c/GRPCClient/private/GRPCCore/{NSData+GRPC.m => NSData+GRPC.mm} (100%) rename src/objective-c/GRPCClient/private/GRPCCore/{NSDictionary+GRPC.m => NSDictionary+GRPC.mm} (100%) rename src/objective-c/GRPCClient/private/GRPCCore/{NSError+GRPC.m => NSError+GRPC.mm} (100%) rename src/objective-c/GRPCClient/private/{GRPCTransport+Private.m => GRPCTransport+Private.mm} (100%) create mode 100644 src/objective-c/examples/SwiftUseFrameworks/Podfile create mode 100644 src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks.xcodeproj/project.pbxproj create mode 100644 src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/AppDelegate.swift create mode 100644 src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/Assets.xcassets/Contents.json create mode 100644 src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/Base.lproj/LaunchScreen.storyboard create mode 100644 src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/Base.lproj/Main.storyboard create mode 100644 src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/Info.plist create mode 100644 src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/SceneDelegate.swift create mode 100644 src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/ViewController.swift diff --git a/gRPC.podspec b/gRPC.podspec index 120a23ffcbc9f..1ba1ac974bae9 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -70,7 +70,7 @@ Pod::Spec.new do |s| "src/objective-c/GRPCClient/GRPCCall+Tests.h", "src/objective-c/GRPCClient/GRPCCallLegacy.h", "src/objective-c/GRPCClient/GRPCTypes.h", - "src/objective-c/GRPCClient/GRPCTypes.m" + "src/objective-c/GRPCClient/GRPCTypes.mm" ss.dependency "gRPC-RxLibrary/Interface", version s.ios.deployment_target = '10.0' @@ -91,19 +91,19 @@ Pod::Spec.new do |s| 'src/objective-c/GRPCClient/version.h' ss.source_files = 'src/objective-c/GRPCClient/GRPCCall.h', - 'src/objective-c/GRPCClient/GRPCCall.m', + 'src/objective-c/GRPCClient/GRPCCall.mm', 'src/objective-c/GRPCClient/GRPCCall+Interceptor.h', - 'src/objective-c/GRPCClient/GRPCCall+Interceptor.m', + 'src/objective-c/GRPCClient/GRPCCall+Interceptor.mm', 'src/objective-c/GRPCClient/GRPCCallOptions.h', - 'src/objective-c/GRPCClient/GRPCCallOptions.m', + 'src/objective-c/GRPCClient/GRPCCallOptions.mm', 'src/objective-c/GRPCClient/GRPCDispatchable.h', 'src/objective-c/GRPCClient/GRPCInterceptor.h', - 'src/objective-c/GRPCClient/GRPCInterceptor.m', + 'src/objective-c/GRPCClient/GRPCInterceptor.mm', 'src/objective-c/GRPCClient/GRPCTransport.h', - 'src/objective-c/GRPCClient/GRPCTransport.m', + 'src/objective-c/GRPCClient/GRPCTransport.mm', 'src/objective-c/GRPCClient/internal/*.h', 'src/objective-c/GRPCClient/private/GRPCTransport+Private.h', - 'src/objective-c/GRPCClient/private/GRPCTransport+Private.m', + 'src/objective-c/GRPCClient/private/GRPCTransport+Private.mm', 'src/objective-c/GRPCClient/version.h' ss.dependency "#{s.name}/Interface-Legacy", version @@ -123,18 +123,18 @@ Pod::Spec.new do |s| 'src/objective-c/GRPCClient/GRPCCall+Tests.h', 'src/objective-c/GRPCClient/GRPCCall+ChannelArg.h' ss.private_header_files = 'src/objective-c/GRPCClient/private/GRPCCore/*.h' - ss.source_files = 'src/objective-c/GRPCClient/private/GRPCCore/*.{h,m}', + ss.source_files = 'src/objective-c/GRPCClient/private/GRPCCore/*.{h,mm}', 'src/objective-c/GRPCClient/GRPCCall+ChannelArg.h', - 'src/objective-c/GRPCClient/GRPCCall+ChannelArg.m', + 'src/objective-c/GRPCClient/GRPCCall+ChannelArg.mm', 'src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h', - 'src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.m', + 'src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.mm', 'src/objective-c/GRPCClient/GRPCCall+Cronet.h', - 'src/objective-c/GRPCClient/GRPCCall+Cronet.m', + 'src/objective-c/GRPCClient/GRPCCall+Cronet.mm', 'src/objective-c/GRPCClient/GRPCCall+OAuth2.h', - 'src/objective-c/GRPCClient/GRPCCall+OAuth2.m', + 'src/objective-c/GRPCClient/GRPCCall+OAuth2.mm', 'src/objective-c/GRPCClient/GRPCCall+Tests.h', - 'src/objective-c/GRPCClient/GRPCCall+Tests.m', - 'src/objective-c/GRPCClient/GRPCCallLegacy.m' + 'src/objective-c/GRPCClient/GRPCCall+Tests.mm', + 'src/objective-c/GRPCClient/GRPCCallLegacy.mm' # Certificates, to be able to establish TLS connections: ss.resource_bundles = { 'gRPCCertificates' => ['etc/roots.pem'] } @@ -154,8 +154,8 @@ Pod::Spec.new do |s| ss.header_mappings_dir = 'src/objective-c/GRPCClient' ss.source_files = 'src/objective-c/GRPCClient/GRPCCall+Cronet.h', - 'src/objective-c/GRPCClient/GRPCCall+Cronet.m', - 'src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/*.{h,m}' + 'src/objective-c/GRPCClient/GRPCCall+Cronet.mm', + 'src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/*.{h,mm}' ss.dependency "#{s.name}/GRPCCore", version ss.dependency 'gRPC-Core/Cronet-Implementation', version ss.dependency 'CronetFramework' @@ -176,7 +176,7 @@ Pod::Spec.new do |s| s.subspec 'InternalTesting' do |ss| ss.dependency "#{s.name}/GRPCCore", version ss.public_header_files = 'src/objective-c/GRPCClient/internal_testing/*.h' - ss.source_files = 'src/objective-c/GRPCClient/internal_testing/*.{h,m}' + ss.source_files = 'src/objective-c/GRPCClient/internal_testing/*.{h,mm}' ss.header_mappings_dir = 'src/objective-c/GRPCClient' s.ios.deployment_target = '10.0' diff --git a/src/objective-c/BUILD b/src/objective-c/BUILD index 79509248d6742..575c963674fcf 100644 --- a/src/objective-c/BUILD +++ b/src/objective-c/BUILD @@ -78,7 +78,7 @@ grpc_objc_library( grpc_objc_library( name = "grpc_objc_interface_types", srcs = [ - "GRPCClient/GRPCTypes.m", + "GRPCClient/GRPCTypes.mm", ], hdrs = [ "GRPCClient/GRPCTypes.h", @@ -88,12 +88,12 @@ grpc_objc_library( grpc_objc_library( name = "grpc_objc_interface", srcs = [ - "GRPCClient/GRPCCall.m", - "GRPCClient/GRPCCall+Interceptor.m", - "GRPCClient/GRPCCallOptions.m", - "GRPCClient/GRPCInterceptor.m", - "GRPCClient/GRPCTransport.m", - "GRPCClient/private/GRPCTransport+Private.m", + "GRPCClient/GRPCCall.mm", + "GRPCClient/GRPCCall+Interceptor.mm", + "GRPCClient/GRPCCallOptions.mm", + "GRPCClient/GRPCInterceptor.mm", + "GRPCClient/GRPCTransport.mm", + "GRPCClient/private/GRPCTransport+Private.mm", ], hdrs = [ "GRPCClient/GRPCCall.h", @@ -117,13 +117,13 @@ grpc_objc_library( grpc_objc_library( name = "grpc_objc_client", srcs = [ - "GRPCClient/GRPCCall+ChannelArg.m", - "GRPCClient/GRPCCall+ChannelCredentials.m", - "GRPCClient/GRPCCall+Cronet.m", - "GRPCClient/GRPCCall+OAuth2.m", - "GRPCClient/GRPCCall+Tests.m", - "GRPCClient/GRPCCallLegacy.m", - ] + glob(["GRPCClient/private/GRPCCore/*.m"]), + "GRPCClient/GRPCCall+ChannelArg.mm", + "GRPCClient/GRPCCall+ChannelCredentials.mm", + "GRPCClient/GRPCCall+Cronet.mm", + "GRPCClient/GRPCCall+OAuth2.mm", + "GRPCClient/GRPCCall+Tests.mm", + "GRPCClient/GRPCCallLegacy.mm", + ] + glob(["GRPCClient/private/GRPCCore/*.mm"]), hdrs = [ "GRPCClient/GRPCCall+ChannelArg.h", "GRPCClient/GRPCCall+ChannelCredentials.h", @@ -209,14 +209,14 @@ apple_resource_bundle( grpc_objc_library( name = "grpc_objc_client_core_internal_testing", srcs = [ - "GRPCClient/GRPCCall+ChannelArg.m", - "GRPCClient/GRPCCall+ChannelCredentials.m", - "GRPCClient/GRPCCall+Cronet.m", - "GRPCClient/GRPCCall+OAuth2.m", - "GRPCClient/GRPCCall+Tests.m", - "GRPCClient/GRPCCallLegacy.m", - "GRPCClient/internal_testing/GRPCCall+InternalTests.m", - ] + glob(["GRPCClient/private/GRPCCore/*.m"]), + "GRPCClient/GRPCCall+ChannelArg.mm", + "GRPCClient/GRPCCall+ChannelCredentials.mm", + "GRPCClient/GRPCCall+Cronet.mm", + "GRPCClient/GRPCCall+OAuth2.mm", + "GRPCClient/GRPCCall+Tests.mm", + "GRPCClient/GRPCCallLegacy.mm", + "GRPCClient/internal_testing/GRPCCall+InternalTests.mm", + ] + glob(["GRPCClient/private/GRPCCore/*.mm"]), hdrs = [ "GRPCClient/GRPCCall+ChannelArg.h", "GRPCClient/GRPCCall+ChannelCredentials.h", @@ -242,7 +242,7 @@ grpc_objc_library( # TODO: Enable this again once @CronetFramework is working #grpc_objc_library( # name = "grpc_objc_client_core_cronet_testing", -# srcs = glob(["GRPCClient/private/GRPCCore/GRPCCoreCronet/*.m"]), +# srcs = glob(["GRPCClient/private/GRPCCore/GRPCCoreCronet/*.mm"]), # hdrs = glob(["GRPCClient/private/GRPCCore/GRPCCoreCronet/*.h"]), # deps = [ # ":grpc_objc_client_core_internal_testing", diff --git a/src/objective-c/BoringSSL-GRPC.podspec b/src/objective-c/BoringSSL-GRPC.podspec index 10a15aaf1190a..6537a0a70a3c6 100644 --- a/src/objective-c/BoringSSL-GRPC.podspec +++ b/src/objective-c/BoringSSL-GRPC.podspec @@ -117,6 +117,7 @@ Pod::Spec.new do |s| # making the linter happy. s.subspec 'Interface' do |ss| ss.header_mappings_dir = 'src/include/openssl' + ss.private_header_files = 'src/include/openssl/time.h' ss.source_files = 'src/include/openssl/*.h' end s.subspec 'Implementation' do |ss| diff --git a/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.mm similarity index 100% rename from src/objective-c/GRPCClient/GRPCCall+ChannelArg.m rename to src/objective-c/GRPCClient/GRPCCall+ChannelArg.mm diff --git a/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.m b/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.mm similarity index 100% rename from src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.m rename to src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.mm diff --git a/src/objective-c/GRPCClient/GRPCCall+Cronet.m b/src/objective-c/GRPCClient/GRPCCall+Cronet.mm similarity index 100% rename from src/objective-c/GRPCClient/GRPCCall+Cronet.m rename to src/objective-c/GRPCClient/GRPCCall+Cronet.mm diff --git a/src/objective-c/GRPCClient/GRPCCall+GID.m b/src/objective-c/GRPCClient/GRPCCall+GID.mm similarity index 100% rename from src/objective-c/GRPCClient/GRPCCall+GID.m rename to src/objective-c/GRPCClient/GRPCCall+GID.mm diff --git a/src/objective-c/GRPCClient/GRPCCall+Interceptor.m b/src/objective-c/GRPCClient/GRPCCall+Interceptor.mm similarity index 100% rename from src/objective-c/GRPCClient/GRPCCall+Interceptor.m rename to src/objective-c/GRPCClient/GRPCCall+Interceptor.mm diff --git a/src/objective-c/GRPCClient/GRPCCall+OAuth2.m b/src/objective-c/GRPCClient/GRPCCall+OAuth2.mm similarity index 100% rename from src/objective-c/GRPCClient/GRPCCall+OAuth2.m rename to src/objective-c/GRPCClient/GRPCCall+OAuth2.mm diff --git a/src/objective-c/GRPCClient/GRPCCall+Tests.m b/src/objective-c/GRPCClient/GRPCCall+Tests.mm similarity index 100% rename from src/objective-c/GRPCClient/GRPCCall+Tests.m rename to src/objective-c/GRPCClient/GRPCCall+Tests.mm diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.mm similarity index 100% rename from src/objective-c/GRPCClient/GRPCCall.m rename to src/objective-c/GRPCClient/GRPCCall.mm diff --git a/src/objective-c/GRPCClient/GRPCCallLegacy.m b/src/objective-c/GRPCClient/GRPCCallLegacy.mm similarity index 99% rename from src/objective-c/GRPCClient/GRPCCallLegacy.m rename to src/objective-c/GRPCClient/GRPCCallLegacy.mm index b3cb11a3222a0..aeb9cbe923c60 100644 --- a/src/objective-c/GRPCClient/GRPCCallLegacy.m +++ b/src/objective-c/GRPCClient/GRPCCallLegacy.mm @@ -598,9 +598,9 @@ - (void)startWithWriteable:(id)writeable { } if (tokenProvider != nil) { - __weak typeof(self) weakSelf = self; + __weak auto weakSelf = self; [tokenProvider getTokenWithHandler:^(NSString *token) { - __strong typeof(self) strongSelf = weakSelf; + __strong auto strongSelf = weakSelf; if (strongSelf) { BOOL startCall = NO; @synchronized(strongSelf) { diff --git a/src/objective-c/GRPCClient/GRPCCallOptions.m b/src/objective-c/GRPCClient/GRPCCallOptions.mm similarity index 100% rename from src/objective-c/GRPCClient/GRPCCallOptions.m rename to src/objective-c/GRPCClient/GRPCCallOptions.mm diff --git a/src/objective-c/GRPCClient/GRPCInterceptor.m b/src/objective-c/GRPCClient/GRPCInterceptor.mm similarity index 100% rename from src/objective-c/GRPCClient/GRPCInterceptor.m rename to src/objective-c/GRPCClient/GRPCInterceptor.mm diff --git a/src/objective-c/GRPCClient/GRPCTransport.m b/src/objective-c/GRPCClient/GRPCTransport.mm similarity index 100% rename from src/objective-c/GRPCClient/GRPCTransport.m rename to src/objective-c/GRPCClient/GRPCTransport.mm diff --git a/src/objective-c/GRPCClient/GRPCTypes.h b/src/objective-c/GRPCClient/GRPCTypes.h index 2aa9fd7945beb..75702ddccf47d 100644 --- a/src/objective-c/GRPCClient/GRPCTypes.h +++ b/src/objective-c/GRPCClient/GRPCTypes.h @@ -171,7 +171,7 @@ extern NSString* _Nonnull const kGRPCHeadersKey; extern NSString* _Nonnull const kGRPCTrailersKey; /** The id of a transport implementation. */ -typedef char* _Nonnull GRPCTransportID; +typedef const char* _Nonnull GRPCTransportID; /** * Implement this protocol to provide a token to gRPC when a call is initiated. diff --git a/src/objective-c/GRPCClient/GRPCTypes.m b/src/objective-c/GRPCClient/GRPCTypes.mm similarity index 100% rename from src/objective-c/GRPCClient/GRPCTypes.m rename to src/objective-c/GRPCClient/GRPCTypes.mm diff --git a/src/objective-c/GRPCClient/internal_testing/GRPCCall+InternalTests.m b/src/objective-c/GRPCClient/internal_testing/GRPCCall+InternalTests.mm similarity index 100% rename from src/objective-c/GRPCClient/internal_testing/GRPCCall+InternalTests.m rename to src/objective-c/GRPCClient/internal_testing/GRPCCall+InternalTests.mm diff --git a/src/objective-c/GRPCClient/private/GRPCCore/ChannelArgsUtil.m b/src/objective-c/GRPCClient/private/GRPCCore/ChannelArgsUtil.mm similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/ChannelArgsUtil.m rename to src/objective-c/GRPCClient/private/GRPCCore/ChannelArgsUtil.mm diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCallInternal.m b/src/objective-c/GRPCClient/private/GRPCCore/GRPCCallInternal.mm similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCCallInternal.m rename to src/objective-c/GRPCClient/private/GRPCCore/GRPCCallInternal.mm diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCCore/GRPCChannel.mm similarity index 99% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCChannel.m rename to src/objective-c/GRPCClient/private/GRPCCore/GRPCChannel.mm index 5727f01c96ae6..7f29485fee3d4 100644 --- a/src/objective-c/GRPCClient/private/GRPCCore/GRPCChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCCore/GRPCChannel.mm @@ -127,7 +127,7 @@ - (NSDictionary *)channelArgs { [NSNumber numberWithUnsignedInteger:_callOptions.responseSizeLimit]; } - if (_callOptions.compressionAlgorithm != GRPC_COMPRESS_NONE) { + if (_callOptions.compressionAlgorithm != GRPCCompressNone) { args[@GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM] = [NSNumber numberWithInteger:_callOptions.compressionAlgorithm]; } diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCChannelPool.m b/src/objective-c/GRPCClient/private/GRPCCore/GRPCChannelPool.mm similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCChannelPool.m rename to src/objective-c/GRPCClient/private/GRPCCore/GRPCChannelPool.mm diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCompletionQueue.m b/src/objective-c/GRPCClient/private/GRPCCore/GRPCCompletionQueue.mm similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCCompletionQueue.m rename to src/objective-c/GRPCClient/private/GRPCCore/GRPCCompletionQueue.mm diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/GRPCCoreCronetFactory.m b/src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/GRPCCoreCronetFactory.mm similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/GRPCCoreCronetFactory.m rename to src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/GRPCCoreCronetFactory.mm diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/GRPCCronetChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/GRPCCronetChannelFactory.mm similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/GRPCCronetChannelFactory.m rename to src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/GRPCCronetChannelFactory.mm diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreFactory.m b/src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreFactory.mm similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreFactory.m rename to src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreFactory.mm diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCCore/GRPCHost.mm similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCHost.m rename to src/objective-c/GRPCClient/private/GRPCCore/GRPCHost.mm diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCInsecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCCore/GRPCInsecureChannelFactory.mm similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCInsecureChannelFactory.m rename to src/objective-c/GRPCClient/private/GRPCCore/GRPCInsecureChannelFactory.mm diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCOpBatchLog.m b/src/objective-c/GRPCClient/private/GRPCCore/GRPCOpBatchLog.mm similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCOpBatchLog.m rename to src/objective-c/GRPCClient/private/GRPCCore/GRPCOpBatchLog.mm diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCRequestHeaders.m b/src/objective-c/GRPCClient/private/GRPCCore/GRPCRequestHeaders.mm similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCRequestHeaders.m rename to src/objective-c/GRPCClient/private/GRPCCore/GRPCRequestHeaders.mm diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCSecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCCore/GRPCSecureChannelFactory.mm similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCSecureChannelFactory.m rename to src/objective-c/GRPCClient/private/GRPCCore/GRPCSecureChannelFactory.mm diff --git a/src/objective-c/GRPCClient/private/GRPCCore/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCCore/GRPCWrappedCall.mm similarity index 97% rename from src/objective-c/GRPCClient/private/GRPCCore/GRPCWrappedCall.m rename to src/objective-c/GRPCClient/private/GRPCCore/GRPCWrappedCall.mm index c54a9b8e29f6a..687bf9783b2ab 100644 --- a/src/objective-c/GRPCClient/private/GRPCCore/GRPCWrappedCall.m +++ b/src/objective-c/GRPCClient/private/GRPCCore/GRPCWrappedCall.mm @@ -140,9 +140,9 @@ - (instancetype)initWithHandler:(void (^)(NSDictionary *))handler { _op.data.recv_initial_metadata.recv_initial_metadata = &_headers; if (handler) { // Prevent reference cycle with _handler - __weak typeof(self) weakSelf = self; + __weak auto weakSelf = self; _handler = ^{ - __strong typeof(self) strongSelf = weakSelf; + __strong auto strongSelf = weakSelf; if (strongSelf) { NSDictionary *metadata = [NSDictionary grpc_dictionaryFromMetadataArray:strongSelf->_headers]; @@ -174,9 +174,9 @@ - (instancetype)initWithHandler:(void (^)(grpc_byte_buffer *))handler { _op.data.recv_message.recv_message = &_receivedMessage; if (handler) { // Prevent reference cycle with _handler - __weak typeof(self) weakSelf = self; + __weak auto weakSelf = self; _handler = ^{ - __strong typeof(self) strongSelf = weakSelf; + __strong auto strongSelf = weakSelf; if (strongSelf) { handler(strongSelf->_receivedMessage); } @@ -210,9 +210,9 @@ - (instancetype)initWithHandler:(void (^)(NSError *, NSDictionary *))handler { _op.data.recv_status_on_client.error_string = &_errorString; if (handler) { // Prevent reference cycle with _handler - __weak typeof(self) weakSelf = self; + __weak auto weakSelf = self; _handler = ^{ - __strong typeof(self) strongSelf = weakSelf; + __strong auto strongSelf = weakSelf; if (strongSelf) { char *details = grpc_slice_to_c_string(strongSelf->_details); NSError *error = [NSError grpc_errorFromStatusCode:strongSelf->_statusCode diff --git a/src/objective-c/GRPCClient/private/GRPCCore/NSData+GRPC.m b/src/objective-c/GRPCClient/private/GRPCCore/NSData+GRPC.mm similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/NSData+GRPC.m rename to src/objective-c/GRPCClient/private/GRPCCore/NSData+GRPC.mm diff --git a/src/objective-c/GRPCClient/private/GRPCCore/NSDictionary+GRPC.m b/src/objective-c/GRPCClient/private/GRPCCore/NSDictionary+GRPC.mm similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/NSDictionary+GRPC.m rename to src/objective-c/GRPCClient/private/GRPCCore/NSDictionary+GRPC.mm diff --git a/src/objective-c/GRPCClient/private/GRPCCore/NSError+GRPC.m b/src/objective-c/GRPCClient/private/GRPCCore/NSError+GRPC.mm similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCCore/NSError+GRPC.m rename to src/objective-c/GRPCClient/private/GRPCCore/NSError+GRPC.mm diff --git a/src/objective-c/GRPCClient/private/GRPCTransport+Private.m b/src/objective-c/GRPCClient/private/GRPCTransport+Private.mm similarity index 100% rename from src/objective-c/GRPCClient/private/GRPCTransport+Private.m rename to src/objective-c/GRPCClient/private/GRPCTransport+Private.mm diff --git a/src/objective-c/examples/SwiftUseFrameworks/Podfile b/src/objective-c/examples/SwiftUseFrameworks/Podfile new file mode 100644 index 0000000000000..4b74f61470504 --- /dev/null +++ b/src/objective-c/examples/SwiftUseFrameworks/Podfile @@ -0,0 +1,19 @@ +source 'https://github.com/CocoaPods/Specs.git' +platform :ios, '10.0' + +# Without this we get linker errors due to files with same names but different paths +# ref: https://github.com/CocoaPods/CocoaPods/issues/8289#issuecomment-1022723820 +install! 'cocoapods', :deterministic_uuids => false + +use_frameworks! + +# Location of gRPC's repo root relative to this file. +GRPC_LOCAL_SRC = '../../../..' + +target 'SwiftUseFrameworks' do + pod 'gRPC', :path => GRPC_LOCAL_SRC + pod 'gRPC-Core', :path => GRPC_LOCAL_SRC + pod 'gRPC-C++', :path => GRPC_LOCAL_SRC + pod 'gRPC-RxLibrary', :path => GRPC_LOCAL_SRC + pod 'BoringSSL-GRPC', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c" +end diff --git a/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks.xcodeproj/project.pbxproj b/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks.xcodeproj/project.pbxproj new file mode 100644 index 0000000000000..7d139519db8eb --- /dev/null +++ b/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks.xcodeproj/project.pbxproj @@ -0,0 +1,366 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + 0F54974D2ADC8E6500A6D01F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F54974C2ADC8E6500A6D01F /* AppDelegate.swift */; }; + 0F54974F2ADC8E6500A6D01F /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F54974E2ADC8E6500A6D01F /* SceneDelegate.swift */; }; + 0F5497512ADC8E6500A6D01F /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F5497502ADC8E6500A6D01F /* ViewController.swift */; }; + 0F5497542ADC8E6500A6D01F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0F5497522ADC8E6500A6D01F /* Main.storyboard */; }; + 0F5497562ADC8E6500A6D01F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0F5497552ADC8E6500A6D01F /* Assets.xcassets */; }; + 0F5497592ADC8E6500A6D01F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0F5497572ADC8E6500A6D01F /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 0F5497492ADC8E6500A6D01F /* SwiftUseFrameworks.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftUseFrameworks.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 0F54974C2ADC8E6500A6D01F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 0F54974E2ADC8E6500A6D01F /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 0F5497502ADC8E6500A6D01F /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 0F5497532ADC8E6500A6D01F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 0F5497552ADC8E6500A6D01F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 0F5497582ADC8E6500A6D01F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 0F54975A2ADC8E6500A6D01F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 0F5497462ADC8E6500A6D01F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0F5497402ADC8E6500A6D01F = { + isa = PBXGroup; + children = ( + 0F54974B2ADC8E6500A6D01F /* SwiftUseFrameworks */, + 0F54974A2ADC8E6500A6D01F /* Products */, + ); + sourceTree = ""; + }; + 0F54974A2ADC8E6500A6D01F /* Products */ = { + isa = PBXGroup; + children = ( + 0F5497492ADC8E6500A6D01F /* SwiftUseFrameworks.app */, + ); + name = Products; + sourceTree = ""; + }; + 0F54974B2ADC8E6500A6D01F /* SwiftUseFrameworks */ = { + isa = PBXGroup; + children = ( + 0F54974C2ADC8E6500A6D01F /* AppDelegate.swift */, + 0F54974E2ADC8E6500A6D01F /* SceneDelegate.swift */, + 0F5497502ADC8E6500A6D01F /* ViewController.swift */, + 0F5497522ADC8E6500A6D01F /* Main.storyboard */, + 0F5497552ADC8E6500A6D01F /* Assets.xcassets */, + 0F5497572ADC8E6500A6D01F /* LaunchScreen.storyboard */, + 0F54975A2ADC8E6500A6D01F /* Info.plist */, + ); + path = SwiftUseFrameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 0F5497482ADC8E6500A6D01F /* SwiftUseFrameworks */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0F54975D2ADC8E6500A6D01F /* Build configuration list for PBXNativeTarget "SwiftUseFrameworks" */; + buildPhases = ( + 0F5497452ADC8E6500A6D01F /* Sources */, + 0F5497462ADC8E6500A6D01F /* Frameworks */, + 0F5497472ADC8E6500A6D01F /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SwiftUseFrameworks; + productName = SwiftUseFrameworks; + productReference = 0F5497492ADC8E6500A6D01F /* SwiftUseFrameworks.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0F5497412ADC8E6500A6D01F /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1500; + LastUpgradeCheck = 1500; + TargetAttributes = { + 0F5497482ADC8E6500A6D01F = { + CreatedOnToolsVersion = 15.0; + }; + }; + }; + buildConfigurationList = 0F5497442ADC8E6500A6D01F /* Build configuration list for PBXProject "SwiftUseFrameworks" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 0F5497402ADC8E6500A6D01F; + productRefGroup = 0F54974A2ADC8E6500A6D01F /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 0F5497482ADC8E6500A6D01F /* SwiftUseFrameworks */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 0F5497472ADC8E6500A6D01F /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0F5497592ADC8E6500A6D01F /* LaunchScreen.storyboard in Resources */, + 0F5497562ADC8E6500A6D01F /* Assets.xcassets in Resources */, + 0F5497542ADC8E6500A6D01F /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 0F5497452ADC8E6500A6D01F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0F5497512ADC8E6500A6D01F /* ViewController.swift in Sources */, + 0F54974D2ADC8E6500A6D01F /* AppDelegate.swift in Sources */, + 0F54974F2ADC8E6500A6D01F /* SceneDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 0F5497522ADC8E6500A6D01F /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 0F5497532ADC8E6500A6D01F /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 0F5497572ADC8E6500A6D01F /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 0F5497582ADC8E6500A6D01F /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 0F54975B2ADC8E6500A6D01F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 0F54975C2ADC8E6500A6D01F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 0F54975E2ADC8E6500A6D01F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = F4HM4BJK94; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = SwiftUseFrameworks/Info.plist; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.SwiftUseFrameworks; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 0F54975F2ADC8E6500A6D01F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = F4HM4BJK94; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = SwiftUseFrameworks/Info.plist; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = io.grpc.SwiftUseFrameworks; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 0F5497442ADC8E6500A6D01F /* Build configuration list for PBXProject "SwiftUseFrameworks" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0F54975B2ADC8E6500A6D01F /* Debug */, + 0F54975C2ADC8E6500A6D01F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 0F54975D2ADC8E6500A6D01F /* Build configuration list for PBXNativeTarget "SwiftUseFrameworks" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0F54975E2ADC8E6500A6D01F /* Debug */, + 0F54975F2ADC8E6500A6D01F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0F5497412ADC8E6500A6D01F /* Project object */; +} diff --git a/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/AppDelegate.swift b/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/AppDelegate.swift new file mode 100644 index 0000000000000..b956706162cf4 --- /dev/null +++ b/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/AppDelegate.swift @@ -0,0 +1,36 @@ +// +// AppDelegate.swift +// SwiftUseFrameworks +// +// Created by Hannah Shi on 10/15/23. +// + +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + // MARK: UISceneSession Lifecycle + + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + } + + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. + } + + +} + diff --git a/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/Assets.xcassets/AccentColor.colorset/Contents.json b/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000000000..eb87897008164 --- /dev/null +++ b/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/Assets.xcassets/AppIcon.appiconset/Contents.json b/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000000..13613e3ee1a93 --- /dev/null +++ b/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/Assets.xcassets/Contents.json b/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/Assets.xcassets/Contents.json new file mode 100644 index 0000000000000..73c00596a7fca --- /dev/null +++ b/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/Base.lproj/LaunchScreen.storyboard b/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000000000..865e9329f3767 --- /dev/null +++ b/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/Base.lproj/Main.storyboard b/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/Base.lproj/Main.storyboard new file mode 100644 index 0000000000000..25a763858ecdb --- /dev/null +++ b/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/Base.lproj/Main.storyboard @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/Info.plist b/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/Info.plist new file mode 100644 index 0000000000000..dd3c9afdae358 --- /dev/null +++ b/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/Info.plist @@ -0,0 +1,25 @@ + + + + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + + diff --git a/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/SceneDelegate.swift b/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/SceneDelegate.swift new file mode 100644 index 0000000000000..1e2bc2f4a599e --- /dev/null +++ b/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/SceneDelegate.swift @@ -0,0 +1,52 @@ +// +// SceneDelegate.swift +// SwiftUseFrameworks +// +// Created by Hannah Shi on 10/15/23. +// + +import UIKit + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. + // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. + // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). + guard let _ = (scene as? UIWindowScene) else { return } + } + + func sceneDidDisconnect(_ scene: UIScene) { + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). + } + + func sceneDidBecomeActive(_ scene: UIScene) { + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. + } + + func sceneWillResignActive(_ scene: UIScene) { + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). + } + + func sceneWillEnterForeground(_ scene: UIScene) { + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. + } + + func sceneDidEnterBackground(_ scene: UIScene) { + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, and store enough scene-specific state information + // to restore the scene back to its current state. + } + + +} + diff --git a/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/ViewController.swift b/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/ViewController.swift new file mode 100644 index 0000000000000..180428789857f --- /dev/null +++ b/src/objective-c/examples/SwiftUseFrameworks/SwiftUseFrameworks/ViewController.swift @@ -0,0 +1,19 @@ +// +// ViewController.swift +// SwiftUseFrameworks +// +// Created by Hannah Shi on 10/15/23. +// + +import UIKit + +class ViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view. + } + + +} + diff --git a/templates/gRPC.podspec.template b/templates/gRPC.podspec.template index 6bba4e1aa6c6c..c1f739ce85e84 100644 --- a/templates/gRPC.podspec.template +++ b/templates/gRPC.podspec.template @@ -72,7 +72,7 @@ "src/objective-c/GRPCClient/GRPCCall+Tests.h", "src/objective-c/GRPCClient/GRPCCallLegacy.h", "src/objective-c/GRPCClient/GRPCTypes.h", - "src/objective-c/GRPCClient/GRPCTypes.m" + "src/objective-c/GRPCClient/GRPCTypes.mm" ss.dependency "gRPC-RxLibrary/Interface", version s.ios.deployment_target = '10.0' @@ -93,19 +93,19 @@ 'src/objective-c/GRPCClient/version.h' ss.source_files = 'src/objective-c/GRPCClient/GRPCCall.h', - 'src/objective-c/GRPCClient/GRPCCall.m', + 'src/objective-c/GRPCClient/GRPCCall.mm', 'src/objective-c/GRPCClient/GRPCCall+Interceptor.h', - 'src/objective-c/GRPCClient/GRPCCall+Interceptor.m', + 'src/objective-c/GRPCClient/GRPCCall+Interceptor.mm', 'src/objective-c/GRPCClient/GRPCCallOptions.h', - 'src/objective-c/GRPCClient/GRPCCallOptions.m', + 'src/objective-c/GRPCClient/GRPCCallOptions.mm', 'src/objective-c/GRPCClient/GRPCDispatchable.h', 'src/objective-c/GRPCClient/GRPCInterceptor.h', - 'src/objective-c/GRPCClient/GRPCInterceptor.m', + 'src/objective-c/GRPCClient/GRPCInterceptor.mm', 'src/objective-c/GRPCClient/GRPCTransport.h', - 'src/objective-c/GRPCClient/GRPCTransport.m', + 'src/objective-c/GRPCClient/GRPCTransport.mm', 'src/objective-c/GRPCClient/internal/*.h', 'src/objective-c/GRPCClient/private/GRPCTransport+Private.h', - 'src/objective-c/GRPCClient/private/GRPCTransport+Private.m', + 'src/objective-c/GRPCClient/private/GRPCTransport+Private.mm', 'src/objective-c/GRPCClient/version.h' ss.dependency "#{s.name}/Interface-Legacy", version @@ -125,18 +125,18 @@ 'src/objective-c/GRPCClient/GRPCCall+Tests.h', 'src/objective-c/GRPCClient/GRPCCall+ChannelArg.h' ss.private_header_files = 'src/objective-c/GRPCClient/private/GRPCCore/*.h' - ss.source_files = 'src/objective-c/GRPCClient/private/GRPCCore/*.{h,m}', + ss.source_files = 'src/objective-c/GRPCClient/private/GRPCCore/*.{h,mm}', 'src/objective-c/GRPCClient/GRPCCall+ChannelArg.h', - 'src/objective-c/GRPCClient/GRPCCall+ChannelArg.m', + 'src/objective-c/GRPCClient/GRPCCall+ChannelArg.mm', 'src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h', - 'src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.m', + 'src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.mm', 'src/objective-c/GRPCClient/GRPCCall+Cronet.h', - 'src/objective-c/GRPCClient/GRPCCall+Cronet.m', + 'src/objective-c/GRPCClient/GRPCCall+Cronet.mm', 'src/objective-c/GRPCClient/GRPCCall+OAuth2.h', - 'src/objective-c/GRPCClient/GRPCCall+OAuth2.m', + 'src/objective-c/GRPCClient/GRPCCall+OAuth2.mm', 'src/objective-c/GRPCClient/GRPCCall+Tests.h', - 'src/objective-c/GRPCClient/GRPCCall+Tests.m', - 'src/objective-c/GRPCClient/GRPCCallLegacy.m' + 'src/objective-c/GRPCClient/GRPCCall+Tests.mm', + 'src/objective-c/GRPCClient/GRPCCallLegacy.mm' # Certificates, to be able to establish TLS connections: ss.resource_bundles = { 'gRPCCertificates' => ['etc/roots.pem'] } @@ -156,8 +156,8 @@ ss.header_mappings_dir = 'src/objective-c/GRPCClient' ss.source_files = 'src/objective-c/GRPCClient/GRPCCall+Cronet.h', - 'src/objective-c/GRPCClient/GRPCCall+Cronet.m', - 'src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/*.{h,m}' + 'src/objective-c/GRPCClient/GRPCCall+Cronet.mm', + 'src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/*.{h,mm}' ss.dependency "#{s.name}/GRPCCore", version ss.dependency 'gRPC-Core/Cronet-Implementation', version ss.dependency 'CronetFramework' @@ -178,7 +178,7 @@ s.subspec 'InternalTesting' do |ss| ss.dependency "#{s.name}/GRPCCore", version ss.public_header_files = 'src/objective-c/GRPCClient/internal_testing/*.h' - ss.source_files = 'src/objective-c/GRPCClient/internal_testing/*.{h,m}' + ss.source_files = 'src/objective-c/GRPCClient/internal_testing/*.{h,mm}' ss.header_mappings_dir = 'src/objective-c/GRPCClient' s.ios.deployment_target = '10.0' diff --git a/templates/src/objective-c/BoringSSL-GRPC.podspec.template b/templates/src/objective-c/BoringSSL-GRPC.podspec.template index 8220876951ae1..e0b511d30ea6e 100644 --- a/templates/src/objective-c/BoringSSL-GRPC.podspec.template +++ b/templates/src/objective-c/BoringSSL-GRPC.podspec.template @@ -147,6 +147,7 @@ # making the linter happy. s.subspec 'Interface' do |ss| ss.header_mappings_dir = 'src/include/openssl' + ss.private_header_files = 'src/include/openssl/time.h' ss.source_files = 'src/include/openssl/*.h' end s.subspec 'Implementation' do |ss| diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index 091817a065a97..ea1b1b0205269 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -1187,6 +1187,19 @@ def test_specs(self): }, ) ) + out.append( + self.config.job_spec( + ["src/objective-c/tests/build_one_example.sh"], + timeout_seconds=20 * 60, + shortname="ios-buildtest-example-switft-use-frameworks", + cpu_cost=1e6, + environ={ + "SCHEME": "SwiftUseFrameworks", + "EXAMPLE_PATH": "src/objective-c/examples/SwiftUseFrameworks", + }, + ) + ) + # Disabled due to #20258 # TODO (mxyan): Reenable this test when #20258 is resolved. # out.append( From 71367424d694f1acde8dcef1ef1773740bade8a1 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Sun, 10 Dec 2023 14:42:24 -0800 Subject: [PATCH 070/127] [call-v3] Make call traces show useful information (#35262) Closes #35262 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35262 from ctiller:cg-call-trace 16ea4c880718d3149711327b2146a933459046b2 PiperOrigin-RevId: 589637737 --- src/core/lib/surface/call_trace.cc | 42 +++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/core/lib/surface/call_trace.cc b/src/core/lib/surface/call_trace.cc index d9b544ee1f9d6..9b198f4abc878 100644 --- a/src/core/lib/surface/call_trace.cc +++ b/src/core/lib/surface/call_trace.cc @@ -77,7 +77,47 @@ const grpc_channel_filter* PromiseTracingFilterFor( return r; }; }, - /* init_call: */ nullptr, grpc_channel_next_op, + /* init_call: */ + [](grpc_channel_element* elem, CallSpineInterface* call) { + auto* source_filter = + static_cast(elem->filter)->filter; + call->client_initial_metadata().receiver.InterceptAndMap( + [source_filter](ClientMetadataHandle md) { + gpr_log(GPR_DEBUG, "%s[%s] OnClientInitialMetadata: %s", + Activity::current()->DebugTag().c_str(), + source_filter->name, md->DebugString().c_str()); + return md; + }); + call->client_to_server_messages().receiver.InterceptAndMap( + [source_filter](MessageHandle msg) { + gpr_log(GPR_DEBUG, "%s[%s] OnClientToServerMessage: %s", + Activity::current()->DebugTag().c_str(), + source_filter->name, msg->DebugString().c_str()); + return msg; + }); + call->server_initial_metadata().sender.InterceptAndMap( + [source_filter](ServerMetadataHandle md) { + gpr_log(GPR_DEBUG, "%s[%s] OnServerInitialMetadata: %s", + Activity::current()->DebugTag().c_str(), + source_filter->name, md->DebugString().c_str()); + return md; + }); + call->server_to_client_messages().sender.InterceptAndMap( + [source_filter](MessageHandle msg) { + gpr_log(GPR_DEBUG, "%s[%s] OnServerToClientMessage: %s", + Activity::current()->DebugTag().c_str(), + source_filter->name, msg->DebugString().c_str()); + return msg; + }); + call->server_trailing_metadata().sender.InterceptAndMap( + [source_filter](ServerMetadataHandle md) { + gpr_log(GPR_DEBUG, "%s[%s] OnServerTrailingMetadata: %s", + Activity::current()->DebugTag().c_str(), + source_filter->name, md->DebugString().c_str()); + return md; + }); + }, + grpc_channel_next_op, /* sizeof_call_data: */ 0, // init_call_elem: [](grpc_call_element*, const grpc_call_element_args*) { From dd1246001894d69c10a3dd4c0e02defab6bc52a4 Mon Sep 17 00:00:00 2001 From: Luwei Ge Date: Mon, 11 Dec 2023 09:22:40 -0800 Subject: [PATCH 071/127] [tls] Add set min/max TLS version APIs to TLS credentials APIs. (#34861) Address #28382. This is a recreation of #31368 except e2e tests are not handled here (yet). Closes #34861 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/34861 from rockspore:tls_version f9a1215ac1291722dba4f22cedc128c241aa3cab PiperOrigin-RevId: 589847110 --- grpc.def | 2 ++ include/grpc/grpc_security.h | 18 ++++++++++++++++++ .../grpcpp/security/tls_credentials_options.h | 9 +++++++++ .../tls/grpc_tls_credentials_options.cc | 12 ++++++++++++ .../credentials/tls/tls_credentials.cc | 16 ++++++++++++++++ src/cpp/common/tls_credentials_options.cc | 12 ++++++++++++ src/ruby/ext/grpc/rb_grpc_imports.generated.c | 4 ++++ src/ruby/ext/grpc/rb_grpc_imports.generated.h | 6 ++++++ .../grpc_tls_credentials_options_test.cc | 16 ++++++++++++++++ test/cpp/client/credentials_test.cc | 16 ++++++++++++++++ test/cpp/server/credentials_test.cc | 18 ++++++++++++++++++ 11 files changed, 129 insertions(+) diff --git a/grpc.def b/grpc.def index c3f8af10860b8..0cc981d0fd54c 100644 --- a/grpc.def +++ b/grpc.def @@ -157,6 +157,8 @@ EXPORTS grpc_tls_certificate_provider_file_watcher_create grpc_tls_certificate_provider_release grpc_tls_credentials_options_create + grpc_tls_credentials_options_set_min_tls_version + grpc_tls_credentials_options_set_max_tls_version grpc_tls_credentials_options_copy grpc_tls_credentials_options_destroy grpc_tls_credentials_options_set_certificate_provider diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h index d099ff6293316..c81b81a207b90 100644 --- a/include/grpc/grpc_security.h +++ b/include/grpc/grpc_security.h @@ -815,6 +815,24 @@ GRPCAPI void grpc_tls_certificate_provider_release( */ GRPCAPI grpc_tls_credentials_options* grpc_tls_credentials_options_create(void); +/** + * EXPERIMENTAL API - Subject to change + * + * Sets the minimum TLS version that will be negotiated during the TLS + * handshake. If not set, the underlying SSL library will set it to TLS v1.2. + */ +GRPCAPI void grpc_tls_credentials_options_set_min_tls_version( + grpc_tls_credentials_options* options, grpc_tls_version min_tls_version); + +/** + * EXPERIMENTAL API - Subject to change + * + * Sets the maximum TLS version that will be negotiated during the TLS + * handshake. If not set, the underlying SSL library will set it to TLS v1.3. + */ +GRPCAPI void grpc_tls_credentials_options_set_max_tls_version( + grpc_tls_credentials_options* options, grpc_tls_version max_tls_version); + /** * EXPERIMENTAL API - Subject to change * diff --git a/include/grpcpp/security/tls_credentials_options.h b/include/grpcpp/security/tls_credentials_options.h index 7ad5b0885680d..7f5cb8208fafe 100644 --- a/include/grpcpp/security/tls_credentials_options.h +++ b/include/grpcpp/security/tls_credentials_options.h @@ -109,6 +109,15 @@ class TlsCredentialsOptions { void set_crl_provider(std::shared_ptr crl_provider); + // Sets the minimum TLS version that will be negotiated during the TLS + // handshake. If not set, the underlying SSL library will use TLS v1.2. + // @param tls_version: The minimum TLS version. + void set_min_tls_version(grpc_tls_version tls_version); + // Sets the maximum TLS version that will be negotiated during the TLS + // handshake. If not set, the underlying SSL library will use TLS v1.3. + // @param tls_version: The maximum TLS version. + void set_max_tls_version(grpc_tls_version tls_version); + // ----- Getters for member fields ---- // Returns a deep copy of the internal c options. The caller takes ownership // of the returned pointer. This function shall be used only internally. diff --git a/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc b/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc index 3c090011f3164..0dcc959bf3c5e 100644 --- a/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc +++ b/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc @@ -149,3 +149,15 @@ void grpc_tls_credentials_options_set_crl_provider( GPR_ASSERT(options != nullptr); options->set_crl_provider(provider); } + +void grpc_tls_credentials_options_set_min_tls_version( + grpc_tls_credentials_options* options, grpc_tls_version min_tls_version) { + GPR_ASSERT(options != nullptr); + options->set_min_tls_version(min_tls_version); +} + +void grpc_tls_credentials_options_set_max_tls_version( + grpc_tls_credentials_options* options, grpc_tls_version max_tls_version) { + GPR_ASSERT(options != nullptr); + options->set_max_tls_version(max_tls_version); +} diff --git a/src/core/lib/security/credentials/tls/tls_credentials.cc b/src/core/lib/security/credentials/tls/tls_credentials.cc index c1a27343fb774..eac64307f8df4 100644 --- a/src/core/lib/security/credentials/tls/tls_credentials.cc +++ b/src/core/lib/security/credentials/tls/tls_credentials.cc @@ -46,6 +46,22 @@ bool CredentialOptionSanityCheck(grpc_tls_credentials_options* options, gpr_log(GPR_ERROR, "TLS credentials options is nullptr."); return false; } + // In this case, there will be non-retriable handshake errors. + if (options->min_tls_version() > options->max_tls_version()) { + gpr_log(GPR_ERROR, "TLS min version must not be higher than max version."); + grpc_tls_credentials_options_destroy(options); + return false; + } + if (options->max_tls_version() > grpc_tls_version::TLS1_3) { + gpr_log(GPR_ERROR, "TLS max version must not be higher than v1.3."); + grpc_tls_credentials_options_destroy(options); + return false; + } + if (options->min_tls_version() < grpc_tls_version::TLS1_2) { + gpr_log(GPR_ERROR, "TLS min version must not be lower than v1.2."); + grpc_tls_credentials_options_destroy(options); + return false; + } if (!options->crl_directory().empty() && options->crl_provider() != nullptr) { gpr_log(GPR_ERROR, "Setting crl_directory and crl_provider not supported. Using the " diff --git a/src/cpp/common/tls_credentials_options.cc b/src/cpp/common/tls_credentials_options.cc index 6e907704652e6..6732aca3454b5 100644 --- a/src/cpp/common/tls_credentials_options.cc +++ b/src/cpp/common/tls_credentials_options.cc @@ -95,6 +95,18 @@ void TlsCredentialsOptions::set_certificate_verifier( } } +void TlsCredentialsOptions::set_min_tls_version(grpc_tls_version tls_version) { + grpc_tls_credentials_options* options = mutable_c_credentials_options(); + GPR_ASSERT(options != nullptr); + grpc_tls_credentials_options_set_min_tls_version(options, tls_version); +} + +void TlsCredentialsOptions::set_max_tls_version(grpc_tls_version tls_version) { + grpc_tls_credentials_options* options = mutable_c_credentials_options(); + GPR_ASSERT(options != nullptr); + grpc_tls_credentials_options_set_max_tls_version(options, tls_version); +} + grpc_tls_credentials_options* TlsCredentialsOptions::c_credentials_options() const { return grpc_tls_credentials_options_copy(c_credentials_options_); diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c index 641c9cb97cc47..b28175e01655e 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c @@ -180,6 +180,8 @@ grpc_tls_certificate_provider_static_data_create_type grpc_tls_certificate_provi grpc_tls_certificate_provider_file_watcher_create_type grpc_tls_certificate_provider_file_watcher_create_import; grpc_tls_certificate_provider_release_type grpc_tls_certificate_provider_release_import; grpc_tls_credentials_options_create_type grpc_tls_credentials_options_create_import; +grpc_tls_credentials_options_set_min_tls_version_type grpc_tls_credentials_options_set_min_tls_version_import; +grpc_tls_credentials_options_set_max_tls_version_type grpc_tls_credentials_options_set_max_tls_version_import; grpc_tls_credentials_options_copy_type grpc_tls_credentials_options_copy_import; grpc_tls_credentials_options_destroy_type grpc_tls_credentials_options_destroy_import; grpc_tls_credentials_options_set_certificate_provider_type grpc_tls_credentials_options_set_certificate_provider_import; @@ -469,6 +471,8 @@ void grpc_rb_load_imports(HMODULE library) { grpc_tls_certificate_provider_file_watcher_create_import = (grpc_tls_certificate_provider_file_watcher_create_type) GetProcAddress(library, "grpc_tls_certificate_provider_file_watcher_create"); grpc_tls_certificate_provider_release_import = (grpc_tls_certificate_provider_release_type) GetProcAddress(library, "grpc_tls_certificate_provider_release"); grpc_tls_credentials_options_create_import = (grpc_tls_credentials_options_create_type) GetProcAddress(library, "grpc_tls_credentials_options_create"); + grpc_tls_credentials_options_set_min_tls_version_import = (grpc_tls_credentials_options_set_min_tls_version_type) GetProcAddress(library, "grpc_tls_credentials_options_set_min_tls_version"); + grpc_tls_credentials_options_set_max_tls_version_import = (grpc_tls_credentials_options_set_max_tls_version_type) GetProcAddress(library, "grpc_tls_credentials_options_set_max_tls_version"); grpc_tls_credentials_options_copy_import = (grpc_tls_credentials_options_copy_type) GetProcAddress(library, "grpc_tls_credentials_options_copy"); grpc_tls_credentials_options_destroy_import = (grpc_tls_credentials_options_destroy_type) GetProcAddress(library, "grpc_tls_credentials_options_destroy"); grpc_tls_credentials_options_set_certificate_provider_import = (grpc_tls_credentials_options_set_certificate_provider_type) GetProcAddress(library, "grpc_tls_credentials_options_set_certificate_provider"); diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h index 55da803ef6a6c..65c095a96e42a 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h @@ -515,6 +515,12 @@ extern grpc_tls_certificate_provider_release_type grpc_tls_certificate_provider_ typedef grpc_tls_credentials_options*(*grpc_tls_credentials_options_create_type)(void); extern grpc_tls_credentials_options_create_type grpc_tls_credentials_options_create_import; #define grpc_tls_credentials_options_create grpc_tls_credentials_options_create_import +typedef void(*grpc_tls_credentials_options_set_min_tls_version_type)(grpc_tls_credentials_options* options, grpc_tls_version min_tls_version); +extern grpc_tls_credentials_options_set_min_tls_version_type grpc_tls_credentials_options_set_min_tls_version_import; +#define grpc_tls_credentials_options_set_min_tls_version grpc_tls_credentials_options_set_min_tls_version_import +typedef void(*grpc_tls_credentials_options_set_max_tls_version_type)(grpc_tls_credentials_options* options, grpc_tls_version max_tls_version); +extern grpc_tls_credentials_options_set_max_tls_version_type grpc_tls_credentials_options_set_max_tls_version_import; +#define grpc_tls_credentials_options_set_max_tls_version grpc_tls_credentials_options_set_max_tls_version_import typedef grpc_tls_credentials_options*(*grpc_tls_credentials_options_copy_type)(grpc_tls_credentials_options* options); extern grpc_tls_credentials_options_copy_type grpc_tls_credentials_options_copy_import; #define grpc_tls_credentials_options_copy grpc_tls_credentials_options_copy_import diff --git a/test/core/security/grpc_tls_credentials_options_test.cc b/test/core/security/grpc_tls_credentials_options_test.cc index b6708224fd5ab..9cafa1b98b278 100644 --- a/test/core/security/grpc_tls_credentials_options_test.cc +++ b/test/core/security/grpc_tls_credentials_options_test.cc @@ -67,6 +67,22 @@ class GrpcTlsCredentialsOptionsTest : public ::testing::Test { HostNameCertificateVerifier hostname_certificate_verifier_; }; +TEST_F(GrpcTlsCredentialsOptionsTest, BadTlsVersionsForChannelCredentials) { + auto options = grpc_tls_credentials_options_create(); + options->set_max_tls_version(grpc_tls_version::TLS1_2); + options->set_min_tls_version(grpc_tls_version::TLS1_3); + auto credentials = grpc_tls_credentials_create(options); + EXPECT_EQ(credentials, nullptr); +} + +TEST_F(GrpcTlsCredentialsOptionsTest, BadTlsVersionsForServerCredentials) { + auto server_options = grpc_tls_credentials_options_create(); + server_options->set_max_tls_version(grpc_tls_version::TLS1_2); + server_options->set_min_tls_version(grpc_tls_version::TLS1_3); + auto server_credentials = grpc_tls_server_credentials_create(server_options); + EXPECT_EQ(server_credentials, nullptr); +} + // // Tests for Default Root Certs. // diff --git a/test/cpp/client/credentials_test.cc b/test/cpp/client/credentials_test.cc index a6b1645e891d5..edf78b44f12ad 100644 --- a/test/cpp/client/credentials_test.cc +++ b/test/cpp/client/credentials_test.cc @@ -500,6 +500,22 @@ TEST(CredentialsTest, MultipleChannelCredentialsOneCrlProviderDoesNotLeak) { EXPECT_NE(channel_creds_2, nullptr); } +TEST(CredentialsTest, TlsChannelCredentialsWithGoodMinAndMaxTlsVersions) { + grpc::experimental::TlsChannelCredentialsOptions options; + options.set_min_tls_version(grpc_tls_version::TLS1_2); + options.set_max_tls_version(grpc_tls_version::TLS1_3); + auto channel_credentials = grpc::experimental::TlsCredentials(options); + EXPECT_NE(channel_credentials, nullptr); +} + +TEST(CredentialsTest, TlsChannelCredentialsWithBadMinAndMaxTlsVersions) { + grpc::experimental::TlsChannelCredentialsOptions options; + options.set_min_tls_version(grpc_tls_version::TLS1_3); + options.set_max_tls_version(grpc_tls_version::TLS1_2); + auto channel_credentials = grpc::experimental::TlsCredentials(options); + EXPECT_EQ(channel_credentials, nullptr); +} + } // namespace } // namespace testing } // namespace grpc diff --git a/test/cpp/server/credentials_test.cc b/test/cpp/server/credentials_test.cc index 8c61d3ce37889..879c2c101dd3b 100644 --- a/test/cpp/server/credentials_test.cc +++ b/test/cpp/server/credentials_test.cc @@ -277,6 +277,24 @@ TEST(CredentialsTest, MultipleServerCredentialsOneCrlProviderDoesNotLeak) { EXPECT_NE(server_creds_2, nullptr); } +TEST(CredentialsTest, TlsServerCredentialsWithGoodMinMaxTlsVersions) { + grpc::experimental::TlsServerCredentialsOptions options( + /*certificate_provider=*/nullptr); + options.set_min_tls_version(grpc_tls_version::TLS1_2); + options.set_max_tls_version(grpc_tls_version::TLS1_3); + auto server_credentials = grpc::experimental::TlsServerCredentials(options); + EXPECT_NE(server_credentials, nullptr); +} + +TEST(CredentialsTest, TlsServerCredentialsWithBadMinMaxTlsVersions) { + grpc::experimental::TlsServerCredentialsOptions options( + /*certificate_provider=*/nullptr); + options.set_min_tls_version(grpc_tls_version::TLS1_3); + options.set_max_tls_version(grpc_tls_version::TLS1_2); + auto server_credentials = grpc::experimental::TlsServerCredentials(options); + EXPECT_EQ(server_credentials, nullptr); +} + } // namespace } // namespace testing } // namespace grpc From 2ffdca65e58d0dcbf76791b576425b684899bc6e Mon Sep 17 00:00:00 2001 From: John Cormie Date: Mon, 11 Dec 2023 10:37:25 -0800 Subject: [PATCH 072/127] binder: skip all tests on ios (#35226) They don't build due to -DNO_GRPC_BINDER. Closes #35226 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35226 from jdcormie:build-skip-ios 408b57bd6e92185072c2ca52a9486de7bd34649f PiperOrigin-RevId: 589870083 --- test/core/transport/binder/BUILD | 5 +++++ test/core/transport/binder/end2end/BUILD | 2 ++ 2 files changed, 7 insertions(+) diff --git a/test/core/transport/binder/BUILD b/test/core/transport/binder/BUILD index 2685b1dcf2b73..b332126ad7b95 100644 --- a/test/core/transport/binder/BUILD +++ b/test/core/transport/binder/BUILD @@ -44,6 +44,7 @@ grpc_cc_test( "gtest", ], language = "C++", + tags = ["no_test_ios"], uses_event_engine = False, uses_polling = False, deps = [ @@ -61,6 +62,7 @@ grpc_cc_test( "gtest", ], language = "C++", + tags = ["no_test_ios"], uses_event_engine = False, uses_polling = False, deps = [ @@ -78,6 +80,7 @@ grpc_cc_test( "gtest", ], language = "C++", + tags = ["no_test_ios"], uses_event_engine = False, uses_polling = False, deps = [ @@ -98,6 +101,7 @@ grpc_cc_test( tags = [ # To avoid `symbolizer buffer too small` warning of UBSAN "noubsan", + "no_test_ios", ], uses_event_engine = False, uses_polling = False, @@ -117,6 +121,7 @@ grpc_cc_test( "gtest", ], language = "C++", + tags = ["no_test_ios"], uses_event_engine = False, uses_polling = False, deps = [ diff --git a/test/core/transport/binder/end2end/BUILD b/test/core/transport/binder/end2end/BUILD index 8ae67d7a82225..30605e19fdfa4 100644 --- a/test/core/transport/binder/end2end/BUILD +++ b/test/core/transport/binder/end2end/BUILD @@ -49,6 +49,7 @@ grpc_cc_test( "gtest", ], language = "C++", + tags = ["no_test_ios"], uses_event_engine = False, uses_polling = False, deps = [ @@ -106,6 +107,7 @@ grpc_cc_test( external_deps = [ "gtest", ], + tags = ["no_test_ios"], deps = [ "//:grpc++", "//:grpc++_binder", From a5c71e132e232880978fdd5ea68fe9efae4cc9dd Mon Sep 17 00:00:00 2001 From: Gregory Cooke Date: Mon, 11 Dec 2023 11:22:53 -0800 Subject: [PATCH 073/127] [Security - TLS] DirectoryReloaderCrlProvider construction time bug fix (#35247) The `DirectoryReloaderProvider` currently segfaults on construction if grpc_init() is not called before construction. This is because when creating the `DirectoryReloaderCrlProvider` we [call GetDefaultEventEngine](https://github.com/grpc/grpc/blob/a58f3f2df531c3fae2afaef39d37186cf9206778/src/core/lib/security/credentials/tls/grpc_tls_crl_provider.cc#L152), and getting the default event engine requires that `grpc_init` is called. This PR adds a test that catches the segfault and adds `grpc_init` and `grpc_shutdown` to the ctor and dtor of `DirectoryReloaderCrlProvider` so that the test passes. Closes #35247 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35247 from gtcooke94:crl_provider_init_fix 25f3dc7f272cb1f16f4794ab3a6adaacb7294dbe PiperOrigin-RevId: 589885254 --- .../credentials/tls/grpc_tls_crl_provider.cc | 27 +++++++-- .../credentials/tls/grpc_tls_crl_provider.h | 6 +- test/cpp/end2end/crl_provider_test.cc | 58 ++++++++++++++++++- 3 files changed, 80 insertions(+), 11 deletions(-) diff --git a/src/core/lib/security/credentials/tls/grpc_tls_crl_provider.cc b/src/core/lib/security/credentials/tls/grpc_tls_crl_provider.cc index c3f525471970e..f9c0868f7c140 100644 --- a/src/core/lib/security/credentials/tls/grpc_tls_crl_provider.cc +++ b/src/core/lib/security/credentials/tls/grpc_tls_crl_provider.cc @@ -148,8 +148,7 @@ absl::StatusOr> CreateDirectoryReloaderCrlProvider( return absl::InvalidArgumentError("Refresh duration minimum is 60 seconds"); } auto provider = std::make_shared( - refresh_duration, reload_error_callback, - grpc_event_engine::experimental::GetDefaultEventEngine(), + refresh_duration, reload_error_callback, /*event_engine=*/nullptr, MakeDirectoryReader(directory)); // This could be slow to do at startup, but we want to // make sure it's done before the provider is used. @@ -157,10 +156,28 @@ absl::StatusOr> CreateDirectoryReloaderCrlProvider( return provider; } +DirectoryReloaderCrlProvider::DirectoryReloaderCrlProvider( + std::chrono::seconds duration, std::function callback, + std::shared_ptr event_engine, + std::shared_ptr directory_impl) + : refresh_duration_(Duration::FromSecondsAsDouble(duration.count())), + reload_error_callback_(std::move(callback)), + crl_directory_(std::move(directory_impl)) { + // Must be called before `GetDefaultEventEngine` + grpc_init(); + if (event_engine == nullptr) { + event_engine_ = grpc_event_engine::experimental::GetDefaultEventEngine(); + } else { + event_engine_ = std::move(event_engine); + } +} + DirectoryReloaderCrlProvider::~DirectoryReloaderCrlProvider() { if (refresh_handle_.has_value()) { event_engine_->Cancel(refresh_handle_.value()); } + // Call here because we call grpc_init in the constructor + grpc_shutdown(); } void DirectoryReloaderCrlProvider::UpdateAndStartTimer() { @@ -209,9 +226,9 @@ absl::Status DirectoryReloaderCrlProvider::Update() { // in-place updated in crls_. for (auto& kv : new_crls) { std::shared_ptr& crl = kv.second; - // It's not safe to say crl->Issuer() on the LHS and std::move(crl) on the - // RHS, because C++ does not guarantee which of those will be executed - // first. + // It's not safe to say crl->Issuer() on the LHS and std::move(crl) on + // the RHS, because C++ does not guarantee which of those will be + // executed first. std::string issuer(crl->Issuer()); crls_[std::move(issuer)] = std::move(crl); } diff --git a/src/core/lib/security/credentials/tls/grpc_tls_crl_provider.h b/src/core/lib/security/credentials/tls/grpc_tls_crl_provider.h index d1ea0c09661ee..6f946c3d9a4e7 100644 --- a/src/core/lib/security/credentials/tls/grpc_tls_crl_provider.h +++ b/src/core/lib/security/credentials/tls/grpc_tls_crl_provider.h @@ -98,11 +98,7 @@ class DirectoryReloaderCrlProvider std::chrono::seconds duration, std::function callback, std::shared_ptr event_engine, - std::shared_ptr directory_impl) - : refresh_duration_(Duration::FromSecondsAsDouble(duration.count())), - reload_error_callback_(std::move(callback)), - event_engine_(std::move(event_engine)), - crl_directory_(std::move(directory_impl)) {} + std::shared_ptr directory_impl); ~DirectoryReloaderCrlProvider() override; std::shared_ptr GetCrl(const CertificateInfo& certificate_info) override; diff --git a/test/cpp/end2end/crl_provider_test.cc b/test/cpp/end2end/crl_provider_test.cc index 52ec1687a7118..180da59eb0e83 100644 --- a/test/cpp/end2end/crl_provider_test.cc +++ b/test/cpp/end2end/crl_provider_test.cc @@ -59,8 +59,23 @@ const char* kRevokedCertPath = "test/core/tsi/test_creds/crl_data/revoked.pem"; const char* kValidKeyPath = "test/core/tsi/test_creds/crl_data/valid.key"; const char* kValidCertPath = "test/core/tsi/test_creds/crl_data/valid.pem"; const char* kRootCrlPath = "test/core/tsi/test_creds/crl_data/crls/current.crl"; +const char* kCrlDirectoryPath = "test/core/tsi/test_creds/crl_data/crls/"; constexpr char kMessage[] = "Hello"; +// This test must be at the top of the file because the +// DirectoryReloaderCrlProvider gets the default event engine on construction. +// To get the default event engine, grpc_init must have been called, otherwise a +// segfault occurs. This test checks that no segfault occurs while getting the +// default event engine during the construction of a +// DirectoryReloaderCrlProvider. `grpc_init` is global state, so if another test +// runs first, then this test could pass because of another test modifying the +// global state +TEST(DirectoryReloaderCrlProviderTestNoFixture, Construction) { + auto provider = grpc_core::experimental::CreateDirectoryReloaderCrlProvider( + kCrlDirectoryPath, std::chrono::seconds(60), nullptr); + ASSERT_TRUE(provider.ok()) << provider.status(); +} + class CrlProviderTest : public ::testing::Test { protected: void RunServer(absl::Notification* notification, absl::string_view server_key, @@ -137,7 +152,7 @@ void DoRpc(const std::string& server_addr, } } -TEST_F(CrlProviderTest, CrlProviderValid) { +TEST_F(CrlProviderTest, CrlProviderValidStaticProvider) { server_addr_ = absl::StrCat("localhost:", std::to_string(grpc_pick_unused_port_or_die())); absl::Notification notification; @@ -220,6 +235,47 @@ TEST_F(CrlProviderTest, CrlProviderRevokedServer) { DoRpc(server_addr_, options, false); } +TEST_F(CrlProviderTest, CrlProviderValidReloaderProvider) { + server_addr_ = absl::StrCat("localhost:", + std::to_string(grpc_pick_unused_port_or_die())); + absl::Notification notification; + std::string server_key = grpc_core::testing::GetFileContents(kValidKeyPath); + std::string server_cert = grpc_core::testing::GetFileContents(kValidCertPath); + server_thread_ = new std::thread( + [&]() { RunServer(¬ification, server_key, server_cert); }); + notification.WaitForNotification(); + + std::string root_cert = grpc_core::testing::GetFileContents(kRootPath); + std::string client_key = grpc_core::testing::GetFileContents(kValidKeyPath); + std::string client_cert = grpc_core::testing::GetFileContents(kValidCertPath); + experimental::IdentityKeyCertPair key_cert_pair; + key_cert_pair.private_key = client_key; + key_cert_pair.certificate_chain = client_cert; + std::vector identity_key_cert_pairs; + identity_key_cert_pairs.emplace_back(key_cert_pair); + auto certificate_provider = + std::make_shared( + root_cert, identity_key_cert_pairs); + grpc::experimental::TlsChannelCredentialsOptions options; + options.set_certificate_provider(certificate_provider); + options.watch_root_certs(); + options.set_root_cert_name("root"); + options.watch_identity_key_cert_pairs(); + options.set_identity_cert_name("identity"); + + absl::StatusOr> + provider = grpc_core::experimental::CreateDirectoryReloaderCrlProvider( + kCrlDirectoryPath, std::chrono::seconds(60), nullptr); + ASSERT_TRUE(provider.ok()); + + options.set_crl_provider(*provider); + options.set_check_call_host(false); + auto verifier = std::make_shared(); + options.set_certificate_verifier(verifier); + + DoRpc(server_addr_, options, true); +} + } // namespace } // namespace testing } // namespace grpc From 57dacad8c761a12de3e5eafa45f190015c73cccb Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 11 Dec 2023 12:42:47 -0800 Subject: [PATCH 074/127] [call-v3] Idle/max-age filters (#35270) Closes #35270 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35270 from ctiller:cg-idle 5312003ca67a3cc0841e6e2ff938161fd59bfda4 PiperOrigin-RevId: 589913523 --- CMakeLists.txt | 2 + Makefile | 2 + Package.swift | 2 + bazel/experiments.bzl | 1 + build_autogenerated.yaml | 4 + config.m4 | 1 + config.w32 | 1 + gRPC-C++.podspec | 2 + gRPC-Core.podspec | 3 + grpc.gemspec | 2 + grpc.gyp | 2 + package.xml | 2 + src/core/BUILD | 2 + .../channel_idle/channel_idle_filter.cc | 19 +- .../channel_idle/channel_idle_filter.h | 28 +- .../legacy_channel_idle_filter.cc | 326 ++++++++++++++++++ .../channel_idle/legacy_channel_idle_filter.h | 143 ++++++++ src/core/lib/experiments/experiments.cc | 15 + src/core/lib/experiments/experiments.h | 8 + src/core/lib/experiments/experiments.yaml | 6 + .../plugin_registry/grpc_plugin_registry.cc | 3 + src/python/grpcio/grpc_core_dependencies.py | 1 + tools/doxygen/Doxyfile.c++.internal | 2 + tools/doxygen/Doxyfile.core.internal | 2 + 24 files changed, 558 insertions(+), 21 deletions(-) create mode 100644 src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc create mode 100644 src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b9390ecccf282..9aea587d790c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1756,6 +1756,7 @@ add_library(grpc src/core/ext/filters/census/grpc_context.cc src/core/ext/filters/channel_idle/channel_idle_filter.cc src/core/ext/filters/channel_idle/idle_filter_state.cc + src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc src/core/ext/filters/client_channel/backend_metric.cc src/core/ext/filters/client_channel/backup_poller.cc src/core/ext/filters/client_channel/channel_connectivity.cc @@ -2820,6 +2821,7 @@ add_library(grpc_unsecure src/core/ext/filters/census/grpc_context.cc src/core/ext/filters/channel_idle/channel_idle_filter.cc src/core/ext/filters/channel_idle/idle_filter_state.cc + src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc src/core/ext/filters/client_channel/backend_metric.cc src/core/ext/filters/client_channel/backup_poller.cc src/core/ext/filters/client_channel/channel_connectivity.cc diff --git a/Makefile b/Makefile index 6df49a7bac0ff..372949e7b4754 100644 --- a/Makefile +++ b/Makefile @@ -958,6 +958,7 @@ LIBGRPC_SRC = \ src/core/ext/filters/census/grpc_context.cc \ src/core/ext/filters/channel_idle/channel_idle_filter.cc \ src/core/ext/filters/channel_idle/idle_filter_state.cc \ + src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc \ src/core/ext/filters/client_channel/backend_metric.cc \ src/core/ext/filters/client_channel/backup_poller.cc \ src/core/ext/filters/client_channel/channel_connectivity.cc \ @@ -1872,6 +1873,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/ext/filters/census/grpc_context.cc \ src/core/ext/filters/channel_idle/channel_idle_filter.cc \ src/core/ext/filters/channel_idle/idle_filter_state.cc \ + src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc \ src/core/ext/filters/client_channel/backend_metric.cc \ src/core/ext/filters/client_channel/backup_poller.cc \ src/core/ext/filters/client_channel/channel_connectivity.cc \ diff --git a/Package.swift b/Package.swift index 7c9d9ce10e9e2..a692977ac4e51 100644 --- a/Package.swift +++ b/Package.swift @@ -121,6 +121,8 @@ let package = Package( "src/core/ext/filters/channel_idle/channel_idle_filter.h", "src/core/ext/filters/channel_idle/idle_filter_state.cc", "src/core/ext/filters/channel_idle/idle_filter_state.h", + "src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc", + "src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h", "src/core/ext/filters/client_channel/backend_metric.cc", "src/core/ext/filters/client_channel/backend_metric.h", "src/core/ext/filters/client_channel/backup_poller.cc", diff --git a/bazel/experiments.bzl b/bazel/experiments.bzl index e5f402426956b..4bac512e43848 100644 --- a/bazel/experiments.bzl +++ b/bazel/experiments.bzl @@ -50,6 +50,7 @@ EXPERIMENT_ENABLES = { "tcp_rcv_lowat": "tcp_rcv_lowat", "trace_record_callops": "trace_record_callops", "unconstrained_max_quota_buffer_size": "unconstrained_max_quota_buffer_size", + "v3_channel_idle_filters": "v3_channel_idle_filters", "work_serializer_clears_time_cache": "work_serializer_clears_time_cache", "work_serializer_dispatch": "work_serializer_dispatch", "write_size_policy": "write_size_policy", diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index 09460f09a88fd..4789b3f5a46c1 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -218,6 +218,7 @@ libs: - src/core/ext/filters/backend_metrics/backend_metric_provider.h - src/core/ext/filters/channel_idle/channel_idle_filter.h - src/core/ext/filters/channel_idle/idle_filter_state.h + - src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h - src/core/ext/filters/client_channel/backend_metric.h - src/core/ext/filters/client_channel/backup_poller.h - src/core/ext/filters/client_channel/client_channel.h @@ -1209,6 +1210,7 @@ libs: - src/core/ext/filters/census/grpc_context.cc - src/core/ext/filters/channel_idle/channel_idle_filter.cc - src/core/ext/filters/channel_idle/idle_filter_state.cc + - src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc - src/core/ext/filters/client_channel/backend_metric.cc - src/core/ext/filters/client_channel/backup_poller.cc - src/core/ext/filters/client_channel/channel_connectivity.cc @@ -2154,6 +2156,7 @@ libs: - src/core/ext/filters/backend_metrics/backend_metric_provider.h - src/core/ext/filters/channel_idle/channel_idle_filter.h - src/core/ext/filters/channel_idle/idle_filter_state.h + - src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h - src/core/ext/filters/client_channel/backend_metric.h - src/core/ext/filters/client_channel/backup_poller.h - src/core/ext/filters/client_channel/client_channel.h @@ -2625,6 +2628,7 @@ libs: - src/core/ext/filters/census/grpc_context.cc - src/core/ext/filters/channel_idle/channel_idle_filter.cc - src/core/ext/filters/channel_idle/idle_filter_state.cc + - src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc - src/core/ext/filters/client_channel/backend_metric.cc - src/core/ext/filters/client_channel/backup_poller.cc - src/core/ext/filters/client_channel/channel_connectivity.cc diff --git a/config.m4 b/config.m4 index f4f52a0044c52..0b2e030045fee 100644 --- a/config.m4 +++ b/config.m4 @@ -45,6 +45,7 @@ if test "$PHP_GRPC" != "no"; then src/core/ext/filters/census/grpc_context.cc \ src/core/ext/filters/channel_idle/channel_idle_filter.cc \ src/core/ext/filters/channel_idle/idle_filter_state.cc \ + src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc \ src/core/ext/filters/client_channel/backend_metric.cc \ src/core/ext/filters/client_channel/backup_poller.cc \ src/core/ext/filters/client_channel/channel_connectivity.cc \ diff --git a/config.w32 b/config.w32 index 52ac38f12049a..1455ff6cc05c7 100644 --- a/config.w32 +++ b/config.w32 @@ -10,6 +10,7 @@ if (PHP_GRPC != "no") { "src\\core\\ext\\filters\\census\\grpc_context.cc " + "src\\core\\ext\\filters\\channel_idle\\channel_idle_filter.cc " + "src\\core\\ext\\filters\\channel_idle\\idle_filter_state.cc " + + "src\\core\\ext\\filters\\channel_idle\\legacy_channel_idle_filter.cc " + "src\\core\\ext\\filters\\client_channel\\backend_metric.cc " + "src\\core\\ext\\filters\\client_channel\\backup_poller.cc " + "src\\core\\ext\\filters\\client_channel\\channel_connectivity.cc " + diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index 14b9978f503b6..9364a57164e87 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -251,6 +251,7 @@ Pod::Spec.new do |s| 'src/core/ext/filters/backend_metrics/backend_metric_provider.h', 'src/core/ext/filters/channel_idle/channel_idle_filter.h', 'src/core/ext/filters/channel_idle/idle_filter_state.h', + 'src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h', 'src/core/ext/filters/client_channel/backend_metric.h', 'src/core/ext/filters/client_channel/backup_poller.h', 'src/core/ext/filters/client_channel/client_channel.h', @@ -1503,6 +1504,7 @@ Pod::Spec.new do |s| 'src/core/ext/filters/backend_metrics/backend_metric_provider.h', 'src/core/ext/filters/channel_idle/channel_idle_filter.h', 'src/core/ext/filters/channel_idle/idle_filter_state.h', + 'src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h', 'src/core/ext/filters/client_channel/backend_metric.h', 'src/core/ext/filters/client_channel/backup_poller.h', 'src/core/ext/filters/client_channel/client_channel.h', diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 303ac9ad5b295..0076a1b6311e5 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -224,6 +224,8 @@ Pod::Spec.new do |s| 'src/core/ext/filters/channel_idle/channel_idle_filter.h', 'src/core/ext/filters/channel_idle/idle_filter_state.cc', 'src/core/ext/filters/channel_idle/idle_filter_state.h', + 'src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc', + 'src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h', 'src/core/ext/filters/client_channel/backend_metric.cc', 'src/core/ext/filters/client_channel/backend_metric.h', 'src/core/ext/filters/client_channel/backup_poller.cc', @@ -2286,6 +2288,7 @@ Pod::Spec.new do |s| 'src/core/ext/filters/backend_metrics/backend_metric_provider.h', 'src/core/ext/filters/channel_idle/channel_idle_filter.h', 'src/core/ext/filters/channel_idle/idle_filter_state.h', + 'src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h', 'src/core/ext/filters/client_channel/backend_metric.h', 'src/core/ext/filters/client_channel/backup_poller.h', 'src/core/ext/filters/client_channel/client_channel.h', diff --git a/grpc.gemspec b/grpc.gemspec index 4b796f508bdcf..e5962295a73c3 100644 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -127,6 +127,8 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/filters/channel_idle/channel_idle_filter.h ) s.files += %w( src/core/ext/filters/channel_idle/idle_filter_state.cc ) s.files += %w( src/core/ext/filters/channel_idle/idle_filter_state.h ) + s.files += %w( src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc ) + s.files += %w( src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h ) s.files += %w( src/core/ext/filters/client_channel/backend_metric.cc ) s.files += %w( src/core/ext/filters/client_channel/backend_metric.h ) s.files += %w( src/core/ext/filters/client_channel/backup_poller.cc ) diff --git a/grpc.gyp b/grpc.gyp index 4b043c457b2a4..e68df91099f59 100644 --- a/grpc.gyp +++ b/grpc.gyp @@ -278,6 +278,7 @@ 'src/core/ext/filters/census/grpc_context.cc', 'src/core/ext/filters/channel_idle/channel_idle_filter.cc', 'src/core/ext/filters/channel_idle/idle_filter_state.cc', + 'src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc', 'src/core/ext/filters/client_channel/backend_metric.cc', 'src/core/ext/filters/client_channel/backup_poller.cc', 'src/core/ext/filters/client_channel/channel_connectivity.cc', @@ -1134,6 +1135,7 @@ 'src/core/ext/filters/census/grpc_context.cc', 'src/core/ext/filters/channel_idle/channel_idle_filter.cc', 'src/core/ext/filters/channel_idle/idle_filter_state.cc', + 'src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc', 'src/core/ext/filters/client_channel/backend_metric.cc', 'src/core/ext/filters/client_channel/backup_poller.cc', 'src/core/ext/filters/client_channel/channel_connectivity.cc', diff --git a/package.xml b/package.xml index e0e276e52c71c..3a2b2beb84ef3 100644 --- a/package.xml +++ b/package.xml @@ -109,6 +109,8 @@ + + diff --git a/src/core/BUILD b/src/core/BUILD index 36bad285ae59c..e5ad5240aea68 100644 --- a/src/core/BUILD +++ b/src/core/BUILD @@ -3892,9 +3892,11 @@ grpc_cc_library( name = "grpc_channel_idle_filter", srcs = [ "ext/filters/channel_idle/channel_idle_filter.cc", + "ext/filters/channel_idle/legacy_channel_idle_filter.cc", ], hdrs = [ "ext/filters/channel_idle/channel_idle_filter.h", + "ext/filters/channel_idle/legacy_channel_idle_filter.h", ], external_deps = [ "absl/base:core_headers", diff --git a/src/core/ext/filters/channel_idle/channel_idle_filter.cc b/src/core/ext/filters/channel_idle/channel_idle_filter.cc index 40bedf4d5958a..cd88ca58b3dfc 100644 --- a/src/core/ext/filters/channel_idle/channel_idle_filter.cc +++ b/src/core/ext/filters/channel_idle/channel_idle_filter.cc @@ -56,6 +56,13 @@ namespace grpc_core { +const NoInterceptor ChannelIdleFilter::Call::OnClientInitialMetadata; +const NoInterceptor ChannelIdleFilter::Call::OnServerInitialMetadata; +const NoInterceptor ChannelIdleFilter::Call::OnServerTrailingMetadata; +const NoInterceptor ChannelIdleFilter::Call::OnClientToServerMessage; +const NoInterceptor ChannelIdleFilter::Call::OnServerToClientMessage; +const NoInterceptor ChannelIdleFilter::Call::OnFinalize; + namespace { // TODO(roth): This can go back to being a constant when the experiment @@ -221,17 +228,6 @@ void MaxAgeFilter::PostInit() { } } -// Construct a promise for one call. -ArenaPromise ChannelIdleFilter::MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) { - using Decrementer = std::unique_ptr; - IncreaseCallCount(); - return ArenaPromise( - [decrementer = Decrementer(this), - next = next_promise_factory(std::move(call_args))]() mutable - -> Poll { return next(); }); -} - bool ChannelIdleFilter::StartTransportOp(grpc_transport_op* op) { // Catch the disconnect_with_error transport op. if (!op->disconnect_with_error.ok()) Shutdown(); @@ -298,6 +294,7 @@ const grpc_channel_filter MaxAgeFilter::kFilter = MakePromiseBasedFilter("max_age"); void RegisterChannelIdleFilters(CoreConfiguration::Builder* builder) { + if (!IsV3ChannelIdleFiltersEnabled()) return; builder->channel_init() ->RegisterFilter(GRPC_CLIENT_CHANNEL, &ClientIdleFilter::kFilter) .ExcludeFromMinimalStack() diff --git a/src/core/ext/filters/channel_idle/channel_idle_filter.h b/src/core/ext/filters/channel_idle/channel_idle_filter.h index 1a2803881bec0..67caadfd5a775 100644 --- a/src/core/ext/filters/channel_idle/channel_idle_filter.h +++ b/src/core/ext/filters/channel_idle/channel_idle_filter.h @@ -40,7 +40,7 @@ namespace grpc_core { -class ChannelIdleFilter : public ChannelFilter { +class ChannelIdleFilter : public ImplementChannelFilter { public: ~ChannelIdleFilter() override = default; @@ -49,9 +49,23 @@ class ChannelIdleFilter : public ChannelFilter { ChannelIdleFilter(ChannelIdleFilter&&) = default; ChannelIdleFilter& operator=(ChannelIdleFilter&&) = default; - // Construct a promise for one call. - ArenaPromise MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) override; + class Call { + public: + explicit Call(ChannelIdleFilter* filter) : filter_(filter) { + filter_->IncreaseCallCount(); + } + ~Call() { filter_->DecreaseCallCount(); } + + static const NoInterceptor OnClientInitialMetadata; + static const NoInterceptor OnServerInitialMetadata; + static const NoInterceptor OnServerTrailingMetadata; + static const NoInterceptor OnClientToServerMessage; + static const NoInterceptor OnServerToClientMessage; + static const NoInterceptor OnFinalize; + + private: + ChannelIdleFilter* filter_; + }; bool StartTransportOp(grpc_transport_op* op) override; @@ -75,12 +89,6 @@ class ChannelIdleFilter : public ChannelFilter { private: void StartIdleTimer(); - struct CallCountDecreaser { - void operator()(ChannelIdleFilter* filter) const { - filter->DecreaseCallCount(); - } - }; - // The channel stack to which we take refs for pending callbacks. grpc_channel_stack* channel_stack_; Duration client_idle_timeout_; diff --git a/src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc b/src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc new file mode 100644 index 0000000000000..23d97c9e2ffdb --- /dev/null +++ b/src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc @@ -0,0 +1,326 @@ +// Copyright 2022 gRPC authors. +// +// Licensed 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. + +// TODO(ctiller): Add a unit test suite for these filters once it's practical to +// mock transport operations. + +#include + +#include "src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h" + +#include +#include + +#include "absl/base/thread_annotations.h" +#include "absl/meta/type_traits.h" +#include "absl/random/random.h" +#include "absl/types/optional.h" + +#include +#include + +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/channel/promise_based_filter.h" +#include "src/core/lib/config/core_configuration.h" +#include "src/core/lib/debug/trace.h" +#include "src/core/lib/experiments/experiments.h" +#include "src/core/lib/gprpp/debug_location.h" +#include "src/core/lib/gprpp/no_destruct.h" +#include "src/core/lib/gprpp/orphanable.h" +#include "src/core/lib/gprpp/per_cpu.h" +#include "src/core/lib/gprpp/status_helper.h" +#include "src/core/lib/gprpp/sync.h" +#include "src/core/lib/iomgr/closure.h" +#include "src/core/lib/iomgr/error.h" +#include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/promise/exec_ctx_wakeup_scheduler.h" +#include "src/core/lib/promise/loop.h" +#include "src/core/lib/promise/poll.h" +#include "src/core/lib/promise/promise.h" +#include "src/core/lib/promise/sleep.h" +#include "src/core/lib/promise/try_seq.h" +#include "src/core/lib/surface/channel_stack_type.h" +#include "src/core/lib/transport/http2_errors.h" +#include "src/core/lib/transport/metadata_batch.h" + +namespace grpc_core { + +namespace { + +// TODO(roth): This can go back to being a constant when the experiment +// is removed. +Duration DefaultIdleTimeout() { + if (IsClientIdlenessEnabled()) return Duration::Minutes(30); + return Duration::Infinity(); +} + +// If these settings change, make sure that we are not sending a GOAWAY for +// inproc transport, since a GOAWAY to inproc ends up destroying the transport. +const auto kDefaultMaxConnectionAge = Duration::Infinity(); +const auto kDefaultMaxConnectionAgeGrace = Duration::Infinity(); +const auto kDefaultMaxConnectionIdle = Duration::Infinity(); +const auto kMaxConnectionAgeJitter = 0.1; + +TraceFlag grpc_trace_client_idle_filter(false, "client_idle_filter"); +} // namespace + +#define GRPC_IDLE_FILTER_LOG(format, ...) \ + do { \ + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_client_idle_filter)) { \ + gpr_log(GPR_INFO, "(client idle filter) " format, ##__VA_ARGS__); \ + } \ + } while (0) + +namespace { + +Duration GetClientIdleTimeout(const ChannelArgs& args) { + return args.GetDurationFromIntMillis(GRPC_ARG_CLIENT_IDLE_TIMEOUT_MS) + .value_or(DefaultIdleTimeout()); +} + +} // namespace + +struct LegacyMaxAgeFilter::Config { + Duration max_connection_age; + Duration max_connection_idle; + Duration max_connection_age_grace; + + bool enable() const { + return max_connection_age != Duration::Infinity() || + max_connection_idle != Duration::Infinity(); + } + + // A random jitter of +/-10% will be added to MAX_CONNECTION_AGE and + // MAX_CONNECTION_IDLE to spread out reconnection storms. + static Config FromChannelArgs(const ChannelArgs& args) { + const Duration args_max_age = + args.GetDurationFromIntMillis(GRPC_ARG_MAX_CONNECTION_AGE_MS) + .value_or(kDefaultMaxConnectionAge); + const Duration args_max_idle = + args.GetDurationFromIntMillis(GRPC_ARG_MAX_CONNECTION_IDLE_MS) + .value_or(kDefaultMaxConnectionIdle); + const Duration args_max_age_grace = + args.GetDurationFromIntMillis(GRPC_ARG_MAX_CONNECTION_AGE_GRACE_MS) + .value_or(kDefaultMaxConnectionAgeGrace); + // generate a random number between 1 - kMaxConnectionAgeJitter and + // 1 + kMaxConnectionAgeJitter + struct BitGen { + Mutex mu; + absl::BitGen bit_gen ABSL_GUARDED_BY(mu); + double MakeUniformDouble(double min, double max) { + MutexLock lock(&mu); + return absl::Uniform(bit_gen, min, max); + } + }; + static NoDestruct> bit_gen(PerCpuOptions().SetMaxShards(8)); + const double multiplier = bit_gen->this_cpu().MakeUniformDouble( + 1.0 - kMaxConnectionAgeJitter, 1.0 + kMaxConnectionAgeJitter); + // GRPC_MILLIS_INF_FUTURE - 0.5 converts the value to float, so that result + // will not be cast to int implicitly before the comparison. + return Config{args_max_age * multiplier, args_max_idle * multiplier, + args_max_age_grace}; + } +}; + +absl::StatusOr LegacyClientIdleFilter::Create( + const ChannelArgs& args, ChannelFilter::Args filter_args) { + LegacyClientIdleFilter filter(filter_args.channel_stack(), + GetClientIdleTimeout(args)); + return absl::StatusOr(std::move(filter)); +} + +absl::StatusOr LegacyMaxAgeFilter::Create( + const ChannelArgs& args, ChannelFilter::Args filter_args) { + LegacyMaxAgeFilter filter(filter_args.channel_stack(), + Config::FromChannelArgs(args)); + return absl::StatusOr(std::move(filter)); +} + +void LegacyMaxAgeFilter::Shutdown() { + max_age_activity_.Reset(); + LegacyChannelIdleFilter::Shutdown(); +} + +void LegacyMaxAgeFilter::PostInit() { + struct StartupClosure { + RefCountedPtr channel_stack; + LegacyMaxAgeFilter* filter; + grpc_closure closure; + }; + auto run_startup = [](void* p, grpc_error_handle) { + auto* startup = static_cast(p); + // Trigger idle timer + startup->filter->IncreaseCallCount(); + startup->filter->DecreaseCallCount(); + grpc_transport_op* op = grpc_make_transport_op(nullptr); + op->start_connectivity_watch.reset( + new ConnectivityWatcher(startup->filter)); + op->start_connectivity_watch_state = GRPC_CHANNEL_IDLE; + grpc_channel_next_op( + grpc_channel_stack_element(startup->channel_stack.get(), 0), op); + delete startup; + }; + auto* startup = + new StartupClosure{this->channel_stack()->Ref(), this, grpc_closure{}}; + GRPC_CLOSURE_INIT(&startup->closure, run_startup, startup, nullptr); + ExecCtx::Run(DEBUG_LOCATION, &startup->closure, absl::OkStatus()); + + auto channel_stack = this->channel_stack()->Ref(); + + // Start the max age timer + if (max_connection_age_ != Duration::Infinity()) { + max_age_activity_.Set(MakeActivity( + TrySeq( + // First sleep until the max connection age + Sleep(Timestamp::Now() + max_connection_age_), + // Then send a goaway. + [this] { + GRPC_CHANNEL_STACK_REF(this->channel_stack(), + "max_age send_goaway"); + // Jump out of the activity to send the goaway. + auto fn = [](void* arg, grpc_error_handle) { + auto* channel_stack = static_cast(arg); + grpc_transport_op* op = grpc_make_transport_op(nullptr); + op->goaway_error = grpc_error_set_int( + GRPC_ERROR_CREATE("max_age"), + StatusIntProperty::kHttp2Error, GRPC_HTTP2_NO_ERROR); + grpc_channel_element* elem = + grpc_channel_stack_element(channel_stack, 0); + elem->filter->start_transport_op(elem, op); + GRPC_CHANNEL_STACK_UNREF(channel_stack, "max_age send_goaway"); + }; + ExecCtx::Run( + DEBUG_LOCATION, + GRPC_CLOSURE_CREATE(fn, this->channel_stack(), nullptr), + absl::OkStatus()); + return Immediate(absl::OkStatus()); + }, + // Sleep for the grace period + [this] { + return Sleep(Timestamp::Now() + max_connection_age_grace_); + }), + ExecCtxWakeupScheduler(), + [channel_stack, this](absl::Status status) { + // OnDone -- close the connection if the promise completed + // successfully. + // (if it did not, it was cancelled) + if (status.ok()) CloseChannel(); + }, + channel_stack->EventEngine())); + } +} + +// Construct a promise for one call. +ArenaPromise LegacyChannelIdleFilter::MakeCallPromise( + CallArgs call_args, NextPromiseFactory next_promise_factory) { + using Decrementer = + std::unique_ptr; + IncreaseCallCount(); + return ArenaPromise( + [decrementer = Decrementer(this), + next = next_promise_factory(std::move(call_args))]() mutable + -> Poll { return next(); }); +} + +bool LegacyChannelIdleFilter::StartTransportOp(grpc_transport_op* op) { + // Catch the disconnect_with_error transport op. + if (!op->disconnect_with_error.ok()) Shutdown(); + // Pass the op to the next filter. + return false; +} + +void LegacyChannelIdleFilter::Shutdown() { + // IncreaseCallCount() introduces a phony call and prevent the timer from + // being reset by other threads. + IncreaseCallCount(); + activity_.Reset(); +} + +void LegacyChannelIdleFilter::IncreaseCallCount() { + idle_filter_state_->IncreaseCallCount(); +} + +void LegacyChannelIdleFilter::DecreaseCallCount() { + if (idle_filter_state_->DecreaseCallCount()) { + // If there are no more calls in progress, start the idle timer. + StartIdleTimer(); + } +} + +void LegacyChannelIdleFilter::StartIdleTimer() { + GRPC_IDLE_FILTER_LOG("timer has started"); + auto idle_filter_state = idle_filter_state_; + // Hold a ref to the channel stack for the timer callback. + auto channel_stack = channel_stack_->Ref(); + auto timeout = client_idle_timeout_; + auto promise = Loop([timeout, idle_filter_state]() { + return TrySeq(Sleep(Timestamp::Now() + timeout), + [idle_filter_state]() -> Poll> { + if (idle_filter_state->CheckTimer()) { + return Continue{}; + } else { + return absl::OkStatus(); + } + }); + }); + activity_.Set(MakeActivity( + std::move(promise), ExecCtxWakeupScheduler{}, + [channel_stack, this](absl::Status status) { + if (status.ok()) CloseChannel(); + }, + channel_stack->EventEngine())); +} + +void LegacyChannelIdleFilter::CloseChannel() { + auto* op = grpc_make_transport_op(nullptr); + op->disconnect_with_error = grpc_error_set_int( + GRPC_ERROR_CREATE("enter idle"), + StatusIntProperty::ChannelConnectivityState, GRPC_CHANNEL_IDLE); + // Pass the transport op down to the channel stack. + auto* elem = grpc_channel_stack_element(channel_stack_, 0); + elem->filter->start_transport_op(elem, op); +} + +const grpc_channel_filter LegacyClientIdleFilter::kFilter = + MakePromiseBasedFilter( + "client_idle"); +const grpc_channel_filter LegacyMaxAgeFilter::kFilter = + MakePromiseBasedFilter( + "max_age"); + +void RegisterLegacyChannelIdleFilters(CoreConfiguration::Builder* builder) { + if (IsV3ChannelIdleFiltersEnabled()) return; + builder->channel_init() + ->RegisterFilter(GRPC_CLIENT_CHANNEL, &LegacyClientIdleFilter::kFilter) + .ExcludeFromMinimalStack() + .If([](const ChannelArgs& channel_args) { + return GetClientIdleTimeout(channel_args) != Duration::Infinity(); + }); + builder->channel_init() + ->RegisterFilter(GRPC_SERVER_CHANNEL, &LegacyMaxAgeFilter::kFilter) + .ExcludeFromMinimalStack() + .If([](const ChannelArgs& channel_args) { + return LegacyMaxAgeFilter::Config::FromChannelArgs(channel_args) + .enable(); + }); +} + +LegacyMaxAgeFilter::LegacyMaxAgeFilter(grpc_channel_stack* channel_stack, + const Config& max_age_config) + : LegacyChannelIdleFilter(channel_stack, + max_age_config.max_connection_idle), + max_connection_age_(max_age_config.max_connection_age), + max_connection_age_grace_(max_age_config.max_connection_age_grace) {} + +} // namespace grpc_core diff --git a/src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h b/src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h new file mode 100644 index 0000000000000..8e06505d7321b --- /dev/null +++ b/src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h @@ -0,0 +1,143 @@ +// Copyright 2022 gRPC authors. +// +// Licensed 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 GRPC_SRC_CORE_EXT_FILTERS_CHANNEL_IDLE_LEGACY_CHANNEL_IDLE_FILTER_H +#define GRPC_SRC_CORE_EXT_FILTERS_CHANNEL_IDLE_LEGACY_CHANNEL_IDLE_FILTER_H + +#include + +#include + +#include "absl/status/status.h" +#include "absl/status/statusor.h" + +#include + +#include "src/core/ext/filters/channel_idle/idle_filter_state.h" +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/channel/channel_fwd.h" +#include "src/core/lib/channel/channel_stack.h" +#include "src/core/lib/channel/promise_based_filter.h" +#include "src/core/lib/gprpp/orphanable.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" +#include "src/core/lib/gprpp/single_set_ptr.h" +#include "src/core/lib/gprpp/time.h" +#include "src/core/lib/promise/activity.h" +#include "src/core/lib/promise/arena_promise.h" +#include "src/core/lib/transport/connectivity_state.h" +#include "src/core/lib/transport/transport.h" + +namespace grpc_core { + +class LegacyChannelIdleFilter : public ChannelFilter { + public: + ~LegacyChannelIdleFilter() override = default; + + LegacyChannelIdleFilter(const LegacyChannelIdleFilter&) = delete; + LegacyChannelIdleFilter& operator=(const LegacyChannelIdleFilter&) = delete; + LegacyChannelIdleFilter(LegacyChannelIdleFilter&&) = default; + LegacyChannelIdleFilter& operator=(LegacyChannelIdleFilter&&) = default; + + // Construct a promise for one call. + ArenaPromise MakeCallPromise( + CallArgs call_args, NextPromiseFactory next_promise_factory) override; + + bool StartTransportOp(grpc_transport_op* op) override; + + protected: + using SingleSetActivityPtr = + SingleSetPtr; + + LegacyChannelIdleFilter(grpc_channel_stack* channel_stack, + Duration client_idle_timeout) + : channel_stack_(channel_stack), + client_idle_timeout_(client_idle_timeout) {} + + grpc_channel_stack* channel_stack() { return channel_stack_; }; + + virtual void Shutdown(); + void CloseChannel(); + + void IncreaseCallCount(); + void DecreaseCallCount(); + + private: + void StartIdleTimer(); + + struct CallCountDecreaser { + void operator()(LegacyChannelIdleFilter* filter) const { + filter->DecreaseCallCount(); + } + }; + + // The channel stack to which we take refs for pending callbacks. + grpc_channel_stack* channel_stack_; + Duration client_idle_timeout_; + std::shared_ptr idle_filter_state_{ + std::make_shared(false)}; + + SingleSetActivityPtr activity_; +}; + +class LegacyClientIdleFilter final : public LegacyChannelIdleFilter { + public: + static const grpc_channel_filter kFilter; + + static absl::StatusOr Create( + const ChannelArgs& args, ChannelFilter::Args filter_args); + + private: + using LegacyChannelIdleFilter::LegacyChannelIdleFilter; +}; + +class LegacyMaxAgeFilter final : public LegacyChannelIdleFilter { + public: + static const grpc_channel_filter kFilter; + struct Config; + + static absl::StatusOr Create( + const ChannelArgs& args, ChannelFilter::Args filter_args); + + void PostInit() override; + + private: + class ConnectivityWatcher : public AsyncConnectivityStateWatcherInterface { + public: + explicit ConnectivityWatcher(LegacyMaxAgeFilter* filter) + : channel_stack_(filter->channel_stack()->Ref()), filter_(filter) {} + ~ConnectivityWatcher() override = default; + + void OnConnectivityStateChange(grpc_connectivity_state new_state, + const absl::Status&) override { + if (new_state == GRPC_CHANNEL_SHUTDOWN) filter_->Shutdown(); + } + + private: + RefCountedPtr channel_stack_; + LegacyMaxAgeFilter* filter_; + }; + + LegacyMaxAgeFilter(grpc_channel_stack* channel_stack, + const Config& max_age_config); + + void Shutdown() override; + + SingleSetActivityPtr max_age_activity_; + Duration max_connection_age_; + Duration max_connection_age_grace_; +}; + +} // namespace grpc_core + +#endif // GRPC_SRC_CORE_EXT_FILTERS_CHANNEL_IDLE_LEGACY_CHANNEL_IDLE_FILTER_H diff --git a/src/core/lib/experiments/experiments.cc b/src/core/lib/experiments/experiments.cc index d44fdac9f7216..0639dd281552d 100644 --- a/src/core/lib/experiments/experiments.cc +++ b/src/core/lib/experiments/experiments.cc @@ -147,6 +147,9 @@ const char* const description_unconstrained_max_quota_buffer_size = "Discard the cap on the max free pool size for one memory allocator"; const char* const additional_constraints_unconstrained_max_quota_buffer_size = "{}"; +const char* const description_v3_channel_idle_filters = + "Use the v3 filter API version of the idle filters."; +const char* const additional_constraints_v3_channel_idle_filters = "{}"; const char* const description_work_serializer_clears_time_cache = "Have the work serializer clear the time cache when it dispatches work."; const char* const additional_constraints_work_serializer_clears_time_cache = @@ -259,6 +262,8 @@ const ExperimentMetadata g_experiment_metadata[] = { description_unconstrained_max_quota_buffer_size, additional_constraints_unconstrained_max_quota_buffer_size, nullptr, 0, false, true}, + {"v3_channel_idle_filters", description_v3_channel_idle_filters, + additional_constraints_v3_channel_idle_filters, nullptr, 0, false, true}, {"work_serializer_clears_time_cache", description_work_serializer_clears_time_cache, additional_constraints_work_serializer_clears_time_cache, nullptr, 0, true, @@ -401,6 +406,9 @@ const char* const description_unconstrained_max_quota_buffer_size = "Discard the cap on the max free pool size for one memory allocator"; const char* const additional_constraints_unconstrained_max_quota_buffer_size = "{}"; +const char* const description_v3_channel_idle_filters = + "Use the v3 filter API version of the idle filters."; +const char* const additional_constraints_v3_channel_idle_filters = "{}"; const char* const description_work_serializer_clears_time_cache = "Have the work serializer clear the time cache when it dispatches work."; const char* const additional_constraints_work_serializer_clears_time_cache = @@ -513,6 +521,8 @@ const ExperimentMetadata g_experiment_metadata[] = { description_unconstrained_max_quota_buffer_size, additional_constraints_unconstrained_max_quota_buffer_size, nullptr, 0, false, true}, + {"v3_channel_idle_filters", description_v3_channel_idle_filters, + additional_constraints_v3_channel_idle_filters, nullptr, 0, false, true}, {"work_serializer_clears_time_cache", description_work_serializer_clears_time_cache, additional_constraints_work_serializer_clears_time_cache, nullptr, 0, true, @@ -655,6 +665,9 @@ const char* const description_unconstrained_max_quota_buffer_size = "Discard the cap on the max free pool size for one memory allocator"; const char* const additional_constraints_unconstrained_max_quota_buffer_size = "{}"; +const char* const description_v3_channel_idle_filters = + "Use the v3 filter API version of the idle filters."; +const char* const additional_constraints_v3_channel_idle_filters = "{}"; const char* const description_work_serializer_clears_time_cache = "Have the work serializer clear the time cache when it dispatches work."; const char* const additional_constraints_work_serializer_clears_time_cache = @@ -767,6 +780,8 @@ const ExperimentMetadata g_experiment_metadata[] = { description_unconstrained_max_quota_buffer_size, additional_constraints_unconstrained_max_quota_buffer_size, nullptr, 0, false, true}, + {"v3_channel_idle_filters", description_v3_channel_idle_filters, + additional_constraints_v3_channel_idle_filters, nullptr, 0, false, true}, {"work_serializer_clears_time_cache", description_work_serializer_clears_time_cache, additional_constraints_work_serializer_clears_time_cache, nullptr, 0, true, diff --git a/src/core/lib/experiments/experiments.h b/src/core/lib/experiments/experiments.h index 1b023557b33d0..bf17ee2ce3bf4 100644 --- a/src/core/lib/experiments/experiments.h +++ b/src/core/lib/experiments/experiments.h @@ -107,6 +107,7 @@ inline bool IsTcpFrameSizeTuningEnabled() { return false; } inline bool IsTcpRcvLowatEnabled() { return false; } inline bool IsTraceRecordCallopsEnabled() { return false; } inline bool IsUnconstrainedMaxQuotaBufferSizeEnabled() { return false; } +inline bool IsV3ChannelIdleFiltersEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_WORK_SERIALIZER_CLEARS_TIME_CACHE inline bool IsWorkSerializerClearsTimeCacheEnabled() { return true; } inline bool IsWorkSerializerDispatchEnabled() { return false; } @@ -169,6 +170,7 @@ inline bool IsTcpFrameSizeTuningEnabled() { return false; } inline bool IsTcpRcvLowatEnabled() { return false; } inline bool IsTraceRecordCallopsEnabled() { return false; } inline bool IsUnconstrainedMaxQuotaBufferSizeEnabled() { return false; } +inline bool IsV3ChannelIdleFiltersEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_WORK_SERIALIZER_CLEARS_TIME_CACHE inline bool IsWorkSerializerClearsTimeCacheEnabled() { return true; } inline bool IsWorkSerializerDispatchEnabled() { return false; } @@ -231,6 +233,7 @@ inline bool IsTcpFrameSizeTuningEnabled() { return false; } inline bool IsTcpRcvLowatEnabled() { return false; } inline bool IsTraceRecordCallopsEnabled() { return false; } inline bool IsUnconstrainedMaxQuotaBufferSizeEnabled() { return false; } +inline bool IsV3ChannelIdleFiltersEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_WORK_SERIALIZER_CLEARS_TIME_CACHE inline bool IsWorkSerializerClearsTimeCacheEnabled() { return true; } inline bool IsWorkSerializerDispatchEnabled() { return false; } @@ -277,6 +280,7 @@ enum ExperimentIds { kExperimentIdTcpRcvLowat, kExperimentIdTraceRecordCallops, kExperimentIdUnconstrainedMaxQuotaBufferSize, + kExperimentIdV3ChannelIdleFilters, kExperimentIdWorkSerializerClearsTimeCache, kExperimentIdWorkSerializerDispatch, kExperimentIdWriteSizePolicy, @@ -416,6 +420,10 @@ inline bool IsTraceRecordCallopsEnabled() { inline bool IsUnconstrainedMaxQuotaBufferSizeEnabled() { return IsExperimentEnabled(kExperimentIdUnconstrainedMaxQuotaBufferSize); } +#define GRPC_EXPERIMENT_IS_INCLUDED_V3_CHANNEL_IDLE_FILTERS +inline bool IsV3ChannelIdleFiltersEnabled() { + return IsExperimentEnabled(kExperimentIdV3ChannelIdleFilters); +} #define GRPC_EXPERIMENT_IS_INCLUDED_WORK_SERIALIZER_CLEARS_TIME_CACHE inline bool IsWorkSerializerClearsTimeCacheEnabled() { return IsExperimentEnabled(kExperimentIdWorkSerializerClearsTimeCache); diff --git a/src/core/lib/experiments/experiments.yaml b/src/core/lib/experiments/experiments.yaml index e3b89572e4388..54b3ea6ff1536 100644 --- a/src/core/lib/experiments/experiments.yaml +++ b/src/core/lib/experiments/experiments.yaml @@ -252,6 +252,12 @@ expiry: 2024/02/01 owner: ctiller@google.com test_tags: [resource_quota_test] +- name: v3_channel_idle_filters + description: + Use the v3 filter API version of the idle filters. + expiry: 2024/04/04 + owner: ctiller@google.com + test_tags: [] - name: work_serializer_clears_time_cache description: Have the work serializer clear the time cache when it dispatches work. diff --git a/src/core/plugin_registry/grpc_plugin_registry.cc b/src/core/plugin_registry/grpc_plugin_registry.cc index 33ca141b0e23b..0401a799ba515 100644 --- a/src/core/plugin_registry/grpc_plugin_registry.cc +++ b/src/core/plugin_registry/grpc_plugin_registry.cc @@ -40,6 +40,8 @@ extern void SecurityRegisterHandshakerFactories( CoreConfiguration::Builder* builder); extern void RegisterClientAuthorityFilter(CoreConfiguration::Builder* builder); extern void RegisterChannelIdleFilters(CoreConfiguration::Builder* builder); +extern void RegisterLegacyChannelIdleFilters( + CoreConfiguration::Builder* builder); extern void RegisterDeadlineFilter(CoreConfiguration::Builder* builder); extern void RegisterGrpcLbPolicy(CoreConfiguration::Builder* builder); extern void RegisterHttpFilters(CoreConfiguration::Builder* builder); @@ -89,6 +91,7 @@ void BuildCoreConfiguration(CoreConfiguration::Builder* builder) { SecurityRegisterHandshakerFactories(builder); RegisterClientAuthorityFilter(builder); RegisterChannelIdleFilters(builder); + RegisterLegacyChannelIdleFilters(builder); RegisterConnectedChannel(builder); RegisterGrpcLbPolicy(builder); RegisterHttpFilters(builder); diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index d6304bccbdca8..c0439924822f1 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -19,6 +19,7 @@ 'src/core/ext/filters/census/grpc_context.cc', 'src/core/ext/filters/channel_idle/channel_idle_filter.cc', 'src/core/ext/filters/channel_idle/idle_filter_state.cc', + 'src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc', 'src/core/ext/filters/client_channel/backend_metric.cc', 'src/core/ext/filters/client_channel/backup_poller.cc', 'src/core/ext/filters/client_channel/channel_connectivity.cc', diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 21666ae9e51b2..b465d10a27151 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -1087,6 +1087,8 @@ src/core/ext/filters/channel_idle/channel_idle_filter.cc \ src/core/ext/filters/channel_idle/channel_idle_filter.h \ src/core/ext/filters/channel_idle/idle_filter_state.cc \ src/core/ext/filters/channel_idle/idle_filter_state.h \ +src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc \ +src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h \ src/core/ext/filters/client_channel/backend_metric.cc \ src/core/ext/filters/client_channel/backend_metric.h \ src/core/ext/filters/client_channel/backup_poller.cc \ diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index b7b1ae5bf255a..7a3ea87d2ac6a 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -891,6 +891,8 @@ src/core/ext/filters/channel_idle/channel_idle_filter.cc \ src/core/ext/filters/channel_idle/channel_idle_filter.h \ src/core/ext/filters/channel_idle/idle_filter_state.cc \ src/core/ext/filters/channel_idle/idle_filter_state.h \ +src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc \ +src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h \ src/core/ext/filters/client_channel/README.md \ src/core/ext/filters/client_channel/backend_metric.cc \ src/core/ext/filters/client_channel/backend_metric.h \ From 2b1d06f03738363e558525f42770c55481050043 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 11 Dec 2023 13:01:43 -0800 Subject: [PATCH 075/127] [fuzzing] Add ability to listen to ports to api-fuzzer (#35273) Unsure when this got dropped! Closes #35273 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35273 from ctiller:server-port be94e30a06764bdd421bd710ae643e6c0de2e231 PiperOrigin-RevId: 589919718 --- test/core/end2end/fuzzers/api_fuzzer.cc | 18 ++++++++++++++++++ test/core/end2end/fuzzers/api_fuzzer.proto | 13 +++++++++++++ 2 files changed, 31 insertions(+) diff --git a/test/core/end2end/fuzzers/api_fuzzer.cc b/test/core/end2end/fuzzers/api_fuzzer.cc index d4c6279e65119..f2e0bba373b99 100644 --- a/test/core/end2end/fuzzers/api_fuzzer.cc +++ b/test/core/end2end/fuzzers/api_fuzzer.cc @@ -369,6 +369,18 @@ static grpc_channel_credentials* ReadChannelCreds( } } +static grpc_server_credentials* ReadServerCreds( + const api_fuzzer::ServerCreds& creds) { + switch (creds.type_case()) { + case api_fuzzer::ServerCreds::TYPE_NOT_SET: + return nullptr; + case api_fuzzer::ServerCreds::kInsecureCreds: + return grpc_insecure_server_credentials_create(); + case api_fuzzer::ServerCreds::kNull: + return nullptr; + } +} + namespace grpc_core { namespace testing { @@ -428,6 +440,12 @@ ApiFuzzer::Result ApiFuzzer::CreateServer( server_ = grpc_server_create(args.ToC().get(), nullptr); GPR_ASSERT(server_ != nullptr); grpc_server_register_completion_queue(server_, cq(), nullptr); + for (const auto& http2_port : create_server.http2_ports()) { + auto* creds = ReadServerCreds(http2_port.server_creds()); + auto addr = absl::StrCat("localhost:", http2_port.port()); + grpc_server_add_http2_port(server_, addr.c_str(), creds); + grpc_server_credentials_release(creds); + } grpc_server_start(server_); ResetServerState(); } else { diff --git a/test/core/end2end/fuzzers/api_fuzzer.proto b/test/core/end2end/fuzzers/api_fuzzer.proto index bec502f5a3b8f..77aac1f9a6a47 100644 --- a/test/core/end2end/fuzzers/api_fuzzer.proto +++ b/test/core/end2end/fuzzers/api_fuzzer.proto @@ -78,6 +78,13 @@ message ChannelCreds { } } +message ServerCreds { + oneof type { + Empty insecure_creds = 1; + Empty null = 2; + } +} + message Metadatum { StringSlice key = 1; ByteSlice value = 2; @@ -89,8 +96,14 @@ message CreateChannel { ChannelCreds channel_creds = 3; } +message Http2ServerPort { + int32 port = 1; + ServerCreds server_creds = 2; +} + message CreateServer { grpc.testing.FuzzingChannelArgs channel_args = 1; + repeated Http2ServerPort http2_ports = 2; } message CreateCall { From b63a21b419040506df091854c45654dadbf822f2 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 11 Dec 2023 13:36:14 -0800 Subject: [PATCH 076/127] [inproc] Call out requirements for inproc transport experiment (#35267) Closes #35267 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35267 from ctiller:cg-experiment-requires 242a3cd21a28257266b128a6ab7074615c2ed78e PiperOrigin-RevId: 589932835 --- bazel/experiments.bzl | 2 +- src/core/lib/experiments/experiments.cc | 57 ++++++++++++++--------- src/core/lib/experiments/experiments.h | 16 +++---- src/core/lib/experiments/experiments.yaml | 1 + 4 files changed, 46 insertions(+), 30 deletions(-) diff --git a/bazel/experiments.bzl b/bazel/experiments.bzl index 4bac512e43848..a1b5860a9c63a 100644 --- a/bazel/experiments.bzl +++ b/bazel/experiments.bzl @@ -36,10 +36,10 @@ EXPERIMENT_ENABLES = { "pending_queue_cap": "pending_queue_cap", "pick_first_happy_eyeballs": "pick_first_happy_eyeballs", "promise_based_client_call": "promise_based_client_call", - "promise_based_inproc_transport": "promise_based_inproc_transport", "promise_based_server_call": "promise_based_server_call", "red_max_concurrent_streams": "red_max_concurrent_streams", "registered_method_lookup_in_transport": "registered_method_lookup_in_transport", + "promise_based_inproc_transport": "promise_based_client_call,promise_based_inproc_transport,promise_based_server_call,registered_method_lookup_in_transport", "registered_methods_map": "registered_methods_map", "rfc_max_concurrent_streams": "rfc_max_concurrent_streams", "round_robin_delegate_to_pick_first": "round_robin_delegate_to_pick_first", diff --git a/src/core/lib/experiments/experiments.cc b/src/core/lib/experiments/experiments.cc index 0639dd281552d..a49b5554e88bd 100644 --- a/src/core/lib/experiments/experiments.cc +++ b/src/core/lib/experiments/experiments.cc @@ -93,9 +93,6 @@ const char* const description_promise_based_client_call = "If set, use the new gRPC promise based call code when it's appropriate " "(ie when all filters in a stack are promise based)"; const char* const additional_constraints_promise_based_client_call = "{}"; -const char* const description_promise_based_inproc_transport = - "Use promises for the in-process transport."; -const char* const additional_constraints_promise_based_inproc_transport = "{}"; const char* const description_promise_based_server_call = "If set, use the new gRPC promise based call code when it's appropriate " "(ie when all filters in a stack are promise based)"; @@ -108,6 +105,14 @@ const char* const description_registered_method_lookup_in_transport = "Change registered method's lookup point to transport"; const char* const additional_constraints_registered_method_lookup_in_transport = "{}"; +const char* const description_promise_based_inproc_transport = + "Use promises for the in-process transport."; +const char* const additional_constraints_promise_based_inproc_transport = "{}"; +const uint8_t required_experiments_promise_based_inproc_transport[] = { + static_cast(grpc_core::kExperimentIdPromiseBasedClientCall), + static_cast(grpc_core::kExperimentIdPromiseBasedServerCall), + static_cast( + grpc_core::kExperimentIdRegisteredMethodLookupInTransport)}; const char* const description_registered_methods_map = "Use absl::flat_hash_map for registered methods."; const char* const additional_constraints_registered_methods_map = "{}"; @@ -222,10 +227,6 @@ const ExperimentMetadata g_experiment_metadata[] = { additional_constraints_pick_first_happy_eyeballs, nullptr, 0, true, true}, {"promise_based_client_call", description_promise_based_client_call, additional_constraints_promise_based_client_call, nullptr, 0, false, true}, - {"promise_based_inproc_transport", - description_promise_based_inproc_transport, - additional_constraints_promise_based_inproc_transport, nullptr, 0, false, - false}, {"promise_based_server_call", description_promise_based_server_call, additional_constraints_promise_based_server_call, nullptr, 0, false, true}, {"red_max_concurrent_streams", description_red_max_concurrent_streams, @@ -235,6 +236,10 @@ const ExperimentMetadata g_experiment_metadata[] = { description_registered_method_lookup_in_transport, additional_constraints_registered_method_lookup_in_transport, nullptr, 0, true, true}, + {"promise_based_inproc_transport", + description_promise_based_inproc_transport, + additional_constraints_promise_based_inproc_transport, + required_experiments_promise_based_inproc_transport, 3, false, false}, {"registered_methods_map", description_registered_methods_map, additional_constraints_registered_methods_map, nullptr, 0, false, true}, {"rfc_max_concurrent_streams", description_rfc_max_concurrent_streams, @@ -352,9 +357,6 @@ const char* const description_promise_based_client_call = "If set, use the new gRPC promise based call code when it's appropriate " "(ie when all filters in a stack are promise based)"; const char* const additional_constraints_promise_based_client_call = "{}"; -const char* const description_promise_based_inproc_transport = - "Use promises for the in-process transport."; -const char* const additional_constraints_promise_based_inproc_transport = "{}"; const char* const description_promise_based_server_call = "If set, use the new gRPC promise based call code when it's appropriate " "(ie when all filters in a stack are promise based)"; @@ -367,6 +369,14 @@ const char* const description_registered_method_lookup_in_transport = "Change registered method's lookup point to transport"; const char* const additional_constraints_registered_method_lookup_in_transport = "{}"; +const char* const description_promise_based_inproc_transport = + "Use promises for the in-process transport."; +const char* const additional_constraints_promise_based_inproc_transport = "{}"; +const uint8_t required_experiments_promise_based_inproc_transport[] = { + static_cast(grpc_core::kExperimentIdPromiseBasedClientCall), + static_cast(grpc_core::kExperimentIdPromiseBasedServerCall), + static_cast( + grpc_core::kExperimentIdRegisteredMethodLookupInTransport)}; const char* const description_registered_methods_map = "Use absl::flat_hash_map for registered methods."; const char* const additional_constraints_registered_methods_map = "{}"; @@ -481,10 +491,6 @@ const ExperimentMetadata g_experiment_metadata[] = { additional_constraints_pick_first_happy_eyeballs, nullptr, 0, true, true}, {"promise_based_client_call", description_promise_based_client_call, additional_constraints_promise_based_client_call, nullptr, 0, false, true}, - {"promise_based_inproc_transport", - description_promise_based_inproc_transport, - additional_constraints_promise_based_inproc_transport, nullptr, 0, false, - false}, {"promise_based_server_call", description_promise_based_server_call, additional_constraints_promise_based_server_call, nullptr, 0, false, true}, {"red_max_concurrent_streams", description_red_max_concurrent_streams, @@ -494,6 +500,10 @@ const ExperimentMetadata g_experiment_metadata[] = { description_registered_method_lookup_in_transport, additional_constraints_registered_method_lookup_in_transport, nullptr, 0, true, true}, + {"promise_based_inproc_transport", + description_promise_based_inproc_transport, + additional_constraints_promise_based_inproc_transport, + required_experiments_promise_based_inproc_transport, 3, false, false}, {"registered_methods_map", description_registered_methods_map, additional_constraints_registered_methods_map, nullptr, 0, false, true}, {"rfc_max_concurrent_streams", description_rfc_max_concurrent_streams, @@ -611,9 +621,6 @@ const char* const description_promise_based_client_call = "If set, use the new gRPC promise based call code when it's appropriate " "(ie when all filters in a stack are promise based)"; const char* const additional_constraints_promise_based_client_call = "{}"; -const char* const description_promise_based_inproc_transport = - "Use promises for the in-process transport."; -const char* const additional_constraints_promise_based_inproc_transport = "{}"; const char* const description_promise_based_server_call = "If set, use the new gRPC promise based call code when it's appropriate " "(ie when all filters in a stack are promise based)"; @@ -626,6 +633,14 @@ const char* const description_registered_method_lookup_in_transport = "Change registered method's lookup point to transport"; const char* const additional_constraints_registered_method_lookup_in_transport = "{}"; +const char* const description_promise_based_inproc_transport = + "Use promises for the in-process transport."; +const char* const additional_constraints_promise_based_inproc_transport = "{}"; +const uint8_t required_experiments_promise_based_inproc_transport[] = { + static_cast(grpc_core::kExperimentIdPromiseBasedClientCall), + static_cast(grpc_core::kExperimentIdPromiseBasedServerCall), + static_cast( + grpc_core::kExperimentIdRegisteredMethodLookupInTransport)}; const char* const description_registered_methods_map = "Use absl::flat_hash_map for registered methods."; const char* const additional_constraints_registered_methods_map = "{}"; @@ -740,10 +755,6 @@ const ExperimentMetadata g_experiment_metadata[] = { additional_constraints_pick_first_happy_eyeballs, nullptr, 0, true, true}, {"promise_based_client_call", description_promise_based_client_call, additional_constraints_promise_based_client_call, nullptr, 0, false, true}, - {"promise_based_inproc_transport", - description_promise_based_inproc_transport, - additional_constraints_promise_based_inproc_transport, nullptr, 0, false, - false}, {"promise_based_server_call", description_promise_based_server_call, additional_constraints_promise_based_server_call, nullptr, 0, false, true}, {"red_max_concurrent_streams", description_red_max_concurrent_streams, @@ -753,6 +764,10 @@ const ExperimentMetadata g_experiment_metadata[] = { description_registered_method_lookup_in_transport, additional_constraints_registered_method_lookup_in_transport, nullptr, 0, true, true}, + {"promise_based_inproc_transport", + description_promise_based_inproc_transport, + additional_constraints_promise_based_inproc_transport, + required_experiments_promise_based_inproc_transport, 3, false, false}, {"registered_methods_map", description_registered_methods_map, additional_constraints_registered_methods_map, nullptr, 0, false, true}, {"rfc_max_concurrent_streams", description_rfc_max_concurrent_streams, diff --git a/src/core/lib/experiments/experiments.h b/src/core/lib/experiments/experiments.h index bf17ee2ce3bf4..2e680ac8ead8d 100644 --- a/src/core/lib/experiments/experiments.h +++ b/src/core/lib/experiments/experiments.h @@ -91,11 +91,11 @@ inline bool IsPendingQueueCapEnabled() { return true; } #define GRPC_EXPERIMENT_IS_INCLUDED_PICK_FIRST_HAPPY_EYEBALLS inline bool IsPickFirstHappyEyeballsEnabled() { return true; } inline bool IsPromiseBasedClientCallEnabled() { return false; } -inline bool IsPromiseBasedInprocTransportEnabled() { return false; } inline bool IsPromiseBasedServerCallEnabled() { return false; } inline bool IsRedMaxConcurrentStreamsEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_REGISTERED_METHOD_LOOKUP_IN_TRANSPORT inline bool IsRegisteredMethodLookupInTransportEnabled() { return true; } +inline bool IsPromiseBasedInprocTransportEnabled() { return false; } inline bool IsRegisteredMethodsMapEnabled() { return false; } inline bool IsRfcMaxConcurrentStreamsEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_ROUND_ROBIN_DELEGATE_TO_PICK_FIRST @@ -154,11 +154,11 @@ inline bool IsPendingQueueCapEnabled() { return true; } #define GRPC_EXPERIMENT_IS_INCLUDED_PICK_FIRST_HAPPY_EYEBALLS inline bool IsPickFirstHappyEyeballsEnabled() { return true; } inline bool IsPromiseBasedClientCallEnabled() { return false; } -inline bool IsPromiseBasedInprocTransportEnabled() { return false; } inline bool IsPromiseBasedServerCallEnabled() { return false; } inline bool IsRedMaxConcurrentStreamsEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_REGISTERED_METHOD_LOOKUP_IN_TRANSPORT inline bool IsRegisteredMethodLookupInTransportEnabled() { return true; } +inline bool IsPromiseBasedInprocTransportEnabled() { return false; } inline bool IsRegisteredMethodsMapEnabled() { return false; } inline bool IsRfcMaxConcurrentStreamsEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_ROUND_ROBIN_DELEGATE_TO_PICK_FIRST @@ -217,11 +217,11 @@ inline bool IsPendingQueueCapEnabled() { return true; } #define GRPC_EXPERIMENT_IS_INCLUDED_PICK_FIRST_HAPPY_EYEBALLS inline bool IsPickFirstHappyEyeballsEnabled() { return true; } inline bool IsPromiseBasedClientCallEnabled() { return false; } -inline bool IsPromiseBasedInprocTransportEnabled() { return false; } inline bool IsPromiseBasedServerCallEnabled() { return false; } inline bool IsRedMaxConcurrentStreamsEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_REGISTERED_METHOD_LOOKUP_IN_TRANSPORT inline bool IsRegisteredMethodLookupInTransportEnabled() { return true; } +inline bool IsPromiseBasedInprocTransportEnabled() { return false; } inline bool IsRegisteredMethodsMapEnabled() { return false; } inline bool IsRfcMaxConcurrentStreamsEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_ROUND_ROBIN_DELEGATE_TO_PICK_FIRST @@ -266,10 +266,10 @@ enum ExperimentIds { kExperimentIdPendingQueueCap, kExperimentIdPickFirstHappyEyeballs, kExperimentIdPromiseBasedClientCall, - kExperimentIdPromiseBasedInprocTransport, kExperimentIdPromiseBasedServerCall, kExperimentIdRedMaxConcurrentStreams, kExperimentIdRegisteredMethodLookupInTransport, + kExperimentIdPromiseBasedInprocTransport, kExperimentIdRegisteredMethodsMap, kExperimentIdRfcMaxConcurrentStreams, kExperimentIdRoundRobinDelegateToPickFirst, @@ -364,10 +364,6 @@ inline bool IsPickFirstHappyEyeballsEnabled() { inline bool IsPromiseBasedClientCallEnabled() { return IsExperimentEnabled(kExperimentIdPromiseBasedClientCall); } -#define GRPC_EXPERIMENT_IS_INCLUDED_PROMISE_BASED_INPROC_TRANSPORT -inline bool IsPromiseBasedInprocTransportEnabled() { - return IsExperimentEnabled(kExperimentIdPromiseBasedInprocTransport); -} #define GRPC_EXPERIMENT_IS_INCLUDED_PROMISE_BASED_SERVER_CALL inline bool IsPromiseBasedServerCallEnabled() { return IsExperimentEnabled(kExperimentIdPromiseBasedServerCall); @@ -380,6 +376,10 @@ inline bool IsRedMaxConcurrentStreamsEnabled() { inline bool IsRegisteredMethodLookupInTransportEnabled() { return IsExperimentEnabled(kExperimentIdRegisteredMethodLookupInTransport); } +#define GRPC_EXPERIMENT_IS_INCLUDED_PROMISE_BASED_INPROC_TRANSPORT +inline bool IsPromiseBasedInprocTransportEnabled() { + return IsExperimentEnabled(kExperimentIdPromiseBasedInprocTransport); +} #define GRPC_EXPERIMENT_IS_INCLUDED_REGISTERED_METHODS_MAP inline bool IsRegisteredMethodsMapEnabled() { return IsExperimentEnabled(kExperimentIdRegisteredMethodsMap); diff --git a/src/core/lib/experiments/experiments.yaml b/src/core/lib/experiments/experiments.yaml index 54b3ea6ff1536..d42e14ee34af0 100644 --- a/src/core/lib/experiments/experiments.yaml +++ b/src/core/lib/experiments/experiments.yaml @@ -169,6 +169,7 @@ owner: ctiller@google.com test_tags: [] allow_in_fuzzing_config: false # experiment currently crashes if enabled + requires: [promise_based_client_call, promise_based_server_call, registered_method_lookup_in_transport] - name: promise_based_server_call description: If set, use the new gRPC promise based call code when it's appropriate From a7e90045db6a6eb1f85c7537b2069e3f55ec25fa Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 11 Dec 2023 16:33:22 -0800 Subject: [PATCH 077/127] [promises] Fix fuzzer found uncancelable call bug in client promise code (#34909) Closes #34909 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/34909 from ctiller:lambda-mcfly 92f759d7630c6a6fb10e6b5f9fc6df2a612febad PiperOrigin-RevId: 589989462 --- src/core/lib/channel/connected_channel.cc | 2 + src/core/lib/surface/call.cc | 3 +- .../client_fuzzer_corpus/5061521840340992 | 51 +++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 test/core/end2end/fuzzers/client_fuzzer_corpus/5061521840340992 diff --git a/src/core/lib/channel/connected_channel.cc b/src/core/lib/channel/connected_channel.cc index 9ea8faeb507d0..b7eccc29dd43b 100644 --- a/src/core/lib/channel/connected_channel.cc +++ b/src/core/lib/channel/connected_channel.cc @@ -411,6 +411,8 @@ auto ConnectedChannelStream::RecvMessages( } if (cancel_on_error && !status.ok()) { incoming_messages.CloseWithError(); + } else { + incoming_messages.Close(); } return Immediate(LoopCtl(status.status())); }; diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc index 840ed8383311b..c34d29d152f22 100644 --- a/src/core/lib/surface/call.cc +++ b/src/core/lib/surface/call.cc @@ -2978,7 +2978,8 @@ void ClientPromiseBasedCall::CommitBatch(const grpc_op* ops, size_t nops, StartRecvMessage( op, completion, [this]() { - return server_initial_metadata_.receiver.AwaitClosed(); + return Race(server_initial_metadata_.receiver.AwaitClosed(), + server_to_client_messages_.receiver.AwaitClosed()); }, &server_to_client_messages_.receiver, false, spawner); break; diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/5061521840340992 b/test/core/end2end/fuzzers/client_fuzzer_corpus/5061521840340992 new file mode 100644 index 0000000000000..880e5959705dd --- /dev/null +++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/5061521840340992 @@ -0,0 +1,51 @@ +api_actions { + create_call { + propagation_mask: 6 + method { + value: "~" + } + timeout: 34816 + } +} +api_actions { + queue_batch { + operations { + send_initial_metadata { + } + } + operations { + send_message { + } + } + operations { + receive_message { + } + } + } +} +api_actions { + create_server { + } +} +api_actions { + disable_tracer: "(" +} +api_actions { + destroy_call { + } +} +api_actions { + poll_cq { + } +} +api_actions { +} +api_actions { + shutdown_server { + } +} +config_vars { + verbosity: "\364\204\204\204\364\204\204\204\364\204\204\204\364\204\204\204\364\204\204\204\364\204\204\204\364\204\204\204\364\204\204\204\004" + stacktrace_minloglevel: "yyyyyyyyyyyyy&yyyyyyy\177\014" + experiments: 1099511626496 +} From ff63ad941360d20757367a9c57192885d1c2fbb9 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 11 Dec 2023 17:55:26 -0800 Subject: [PATCH 078/127] [call-v3] Convert message compression filter (#35269) Closes #35269 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35269 from ctiller:cg-compress 0304821f07f29e9132799d46a2cdf7bb8dfb5309 PiperOrigin-RevId: 590010564 --- BUILD | 3 + CMakeLists.txt | 2 + Makefile | 2 + Package.swift | 2 + bazel/experiments.bzl | 10 + build_autogenerated.yaml | 4 + config.m4 | 1 + config.w32 | 1 + gRPC-C++.podspec | 2 + gRPC-Core.podspec | 3 + grpc.gemspec | 2 + grpc.gyp | 2 + package.xml | 2 + .../ext/filters/http/http_filters_plugin.cc | 48 ++- .../message_compress/compression_filter.cc | 135 +++----- .../message_compress/compression_filter.h | 66 +++- .../legacy_compression_filter.cc | 325 ++++++++++++++++++ .../legacy_compression_filter.h | 139 ++++++++ src/core/lib/channel/promise_based_filter.h | 182 +++++++++- src/core/lib/experiments/experiments.cc | 15 + src/core/lib/experiments/experiments.h | 8 + src/core/lib/experiments/experiments.yaml | 6 + src/python/grpcio/grpc_core_dependencies.py | 1 + test/core/end2end/BUILD | 5 +- test/core/end2end/grpc_core_end2end_test.bzl | 4 +- tools/doxygen/Doxyfile.c++.internal | 2 + tools/doxygen/Doxyfile.core.internal | 2 + 27 files changed, 863 insertions(+), 111 deletions(-) create mode 100644 src/core/ext/filters/http/message_compress/legacy_compression_filter.cc create mode 100644 src/core/ext/filters/http/message_compress/legacy_compression_filter.h diff --git a/BUILD b/BUILD index d07866b8b9cd3..4c668a9e393af 100644 --- a/BUILD +++ b/BUILD @@ -3590,11 +3590,13 @@ grpc_cc_library( "//src/core:ext/filters/http/client/http_client_filter.cc", "//src/core:ext/filters/http/http_filters_plugin.cc", "//src/core:ext/filters/http/message_compress/compression_filter.cc", + "//src/core:ext/filters/http/message_compress/legacy_compression_filter.cc", "//src/core:ext/filters/http/server/http_server_filter.cc", ], hdrs = [ "//src/core:ext/filters/http/client/http_client_filter.h", "//src/core:ext/filters/http/message_compress/compression_filter.h", + "//src/core:ext/filters/http/message_compress/legacy_compression_filter.h", "//src/core:ext/filters/http/server/http_server_filter.h", ], external_deps = [ @@ -3623,6 +3625,7 @@ grpc_cc_library( "//src/core:channel_fwd", "//src/core:channel_stack_type", "//src/core:context", + "//src/core:experiments", "//src/core:grpc_message_size_filter", "//src/core:latch", "//src/core:map", diff --git a/CMakeLists.txt b/CMakeLists.txt index 9aea587d790c9..90f0b5d3a4a7a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1826,6 +1826,7 @@ add_library(grpc src/core/ext/filters/http/client_authority_filter.cc src/core/ext/filters/http/http_filters_plugin.cc src/core/ext/filters/http/message_compress/compression_filter.cc + src/core/ext/filters/http/message_compress/legacy_compression_filter.cc src/core/ext/filters/http/server/http_server_filter.cc src/core/ext/filters/message_size/message_size_filter.cc src/core/ext/filters/rbac/rbac_filter.cc @@ -2882,6 +2883,7 @@ add_library(grpc_unsecure src/core/ext/filters/http/client_authority_filter.cc src/core/ext/filters/http/http_filters_plugin.cc src/core/ext/filters/http/message_compress/compression_filter.cc + src/core/ext/filters/http/message_compress/legacy_compression_filter.cc src/core/ext/filters/http/server/http_server_filter.cc src/core/ext/filters/message_size/message_size_filter.cc src/core/ext/transport/chttp2/client/chttp2_connector.cc diff --git a/Makefile b/Makefile index 372949e7b4754..30eb03c8ef2eb 100644 --- a/Makefile +++ b/Makefile @@ -1028,6 +1028,7 @@ LIBGRPC_SRC = \ src/core/ext/filters/http/client_authority_filter.cc \ src/core/ext/filters/http/http_filters_plugin.cc \ src/core/ext/filters/http/message_compress/compression_filter.cc \ + src/core/ext/filters/http/message_compress/legacy_compression_filter.cc \ src/core/ext/filters/http/server/http_server_filter.cc \ src/core/ext/filters/message_size/message_size_filter.cc \ src/core/ext/filters/rbac/rbac_filter.cc \ @@ -1934,6 +1935,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/ext/filters/http/client_authority_filter.cc \ src/core/ext/filters/http/http_filters_plugin.cc \ src/core/ext/filters/http/message_compress/compression_filter.cc \ + src/core/ext/filters/http/message_compress/legacy_compression_filter.cc \ src/core/ext/filters/http/server/http_server_filter.cc \ src/core/ext/filters/message_size/message_size_filter.cc \ src/core/ext/transport/chttp2/client/chttp2_connector.cc \ diff --git a/Package.swift b/Package.swift index a692977ac4e51..512f70b00dfeb 100644 --- a/Package.swift +++ b/Package.swift @@ -249,6 +249,8 @@ let package = Package( "src/core/ext/filters/http/http_filters_plugin.cc", "src/core/ext/filters/http/message_compress/compression_filter.cc", "src/core/ext/filters/http/message_compress/compression_filter.h", + "src/core/ext/filters/http/message_compress/legacy_compression_filter.cc", + "src/core/ext/filters/http/message_compress/legacy_compression_filter.h", "src/core/ext/filters/http/server/http_server_filter.cc", "src/core/ext/filters/http/server/http_server_filter.h", "src/core/ext/filters/message_size/message_size_filter.cc", diff --git a/bazel/experiments.bzl b/bazel/experiments.bzl index a1b5860a9c63a..1b63ca0a1b24d 100644 --- a/bazel/experiments.bzl +++ b/bazel/experiments.bzl @@ -51,6 +51,7 @@ EXPERIMENT_ENABLES = { "trace_record_callops": "trace_record_callops", "unconstrained_max_quota_buffer_size": "unconstrained_max_quota_buffer_size", "v3_channel_idle_filters": "v3_channel_idle_filters", + "v3_compression_filter": "v3_compression_filter", "work_serializer_clears_time_cache": "work_serializer_clears_time_cache", "work_serializer_dispatch": "work_serializer_dispatch", "write_size_policy": "write_size_policy", @@ -66,6 +67,9 @@ EXPERIMENTS = { "bad_client_test": [ "rfc_max_concurrent_streams", ], + "compression_test": [ + "v3_compression_filter", + ], "core_end2end_test": [ "promise_based_client_call", "promise_based_server_call", @@ -145,6 +149,9 @@ EXPERIMENTS = { "bad_client_test": [ "rfc_max_concurrent_streams", ], + "compression_test": [ + "v3_compression_filter", + ], "core_end2end_test": [ "promise_based_client_call", "promise_based_server_call", @@ -221,6 +228,9 @@ EXPERIMENTS = { "cancel_ares_query_test": [ "event_engine_dns", ], + "compression_test": [ + "v3_compression_filter", + ], "core_end2end_test": [ "event_engine_client", "promise_based_client_call", diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index 4789b3f5a46c1..1aeb1ad9026ae 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -276,6 +276,7 @@ libs: - src/core/ext/filters/http/client/http_client_filter.h - src/core/ext/filters/http/client_authority_filter.h - src/core/ext/filters/http/message_compress/compression_filter.h + - src/core/ext/filters/http/message_compress/legacy_compression_filter.h - src/core/ext/filters/http/server/http_server_filter.h - src/core/ext/filters/message_size/message_size_filter.h - src/core/ext/filters/rbac/rbac_filter.h @@ -1280,6 +1281,7 @@ libs: - src/core/ext/filters/http/client_authority_filter.cc - src/core/ext/filters/http/http_filters_plugin.cc - src/core/ext/filters/http/message_compress/compression_filter.cc + - src/core/ext/filters/http/message_compress/legacy_compression_filter.cc - src/core/ext/filters/http/server/http_server_filter.cc - src/core/ext/filters/message_size/message_size_filter.cc - src/core/ext/filters/rbac/rbac_filter.cc @@ -2210,6 +2212,7 @@ libs: - src/core/ext/filters/http/client/http_client_filter.h - src/core/ext/filters/http/client_authority_filter.h - src/core/ext/filters/http/message_compress/compression_filter.h + - src/core/ext/filters/http/message_compress/legacy_compression_filter.h - src/core/ext/filters/http/server/http_server_filter.h - src/core/ext/filters/message_size/message_size_filter.h - src/core/ext/transport/chttp2/client/chttp2_connector.h @@ -2689,6 +2692,7 @@ libs: - src/core/ext/filters/http/client_authority_filter.cc - src/core/ext/filters/http/http_filters_plugin.cc - src/core/ext/filters/http/message_compress/compression_filter.cc + - src/core/ext/filters/http/message_compress/legacy_compression_filter.cc - src/core/ext/filters/http/server/http_server_filter.cc - src/core/ext/filters/message_size/message_size_filter.cc - src/core/ext/transport/chttp2/client/chttp2_connector.cc diff --git a/config.m4 b/config.m4 index 0b2e030045fee..146fbf7251c7e 100644 --- a/config.m4 +++ b/config.m4 @@ -115,6 +115,7 @@ if test "$PHP_GRPC" != "no"; then src/core/ext/filters/http/client_authority_filter.cc \ src/core/ext/filters/http/http_filters_plugin.cc \ src/core/ext/filters/http/message_compress/compression_filter.cc \ + src/core/ext/filters/http/message_compress/legacy_compression_filter.cc \ src/core/ext/filters/http/server/http_server_filter.cc \ src/core/ext/filters/message_size/message_size_filter.cc \ src/core/ext/filters/rbac/rbac_filter.cc \ diff --git a/config.w32 b/config.w32 index 1455ff6cc05c7..6fd1c3c50dd79 100644 --- a/config.w32 +++ b/config.w32 @@ -80,6 +80,7 @@ if (PHP_GRPC != "no") { "src\\core\\ext\\filters\\http\\client_authority_filter.cc " + "src\\core\\ext\\filters\\http\\http_filters_plugin.cc " + "src\\core\\ext\\filters\\http\\message_compress\\compression_filter.cc " + + "src\\core\\ext\\filters\\http\\message_compress\\legacy_compression_filter.cc " + "src\\core\\ext\\filters\\http\\server\\http_server_filter.cc " + "src\\core\\ext\\filters\\message_size\\message_size_filter.cc " + "src\\core\\ext\\filters\\rbac\\rbac_filter.cc " + diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index 9364a57164e87..5bc1877ac30be 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -309,6 +309,7 @@ Pod::Spec.new do |s| 'src/core/ext/filters/http/client/http_client_filter.h', 'src/core/ext/filters/http/client_authority_filter.h', 'src/core/ext/filters/http/message_compress/compression_filter.h', + 'src/core/ext/filters/http/message_compress/legacy_compression_filter.h', 'src/core/ext/filters/http/server/http_server_filter.h', 'src/core/ext/filters/message_size/message_size_filter.h', 'src/core/ext/filters/rbac/rbac_filter.h', @@ -1562,6 +1563,7 @@ Pod::Spec.new do |s| 'src/core/ext/filters/http/client/http_client_filter.h', 'src/core/ext/filters/http/client_authority_filter.h', 'src/core/ext/filters/http/message_compress/compression_filter.h', + 'src/core/ext/filters/http/message_compress/legacy_compression_filter.h', 'src/core/ext/filters/http/server/http_server_filter.h', 'src/core/ext/filters/message_size/message_size_filter.h', 'src/core/ext/filters/rbac/rbac_filter.h', diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 0076a1b6311e5..b33c007214aee 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -352,6 +352,8 @@ Pod::Spec.new do |s| 'src/core/ext/filters/http/http_filters_plugin.cc', 'src/core/ext/filters/http/message_compress/compression_filter.cc', 'src/core/ext/filters/http/message_compress/compression_filter.h', + 'src/core/ext/filters/http/message_compress/legacy_compression_filter.cc', + 'src/core/ext/filters/http/message_compress/legacy_compression_filter.h', 'src/core/ext/filters/http/server/http_server_filter.cc', 'src/core/ext/filters/http/server/http_server_filter.h', 'src/core/ext/filters/message_size/message_size_filter.cc', @@ -2346,6 +2348,7 @@ Pod::Spec.new do |s| 'src/core/ext/filters/http/client/http_client_filter.h', 'src/core/ext/filters/http/client_authority_filter.h', 'src/core/ext/filters/http/message_compress/compression_filter.h', + 'src/core/ext/filters/http/message_compress/legacy_compression_filter.h', 'src/core/ext/filters/http/server/http_server_filter.h', 'src/core/ext/filters/message_size/message_size_filter.h', 'src/core/ext/filters/rbac/rbac_filter.h', diff --git a/grpc.gemspec b/grpc.gemspec index e5962295a73c3..e18172ead0150 100644 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -255,6 +255,8 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/filters/http/http_filters_plugin.cc ) s.files += %w( src/core/ext/filters/http/message_compress/compression_filter.cc ) s.files += %w( src/core/ext/filters/http/message_compress/compression_filter.h ) + s.files += %w( src/core/ext/filters/http/message_compress/legacy_compression_filter.cc ) + s.files += %w( src/core/ext/filters/http/message_compress/legacy_compression_filter.h ) s.files += %w( src/core/ext/filters/http/server/http_server_filter.cc ) s.files += %w( src/core/ext/filters/http/server/http_server_filter.h ) s.files += %w( src/core/ext/filters/message_size/message_size_filter.cc ) diff --git a/grpc.gyp b/grpc.gyp index e68df91099f59..fd09bd55d1e58 100644 --- a/grpc.gyp +++ b/grpc.gyp @@ -348,6 +348,7 @@ 'src/core/ext/filters/http/client_authority_filter.cc', 'src/core/ext/filters/http/http_filters_plugin.cc', 'src/core/ext/filters/http/message_compress/compression_filter.cc', + 'src/core/ext/filters/http/message_compress/legacy_compression_filter.cc', 'src/core/ext/filters/http/server/http_server_filter.cc', 'src/core/ext/filters/message_size/message_size_filter.cc', 'src/core/ext/filters/rbac/rbac_filter.cc', @@ -1196,6 +1197,7 @@ 'src/core/ext/filters/http/client_authority_filter.cc', 'src/core/ext/filters/http/http_filters_plugin.cc', 'src/core/ext/filters/http/message_compress/compression_filter.cc', + 'src/core/ext/filters/http/message_compress/legacy_compression_filter.cc', 'src/core/ext/filters/http/server/http_server_filter.cc', 'src/core/ext/filters/message_size/message_size_filter.cc', 'src/core/ext/transport/chttp2/client/chttp2_connector.cc', diff --git a/package.xml b/package.xml index 3a2b2beb84ef3..f5724cbc51288 100644 --- a/package.xml +++ b/package.xml @@ -237,6 +237,8 @@ + + diff --git a/src/core/ext/filters/http/http_filters_plugin.cc b/src/core/ext/filters/http/http_filters_plugin.cc index 04fb7f9707d09..b8099c45c2f9e 100644 --- a/src/core/ext/filters/http/http_filters_plugin.cc +++ b/src/core/ext/filters/http/http_filters_plugin.cc @@ -22,10 +22,12 @@ #include "src/core/ext/filters/http/client/http_client_filter.h" #include "src/core/ext/filters/http/message_compress/compression_filter.h" +#include "src/core/ext/filters/http/message_compress/legacy_compression_filter.h" #include "src/core/ext/filters/http/server/http_server_filter.h" #include "src/core/ext/filters/message_size/message_size_filter.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/config/core_configuration.h" +#include "src/core/lib/experiments/experiments.h" #include "src/core/lib/surface/channel_stack_type.h" #include "src/core/lib/transport/transport.h" @@ -38,20 +40,38 @@ bool IsBuildingHttpLikeTransport(const ChannelArgs& args) { } // namespace void RegisterHttpFilters(CoreConfiguration::Builder* builder) { - builder->channel_init() - ->RegisterFilter(GRPC_CLIENT_SUBCHANNEL, - &ClientCompressionFilter::kFilter) - .If(IsBuildingHttpLikeTransport) - .After({&HttpClientFilter::kFilter, &ClientMessageSizeFilter::kFilter}); - builder->channel_init() - ->RegisterFilter(GRPC_CLIENT_DIRECT_CHANNEL, - &ClientCompressionFilter::kFilter) - .If(IsBuildingHttpLikeTransport) - .After({&HttpClientFilter::kFilter, &ClientMessageSizeFilter::kFilter}); - builder->channel_init() - ->RegisterFilter(GRPC_SERVER_CHANNEL, &ServerCompressionFilter::kFilter) - .If(IsBuildingHttpLikeTransport) - .After({&HttpServerFilter::kFilter, &ServerMessageSizeFilter::kFilter}); + if (IsV3CompressionFilterEnabled()) { + builder->channel_init() + ->RegisterFilter(GRPC_CLIENT_SUBCHANNEL, + &ClientCompressionFilter::kFilter) + .If(IsBuildingHttpLikeTransport) + .After({&HttpClientFilter::kFilter, &ClientMessageSizeFilter::kFilter}); + builder->channel_init() + ->RegisterFilter(GRPC_CLIENT_DIRECT_CHANNEL, + &ClientCompressionFilter::kFilter) + .If(IsBuildingHttpLikeTransport) + .After({&HttpClientFilter::kFilter, &ClientMessageSizeFilter::kFilter}); + builder->channel_init() + ->RegisterFilter(GRPC_SERVER_CHANNEL, &ServerCompressionFilter::kFilter) + .If(IsBuildingHttpLikeTransport) + .After({&HttpServerFilter::kFilter, &ServerMessageSizeFilter::kFilter}); + } else { + builder->channel_init() + ->RegisterFilter(GRPC_CLIENT_SUBCHANNEL, + &LegacyClientCompressionFilter::kFilter) + .If(IsBuildingHttpLikeTransport) + .After({&HttpClientFilter::kFilter, &ClientMessageSizeFilter::kFilter}); + builder->channel_init() + ->RegisterFilter(GRPC_CLIENT_DIRECT_CHANNEL, + &LegacyClientCompressionFilter::kFilter) + .If(IsBuildingHttpLikeTransport) + .After({&HttpClientFilter::kFilter, &ClientMessageSizeFilter::kFilter}); + builder->channel_init() + ->RegisterFilter(GRPC_SERVER_CHANNEL, + &LegacyServerCompressionFilter::kFilter) + .If(IsBuildingHttpLikeTransport) + .After({&HttpServerFilter::kFilter, &ServerMessageSizeFilter::kFilter}); + } builder->channel_init() ->RegisterFilter(GRPC_CLIENT_SUBCHANNEL, &HttpClientFilter::kFilter) .If(IsBuildingHttpLikeTransport) diff --git a/src/core/ext/filters/http/message_compress/compression_filter.cc b/src/core/ext/filters/http/message_compress/compression_filter.cc index b3c8d521cc96c..1ffee085230e1 100644 --- a/src/core/ext/filters/http/message_compress/compression_filter.cc +++ b/src/core/ext/filters/http/message_compress/compression_filter.cc @@ -56,6 +56,11 @@ namespace grpc_core { +const NoInterceptor ServerCompressionFilter::Call::OnServerTrailingMetadata; +const NoInterceptor ServerCompressionFilter::Call::OnFinalize; +const NoInterceptor ClientCompressionFilter::Call::OnServerTrailingMetadata; +const NoInterceptor ClientCompressionFilter::Call::OnFinalize; + const grpc_channel_filter ClientCompressionFilter::kFilter = MakePromiseBasedFilter ServerCompressionFilter::Create( return ServerCompressionFilter(args); } -CompressionFilter::CompressionFilter(const ChannelArgs& args) +ChannelCompression::ChannelCompression(const ChannelArgs& args) : max_recv_size_(GetMaxRecvSizeFromChannelArgs(args)), message_size_service_config_parser_index_( MessageSizeParser::ParserIndex()), @@ -105,7 +110,7 @@ CompressionFilter::CompressionFilter(const ChannelArgs& args) } } -MessageHandle CompressionFilter::CompressMessage( +MessageHandle ChannelCompression::CompressMessage( MessageHandle message, grpc_compression_algorithm algorithm) const { if (GRPC_TRACE_FLAG_ENABLED(grpc_compression_trace)) { gpr_log(GPR_INFO, "CompressMessage: len=%" PRIdPTR " alg=%d flags=%d", @@ -163,7 +168,7 @@ MessageHandle CompressionFilter::CompressMessage( return message; } -absl::StatusOr CompressionFilter::DecompressMessage( +absl::StatusOr ChannelCompression::DecompressMessage( MessageHandle message, DecompressArgs args) const { if (GRPC_TRACE_FLAG_ENABLED(grpc_compression_trace)) { gpr_log(GPR_INFO, "DecompressMessage: len=%" PRIdPTR " max=%d alg=%d", @@ -208,7 +213,7 @@ absl::StatusOr CompressionFilter::DecompressMessage( return std::move(message); } -grpc_compression_algorithm CompressionFilter::HandleOutgoingMetadata( +grpc_compression_algorithm ChannelCompression::HandleOutgoingMetadata( grpc_metadata_batch& outgoing_metadata) { const auto algorithm = outgoing_metadata.Take(GrpcInternalEncodingRequest()) .value_or(default_compression_algorithm()); @@ -221,7 +226,7 @@ grpc_compression_algorithm CompressionFilter::HandleOutgoingMetadata( return algorithm; } -CompressionFilter::DecompressArgs CompressionFilter::HandleIncomingMetadata( +ChannelCompression::DecompressArgs ChannelCompression::HandleIncomingMetadata( const grpc_metadata_batch& incoming_metadata) { // Configure max receive size. auto max_recv_message_length = max_recv_size_; @@ -232,89 +237,59 @@ CompressionFilter::DecompressArgs CompressionFilter::HandleIncomingMetadata( if (limits != nullptr && limits->max_recv_size().has_value() && (!max_recv_message_length.has_value() || *limits->max_recv_size() < *max_recv_message_length)) { - max_recv_message_length = *limits->max_recv_size(); + max_recv_message_length = limits->max_recv_size(); } return DecompressArgs{incoming_metadata.get(GrpcEncodingMetadata()) .value_or(GRPC_COMPRESS_NONE), max_recv_message_length}; } -ArenaPromise ClientCompressionFilter::MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) { - auto compression_algorithm = - HandleOutgoingMetadata(*call_args.client_initial_metadata); - call_args.client_to_server_messages->InterceptAndMap( - [compression_algorithm, - this](MessageHandle message) -> absl::optional { - return CompressMessage(std::move(message), compression_algorithm); - }); - auto* decompress_args = GetContext()->New( - DecompressArgs{GRPC_COMPRESS_ALGORITHMS_COUNT, absl::nullopt}); - auto* decompress_err = - GetContext()->New>(); - call_args.server_initial_metadata->InterceptAndMap( - [decompress_args, this](ServerMetadataHandle server_initial_metadata) - -> absl::optional { - if (server_initial_metadata == nullptr) return absl::nullopt; - *decompress_args = HandleIncomingMetadata(*server_initial_metadata); - return std::move(server_initial_metadata); - }); - call_args.server_to_client_messages->InterceptAndMap( - [decompress_err, decompress_args, - this](MessageHandle message) -> absl::optional { - auto r = DecompressMessage(std::move(message), *decompress_args); - if (!r.ok()) { - decompress_err->Set(ServerMetadataFromStatus(r.status())); - return absl::nullopt; - } - return std::move(*r); - }); - // Run the next filter, and race it with getting an error from decompression. - return PrioritizedRace(decompress_err->Wait(), - next_promise_factory(std::move(call_args))); +void ClientCompressionFilter::Call::OnClientInitialMetadata( + ClientMetadata& md, ClientCompressionFilter* filter) { + compression_algorithm_ = + filter->compression_engine_.HandleOutgoingMetadata(md); +} + +MessageHandle ClientCompressionFilter::Call::OnClientToServerMessage( + MessageHandle message, ClientCompressionFilter* filter) { + return filter->compression_engine_.CompressMessage(std::move(message), + compression_algorithm_); +} + +void ClientCompressionFilter::Call::OnServerInitialMetadata( + ServerMetadata& md, ClientCompressionFilter* filter) { + decompress_args_ = filter->compression_engine_.HandleIncomingMetadata(md); +} + +absl::StatusOr +ClientCompressionFilter::Call::OnServerToClientMessage( + MessageHandle message, ClientCompressionFilter* filter) { + return filter->compression_engine_.DecompressMessage(std::move(message), + decompress_args_); +} + +void ServerCompressionFilter::Call::OnClientInitialMetadata( + ClientMetadata& md, ServerCompressionFilter* filter) { + decompress_args_ = filter->compression_engine_.HandleIncomingMetadata(md); +} + +absl::StatusOr +ServerCompressionFilter::Call::OnClientToServerMessage( + MessageHandle message, ServerCompressionFilter* filter) { + return filter->compression_engine_.DecompressMessage(std::move(message), + decompress_args_); +} + +void ServerCompressionFilter::Call::OnServerInitialMetadata( + ServerMetadata& md, ServerCompressionFilter* filter) { + compression_algorithm_ = + filter->compression_engine_.HandleOutgoingMetadata(md); } -ArenaPromise ServerCompressionFilter::MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) { - auto decompress_args = - HandleIncomingMetadata(*call_args.client_initial_metadata); - auto* decompress_err = - GetContext()->New>(); - call_args.client_to_server_messages->InterceptAndMap( - [decompress_err, decompress_args, - this](MessageHandle message) -> absl::optional { - auto r = DecompressMessage(std::move(message), decompress_args); - if (grpc_call_trace.enabled()) { - gpr_log(GPR_DEBUG, "%s[compression] DecompressMessage returned %s", - Activity::current()->DebugTag().c_str(), - r.status().ToString().c_str()); - } - if (!r.ok()) { - decompress_err->Set(ServerMetadataFromStatus(r.status())); - return absl::nullopt; - } - return std::move(*r); - }); - auto* compression_algorithm = - GetContext()->New(); - call_args.server_initial_metadata->InterceptAndMap( - [this, compression_algorithm](ServerMetadataHandle md) { - if (grpc_call_trace.enabled()) { - gpr_log(GPR_INFO, "%s[compression] Write metadata", - Activity::current()->DebugTag().c_str()); - } - // Find the compression algorithm. - *compression_algorithm = HandleOutgoingMetadata(*md); - return md; - }); - call_args.server_to_client_messages->InterceptAndMap( - [compression_algorithm, - this](MessageHandle message) -> absl::optional { - return CompressMessage(std::move(message), *compression_algorithm); - }); - // Run the next filter, and race it with getting an error from decompression. - return PrioritizedRace(decompress_err->Wait(), - next_promise_factory(std::move(call_args))); +MessageHandle ServerCompressionFilter::Call::OnServerToClientMessage( + MessageHandle message, ServerCompressionFilter* filter) { + return filter->compression_engine_.CompressMessage(std::move(message), + compression_algorithm_); } } // namespace grpc_core diff --git a/src/core/ext/filters/http/message_compress/compression_filter.h b/src/core/ext/filters/http/message_compress/compression_filter.h index caf49c03336fa..40e88d9b5a8d9 100644 --- a/src/core/ext/filters/http/message_compress/compression_filter.h +++ b/src/core/ext/filters/http/message_compress/compression_filter.h @@ -61,15 +61,15 @@ namespace grpc_core { /// the aforementioned 'grpc-encoding' metadata value, data will pass through /// uncompressed. -class CompressionFilter : public ChannelFilter { - protected: +class ChannelCompression { + public: + explicit ChannelCompression(const ChannelArgs& args); + struct DecompressArgs { grpc_compression_algorithm algorithm; absl::optional max_recv_message_length; }; - explicit CompressionFilter(const ChannelArgs& args); - grpc_compression_algorithm default_compression_algorithm() const { return default_compression_algorithm_; } @@ -104,7 +104,8 @@ class CompressionFilter : public ChannelFilter { bool enable_decompression_; }; -class ClientCompressionFilter final : public CompressionFilter { +class ClientCompressionFilter final + : public ImplementChannelFilter { public: static const grpc_channel_filter kFilter; @@ -112,14 +113,35 @@ class ClientCompressionFilter final : public CompressionFilter { const ChannelArgs& args, ChannelFilter::Args filter_args); // Construct a promise for one call. - ArenaPromise MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) override; + class Call { + public: + void OnClientInitialMetadata(ClientMetadata& md, + ClientCompressionFilter* filter); + MessageHandle OnClientToServerMessage(MessageHandle message, + ClientCompressionFilter* filter); + + void OnServerInitialMetadata(ServerMetadata& md, + ClientCompressionFilter* filter); + absl::StatusOr OnServerToClientMessage( + MessageHandle message, ClientCompressionFilter* filter); + + static const NoInterceptor OnServerTrailingMetadata; + static const NoInterceptor OnFinalize; + + private: + grpc_compression_algorithm compression_algorithm_; + ChannelCompression::DecompressArgs decompress_args_; + }; private: - using CompressionFilter::CompressionFilter; + explicit ClientCompressionFilter(const ChannelArgs& args) + : compression_engine_(args) {} + + ChannelCompression compression_engine_; }; -class ServerCompressionFilter final : public CompressionFilter { +class ServerCompressionFilter final + : public ImplementChannelFilter { public: static const grpc_channel_filter kFilter; @@ -127,11 +149,31 @@ class ServerCompressionFilter final : public CompressionFilter { const ChannelArgs& args, ChannelFilter::Args filter_args); // Construct a promise for one call. - ArenaPromise MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) override; + class Call { + public: + void OnClientInitialMetadata(ClientMetadata& md, + ServerCompressionFilter* filter); + absl::StatusOr OnClientToServerMessage( + MessageHandle message, ServerCompressionFilter* filter); + + void OnServerInitialMetadata(ServerMetadata& md, + ServerCompressionFilter* filter); + MessageHandle OnServerToClientMessage(MessageHandle message, + ServerCompressionFilter* filter); + + static const NoInterceptor OnServerTrailingMetadata; + static const NoInterceptor OnFinalize; + + private: + ChannelCompression::DecompressArgs decompress_args_; + grpc_compression_algorithm compression_algorithm_; + }; private: - using CompressionFilter::CompressionFilter; + explicit ServerCompressionFilter(const ChannelArgs& args) + : compression_engine_(args) {} + + ChannelCompression compression_engine_; }; } // namespace grpc_core diff --git a/src/core/ext/filters/http/message_compress/legacy_compression_filter.cc b/src/core/ext/filters/http/message_compress/legacy_compression_filter.cc new file mode 100644 index 0000000000000..71f9a6d920741 --- /dev/null +++ b/src/core/ext/filters/http/message_compress/legacy_compression_filter.cc @@ -0,0 +1,325 @@ +// Copyright 2022 gRPC authors. +// +// Licensed 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. + +#include + +#include "src/core/ext/filters/http/message_compress/legacy_compression_filter.h" + +#include + +#include +#include +#include + +#include "absl/status/status.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" +#include "absl/types/optional.h" + +#include +#include +#include +#include +#include + +#include "src/core/ext/filters/message_size/message_size_filter.h" +#include "src/core/lib/channel/call_tracer.h" +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/channel/channel_stack.h" +#include "src/core/lib/channel/context.h" +#include "src/core/lib/channel/promise_based_filter.h" +#include "src/core/lib/compression/compression_internal.h" +#include "src/core/lib/compression/message_compress.h" +#include "src/core/lib/debug/trace.h" +#include "src/core/lib/promise/activity.h" +#include "src/core/lib/promise/context.h" +#include "src/core/lib/promise/latch.h" +#include "src/core/lib/promise/pipe.h" +#include "src/core/lib/promise/prioritized_race.h" +#include "src/core/lib/resource_quota/arena.h" +#include "src/core/lib/slice/slice_buffer.h" +#include "src/core/lib/surface/call.h" +#include "src/core/lib/surface/call_trace.h" +#include "src/core/lib/transport/metadata_batch.h" +#include "src/core/lib/transport/transport.h" + +namespace grpc_core { + +const grpc_channel_filter LegacyClientCompressionFilter::kFilter = + MakePromiseBasedFilter< + LegacyClientCompressionFilter, FilterEndpoint::kClient, + kFilterExaminesServerInitialMetadata | kFilterExaminesInboundMessages | + kFilterExaminesOutboundMessages>("compression"); +const grpc_channel_filter LegacyServerCompressionFilter::kFilter = + MakePromiseBasedFilter< + LegacyServerCompressionFilter, FilterEndpoint::kServer, + kFilterExaminesServerInitialMetadata | kFilterExaminesInboundMessages | + kFilterExaminesOutboundMessages>("compression"); + +absl::StatusOr +LegacyClientCompressionFilter::Create(const ChannelArgs& args, + ChannelFilter::Args) { + return LegacyClientCompressionFilter(args); +} + +absl::StatusOr +LegacyServerCompressionFilter::Create(const ChannelArgs& args, + ChannelFilter::Args) { + return LegacyServerCompressionFilter(args); +} + +LegacyCompressionFilter::LegacyCompressionFilter(const ChannelArgs& args) + : max_recv_size_(GetMaxRecvSizeFromChannelArgs(args)), + message_size_service_config_parser_index_( + MessageSizeParser::ParserIndex()), + default_compression_algorithm_( + DefaultCompressionAlgorithmFromChannelArgs(args).value_or( + GRPC_COMPRESS_NONE)), + enabled_compression_algorithms_( + CompressionAlgorithmSet::FromChannelArgs(args)), + enable_compression_( + args.GetBool(GRPC_ARG_ENABLE_PER_MESSAGE_COMPRESSION).value_or(true)), + enable_decompression_( + args.GetBool(GRPC_ARG_ENABLE_PER_MESSAGE_DECOMPRESSION) + .value_or(true)) { + // Make sure the default is enabled. + if (!enabled_compression_algorithms_.IsSet(default_compression_algorithm_)) { + const char* name; + if (!grpc_compression_algorithm_name(default_compression_algorithm_, + &name)) { + name = ""; + } + gpr_log(GPR_ERROR, + "default compression algorithm %s not enabled: switching to none", + name); + default_compression_algorithm_ = GRPC_COMPRESS_NONE; + } +} + +MessageHandle LegacyCompressionFilter::CompressMessage( + MessageHandle message, grpc_compression_algorithm algorithm) const { + if (GRPC_TRACE_FLAG_ENABLED(grpc_compression_trace)) { + gpr_log(GPR_INFO, "CompressMessage: len=%" PRIdPTR " alg=%d flags=%d", + message->payload()->Length(), algorithm, message->flags()); + } + auto* call_context = GetContext(); + auto* call_tracer = static_cast( + call_context[GRPC_CONTEXT_CALL_TRACER].value); + if (call_tracer != nullptr) { + call_tracer->RecordSendMessage(*message->payload()); + } + // Check if we're allowed to compress this message + // (apps might want to disable compression for certain messages to avoid + // crime/beast like vulns). + uint32_t& flags = message->mutable_flags(); + if (algorithm == GRPC_COMPRESS_NONE || !enable_compression_ || + (flags & (GRPC_WRITE_NO_COMPRESS | GRPC_WRITE_INTERNAL_COMPRESS))) { + return message; + } + // Try to compress the payload. + SliceBuffer tmp; + SliceBuffer* payload = message->payload(); + bool did_compress = grpc_msg_compress(algorithm, payload->c_slice_buffer(), + tmp.c_slice_buffer()); + // If we achieved compression send it as compressed, otherwise send it as (to + // avoid spending cycles on the receiver decompressing). + if (did_compress) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_compression_trace)) { + const char* algo_name; + const size_t before_size = payload->Length(); + const size_t after_size = tmp.Length(); + const float savings_ratio = 1.0f - static_cast(after_size) / + static_cast(before_size); + GPR_ASSERT(grpc_compression_algorithm_name(algorithm, &algo_name)); + gpr_log(GPR_INFO, + "Compressed[%s] %" PRIuPTR " bytes vs. %" PRIuPTR + " bytes (%.2f%% savings)", + algo_name, before_size, after_size, 100 * savings_ratio); + } + tmp.Swap(payload); + flags |= GRPC_WRITE_INTERNAL_COMPRESS; + if (call_tracer != nullptr) { + call_tracer->RecordSendCompressedMessage(*message->payload()); + } + } else { + if (GRPC_TRACE_FLAG_ENABLED(grpc_compression_trace)) { + const char* algo_name; + GPR_ASSERT(grpc_compression_algorithm_name(algorithm, &algo_name)); + gpr_log(GPR_INFO, + "Algorithm '%s' enabled but decided not to compress. Input size: " + "%" PRIuPTR, + algo_name, payload->Length()); + } + } + return message; +} + +absl::StatusOr LegacyCompressionFilter::DecompressMessage( + MessageHandle message, DecompressArgs args) const { + if (GRPC_TRACE_FLAG_ENABLED(grpc_compression_trace)) { + gpr_log(GPR_INFO, "DecompressMessage: len=%" PRIdPTR " max=%d alg=%d", + message->payload()->Length(), + args.max_recv_message_length.value_or(-1), args.algorithm); + } + auto* call_context = GetContext(); + auto* call_tracer = static_cast( + call_context[GRPC_CONTEXT_CALL_TRACER].value); + if (call_tracer != nullptr) { + call_tracer->RecordReceivedMessage(*message->payload()); + } + // Check max message length. + if (args.max_recv_message_length.has_value() && + message->payload()->Length() > + static_cast(*args.max_recv_message_length)) { + return absl::ResourceExhaustedError(absl::StrFormat( + "Received message larger than max (%u vs. %d)", + message->payload()->Length(), *args.max_recv_message_length)); + } + // Check if decompression is enabled (if not, we can just pass the message + // up). + if (!enable_decompression_ || + (message->flags() & GRPC_WRITE_INTERNAL_COMPRESS) == 0) { + return std::move(message); + } + // Try to decompress the payload. + SliceBuffer decompressed_slices; + if (grpc_msg_decompress(args.algorithm, message->payload()->c_slice_buffer(), + decompressed_slices.c_slice_buffer()) == 0) { + return absl::InternalError( + absl::StrCat("Unexpected error decompressing data for algorithm ", + CompressionAlgorithmAsString(args.algorithm))); + } + // Swap the decompressed slices into the message. + message->payload()->Swap(&decompressed_slices); + message->mutable_flags() &= ~GRPC_WRITE_INTERNAL_COMPRESS; + message->mutable_flags() |= GRPC_WRITE_INTERNAL_TEST_ONLY_WAS_COMPRESSED; + if (call_tracer != nullptr) { + call_tracer->RecordReceivedDecompressedMessage(*message->payload()); + } + return std::move(message); +} + +grpc_compression_algorithm LegacyCompressionFilter::HandleOutgoingMetadata( + grpc_metadata_batch& outgoing_metadata) { + const auto algorithm = outgoing_metadata.Take(GrpcInternalEncodingRequest()) + .value_or(default_compression_algorithm()); + // Convey supported compression algorithms. + outgoing_metadata.Set(GrpcAcceptEncodingMetadata(), + enabled_compression_algorithms()); + if (algorithm != GRPC_COMPRESS_NONE) { + outgoing_metadata.Set(GrpcEncodingMetadata(), algorithm); + } + return algorithm; +} + +LegacyCompressionFilter::DecompressArgs +LegacyCompressionFilter::HandleIncomingMetadata( + const grpc_metadata_batch& incoming_metadata) { + // Configure max receive size. + auto max_recv_message_length = max_recv_size_; + const MessageSizeParsedConfig* limits = + MessageSizeParsedConfig::GetFromCallContext( + GetContext(), + message_size_service_config_parser_index_); + if (limits != nullptr && limits->max_recv_size().has_value() && + (!max_recv_message_length.has_value() || + *limits->max_recv_size() < *max_recv_message_length)) { + max_recv_message_length = *limits->max_recv_size(); + } + return DecompressArgs{incoming_metadata.get(GrpcEncodingMetadata()) + .value_or(GRPC_COMPRESS_NONE), + max_recv_message_length}; +} + +ArenaPromise +LegacyClientCompressionFilter::MakeCallPromise( + CallArgs call_args, NextPromiseFactory next_promise_factory) { + auto compression_algorithm = + HandleOutgoingMetadata(*call_args.client_initial_metadata); + call_args.client_to_server_messages->InterceptAndMap( + [compression_algorithm, + this](MessageHandle message) -> absl::optional { + return CompressMessage(std::move(message), compression_algorithm); + }); + auto* decompress_args = GetContext()->New( + DecompressArgs{GRPC_COMPRESS_ALGORITHMS_COUNT, absl::nullopt}); + auto* decompress_err = + GetContext()->New>(); + call_args.server_initial_metadata->InterceptAndMap( + [decompress_args, this](ServerMetadataHandle server_initial_metadata) + -> absl::optional { + if (server_initial_metadata == nullptr) return absl::nullopt; + *decompress_args = HandleIncomingMetadata(*server_initial_metadata); + return std::move(server_initial_metadata); + }); + call_args.server_to_client_messages->InterceptAndMap( + [decompress_err, decompress_args, + this](MessageHandle message) -> absl::optional { + auto r = DecompressMessage(std::move(message), *decompress_args); + if (!r.ok()) { + decompress_err->Set(ServerMetadataFromStatus(r.status())); + return absl::nullopt; + } + return std::move(*r); + }); + // Run the next filter, and race it with getting an error from decompression. + return PrioritizedRace(decompress_err->Wait(), + next_promise_factory(std::move(call_args))); +} + +ArenaPromise +LegacyServerCompressionFilter::MakeCallPromise( + CallArgs call_args, NextPromiseFactory next_promise_factory) { + auto decompress_args = + HandleIncomingMetadata(*call_args.client_initial_metadata); + auto* decompress_err = + GetContext()->New>(); + call_args.client_to_server_messages->InterceptAndMap( + [decompress_err, decompress_args, + this](MessageHandle message) -> absl::optional { + auto r = DecompressMessage(std::move(message), decompress_args); + if (grpc_call_trace.enabled()) { + gpr_log(GPR_DEBUG, "%s[compression] DecompressMessage returned %s", + Activity::current()->DebugTag().c_str(), + r.status().ToString().c_str()); + } + if (!r.ok()) { + decompress_err->Set(ServerMetadataFromStatus(r.status())); + return absl::nullopt; + } + return std::move(*r); + }); + auto* compression_algorithm = + GetContext()->New(); + call_args.server_initial_metadata->InterceptAndMap( + [this, compression_algorithm](ServerMetadataHandle md) { + if (grpc_call_trace.enabled()) { + gpr_log(GPR_INFO, "%s[compression] Write metadata", + Activity::current()->DebugTag().c_str()); + } + // Find the compression algorithm. + *compression_algorithm = HandleOutgoingMetadata(*md); + return md; + }); + call_args.server_to_client_messages->InterceptAndMap( + [compression_algorithm, + this](MessageHandle message) -> absl::optional { + return CompressMessage(std::move(message), *compression_algorithm); + }); + // Run the next filter, and race it with getting an error from decompression. + return PrioritizedRace(decompress_err->Wait(), + next_promise_factory(std::move(call_args))); +} + +} // namespace grpc_core diff --git a/src/core/ext/filters/http/message_compress/legacy_compression_filter.h b/src/core/ext/filters/http/message_compress/legacy_compression_filter.h new file mode 100644 index 0000000000000..0926bc09ed903 --- /dev/null +++ b/src/core/ext/filters/http/message_compress/legacy_compression_filter.h @@ -0,0 +1,139 @@ +// +// +// Copyright 2020 gRPC authors. +// +// Licensed 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 GRPC_SRC_CORE_EXT_FILTERS_HTTP_MESSAGE_COMPRESS_LEGACY_COMPRESSION_FILTER_H +#define GRPC_SRC_CORE_EXT_FILTERS_HTTP_MESSAGE_COMPRESS_LEGACY_COMPRESSION_FILTER_H + +#include + +#include +#include + +#include "absl/status/statusor.h" +#include "absl/types/optional.h" + +#include + +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/channel/channel_fwd.h" +#include "src/core/lib/channel/promise_based_filter.h" +#include "src/core/lib/compression/compression_internal.h" +#include "src/core/lib/promise/arena_promise.h" +#include "src/core/lib/transport/metadata_batch.h" +#include "src/core/lib/transport/transport.h" + +namespace grpc_core { + +/// Compression filter for messages. +/// +/// See for the available compression settings. +/// +/// Compression settings may come from: +/// - Channel configuration, as established at channel creation time. +/// - The metadata accompanying the outgoing data to be compressed. This is +/// taken as a request only. We may choose not to honor it. The metadata key +/// is given by \a GRPC_COMPRESSION_REQUEST_ALGORITHM_MD_KEY. +/// +/// Compression can be disabled for concrete messages (for instance in order to +/// prevent CRIME/BEAST type attacks) by having the GRPC_WRITE_NO_COMPRESS set +/// in the MessageHandle flags. +/// +/// The attempted compression mechanism is added to the resulting initial +/// metadata under the 'grpc-encoding' key. +/// +/// If compression is actually performed, the MessageHandle's flag is modified +/// to incorporate GRPC_WRITE_INTERNAL_COMPRESS. Otherwise, and regardless of +/// the aforementioned 'grpc-encoding' metadata value, data will pass through +/// uncompressed. + +class LegacyCompressionFilter : public ChannelFilter { + protected: + struct DecompressArgs { + grpc_compression_algorithm algorithm; + absl::optional max_recv_message_length; + }; + + explicit LegacyCompressionFilter(const ChannelArgs& args); + + grpc_compression_algorithm default_compression_algorithm() const { + return default_compression_algorithm_; + } + + CompressionAlgorithmSet enabled_compression_algorithms() const { + return enabled_compression_algorithms_; + } + + grpc_compression_algorithm HandleOutgoingMetadata( + grpc_metadata_batch& outgoing_metadata); + DecompressArgs HandleIncomingMetadata( + const grpc_metadata_batch& incoming_metadata); + + // Compress one message synchronously. + MessageHandle CompressMessage(MessageHandle message, + grpc_compression_algorithm algorithm) const; + // Decompress one message synchronously. + absl::StatusOr DecompressMessage(MessageHandle message, + DecompressArgs args) const; + + private: + // Max receive message length, if set. + absl::optional max_recv_size_; + size_t message_size_service_config_parser_index_; + // The default, channel-level, compression algorithm. + grpc_compression_algorithm default_compression_algorithm_; + // Enabled compression algorithms. + CompressionAlgorithmSet enabled_compression_algorithms_; + // Is compression enabled? + bool enable_compression_; + // Is decompression enabled? + bool enable_decompression_; +}; + +class LegacyClientCompressionFilter final : public LegacyCompressionFilter { + public: + static const grpc_channel_filter kFilter; + + static absl::StatusOr Create( + const ChannelArgs& args, ChannelFilter::Args filter_args); + + // Construct a promise for one call. + ArenaPromise MakeCallPromise( + CallArgs call_args, NextPromiseFactory next_promise_factory) override; + + private: + using LegacyCompressionFilter::LegacyCompressionFilter; +}; + +class LegacyServerCompressionFilter final : public LegacyCompressionFilter { + public: + static const grpc_channel_filter kFilter; + + static absl::StatusOr Create( + const ChannelArgs& args, ChannelFilter::Args filter_args); + + // Construct a promise for one call. + ArenaPromise MakeCallPromise( + CallArgs call_args, NextPromiseFactory next_promise_factory) override; + + private: + using LegacyCompressionFilter::LegacyCompressionFilter; +}; + +} // namespace grpc_core + +#endif // GRPC_SRC_CORE_EXT_FILTERS_HTTP_MESSAGE_COMPRESS_LEGACY_COMPRESSION_FILTER_H diff --git a/src/core/lib/channel/promise_based_filter.h b/src/core/lib/channel/promise_based_filter.h index ad33f366378cd..b455ab869b992 100644 --- a/src/core/lib/channel/promise_based_filter.h +++ b/src/core/lib/channel/promise_based_filter.h @@ -139,11 +139,21 @@ inline constexpr bool HasAsyncErrorInterceptor(const NoInterceptor*) { return false; } +template +inline constexpr bool HasAsyncErrorInterceptor(A0 (T::*)(A0, As...)) { + return false; +} + template inline constexpr bool HasAsyncErrorInterceptor(absl::Status (T::*)(A...)) { return true; } +template +inline constexpr bool HasAsyncErrorInterceptor(absl::StatusOr (T::*)(A...)) { + return true; +} + template inline constexpr bool HasAsyncErrorInterceptor( ServerMetadataHandle (T::*)(A...)) { @@ -404,6 +414,34 @@ inline void InterceptClientToServerMessage( }); } +template +inline void InterceptClientToServerMessage( + MessageHandle (Derived::Call::*fn)(MessageHandle, Derived*), + FilterCallData* call_data, const CallArgs& call_args) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnClientToServerMessage); + call_args.client_to_server_messages->InterceptAndMap( + [call_data](MessageHandle msg) -> absl::optional { + return call_data->call.OnClientToServerMessage(std::move(msg), + call_data->channel); + }); +} + +template +inline void InterceptClientToServerMessage( + absl::StatusOr (Derived::Call::*fn)(MessageHandle, Derived*), + FilterCallData* call_data, const CallArgs& call_args) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnClientToServerMessage); + call_args.client_to_server_messages->InterceptAndMap( + [call_data](MessageHandle msg) -> absl::optional { + auto r = call_data->call.OnClientToServerMessage(std::move(msg), + call_data->channel); + if (r.ok()) return std::move(*r); + if (call_data->error_latch.is_set()) return absl::nullopt; + call_data->error_latch.Set(ServerMetadataFromStatus(r.status())); + return absl::nullopt; + }); +} + inline void InterceptClientToServerMessage(const NoInterceptor*, void*, void*, CallSpineInterface*) {} @@ -412,7 +450,7 @@ inline void InterceptClientToServerMessage( ServerMetadataHandle (Derived::Call::*fn)(const Message&), typename Derived::Call* call, Derived*, CallSpineInterface* call_spine) { GPR_DEBUG_ASSERT(fn == &Derived::Call::OnClientToServerMessage); - call_spine->server_to_client_messages().sender.InterceptAndMap( + call_spine->client_to_server_messages().receiver.InterceptAndMap( [call, call_spine](MessageHandle msg) -> absl::optional { auto return_md = call->OnClientToServerMessage(*msg); if (return_md == nullptr) return std::move(msg); @@ -426,7 +464,7 @@ inline void InterceptClientToServerMessage( typename Derived::Call* call, Derived* channel, CallSpineInterface* call_spine) { GPR_DEBUG_ASSERT(fn == &Derived::Call::OnClientToServerMessage); - call_spine->server_to_client_messages().sender.InterceptAndMap( + call_spine->client_to_server_messages().receiver.InterceptAndMap( [call, call_spine, channel](MessageHandle msg) -> absl::optional { auto return_md = call->OnClientToServerMessage(*msg, channel); @@ -435,6 +473,33 @@ inline void InterceptClientToServerMessage( }); } +template +inline void InterceptClientToServerMessage( + MessageHandle (Derived::Call::*fn)(MessageHandle, Derived*), + typename Derived::Call* call, Derived* channel, + CallSpineInterface* call_spine) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnClientToServerMessage); + call_spine->client_to_server_messages().receiver.InterceptAndMap( + [call, channel](MessageHandle msg) { + return call->OnClientToServerMessage(std::move(msg), channel); + }); +} + +template +inline void InterceptClientToServerMessage( + absl::StatusOr (Derived::Call::*fn)(MessageHandle, Derived*), + typename Derived::Call* call, Derived* channel, + CallSpineInterface* call_spine) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnClientToServerMessage); + call_spine->client_to_server_messages().receiver.InterceptAndMap( + [call, call_spine, + channel](MessageHandle msg) -> absl::optional { + auto r = call->OnClientToServerMessage(std::move(msg), channel); + if (r.ok()) return std::move(*r); + return call_spine->Cancel(ServerMetadataFromStatus(r.status())); + }); +} + inline void InterceptClientInitialMetadata(const NoInterceptor*, void*, void*, CallSpineInterface*) {} @@ -526,6 +591,36 @@ inline void InterceptServerInitialMetadata( }); } +template +inline void InterceptServerInitialMetadata( + void (Derived::Call::*fn)(ServerMetadata&, Derived*), + FilterCallData* call_data, const CallArgs& call_args) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnServerInitialMetadata); + call_args.server_initial_metadata->InterceptAndMap( + [call_data](ServerMetadataHandle md) { + call_data->call.OnServerInitialMetadata(*md, call_data->channel); + return md; + }); +} + +template +inline void InterceptServerInitialMetadata( + absl::Status (Derived::Call::*fn)(ServerMetadata&, Derived*), + FilterCallData* call_data, const CallArgs& call_args) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnServerInitialMetadata); + call_args.server_initial_metadata->InterceptAndMap( + [call_data]( + ServerMetadataHandle md) -> absl::optional { + auto status = + call_data->call.OnServerInitialMetadata(*md, call_data->channel); + if (!status.ok() && !call_data->error_latch.is_set()) { + call_data->error_latch.Set(ServerMetadataFromStatus(status)); + return absl::nullopt; + } + return std::move(md); + }); +} + inline void InterceptServerInitialMetadata(const NoInterceptor*, void*, void*, CallSpineInterface*) {} @@ -555,6 +650,34 @@ inline void InterceptServerInitialMetadata( }); } +template +inline void InterceptServerInitialMetadata( + void (Derived::Call::*fn)(ServerMetadata&, Derived*), + typename Derived::Call* call, Derived* channel, + CallSpineInterface* call_spine) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnServerInitialMetadata); + call_spine->server_initial_metadata().sender.InterceptAndMap( + [call, channel](ServerMetadataHandle md) { + call->OnServerInitialMetadata(*md, channel); + return md; + }); +} + +template +inline void InterceptServerInitialMetadata( + absl::Status (Derived::Call::*fn)(ServerMetadata&, Derived*), + typename Derived::Call* call, Derived* channel, + CallSpineInterface* call_spine) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnServerInitialMetadata); + call_spine->server_initial_metadata().sender.InterceptAndMap( + [call, call_spine, channel]( + ServerMetadataHandle md) -> absl::optional { + auto status = call->OnServerInitialMetadata(*md, channel); + if (status.ok()) return std::move(md); + return call_spine->Cancel(ServerMetadataFromStatus(status)); + }); +} + inline void InterceptServerToClientMessage(const NoInterceptor*, void*, const CallArgs&) {} @@ -589,6 +712,34 @@ inline void InterceptServerToClientMessage( }); } +template +inline void InterceptServerToClientMessage( + MessageHandle (Derived::Call::*fn)(MessageHandle, Derived*), + FilterCallData* call_data, const CallArgs& call_args) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnServerToClientMessage); + call_args.server_to_client_messages->InterceptAndMap( + [call_data](MessageHandle msg) -> absl::optional { + return call_data->call.OnServerToClientMessage(std::move(msg), + call_data->channel); + }); +} + +template +inline void InterceptServerToClientMessage( + absl::StatusOr (Derived::Call::*fn)(MessageHandle, Derived*), + FilterCallData* call_data, const CallArgs& call_args) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnServerToClientMessage); + call_args.server_to_client_messages->InterceptAndMap( + [call_data](MessageHandle msg) -> absl::optional { + auto r = call_data->call.OnServerToClientMessage(std::move(msg), + call_data->channel); + if (r.ok()) return std::move(*r); + if (call_data->error_latch.is_set()) return absl::nullopt; + call_data->error_latch.Set(ServerMetadataFromStatus(r.status())); + return absl::nullopt; + }); +} + inline void InterceptServerToClientMessage(const NoInterceptor*, void*, void*, CallSpineInterface*) {} @@ -620,6 +771,33 @@ inline void InterceptServerToClientMessage( }); } +template +inline void InterceptServerToClientMessage( + MessageHandle (Derived::Call::*fn)(MessageHandle, Derived*), + typename Derived::Call* call, Derived* channel, + CallSpineInterface* call_spine) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnServerToClientMessage); + call_spine->server_to_client_messages().sender.InterceptAndMap( + [call, channel](MessageHandle msg) { + return call->OnServerToClientMessage(std::move(msg), channel); + }); +} + +template +inline void InterceptServerToClientMessage( + absl::StatusOr (Derived::Call::*fn)(MessageHandle, Derived*), + typename Derived::Call* call, Derived* channel, + CallSpineInterface* call_spine) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnServerToClientMessage); + call_spine->server_to_client_messages().sender.InterceptAndMap( + [call, call_spine, + channel](MessageHandle msg) -> absl::optional { + auto r = call->OnServerToClientMessage(std::move(msg), channel); + if (r.ok()) return std::move(*r); + return call_spine->Cancel(ServerMetadataFromStatus(r.status())); + }); +} + inline void InterceptServerTrailingMetadata(const NoInterceptor*, void*, void*, CallSpineInterface*) {} diff --git a/src/core/lib/experiments/experiments.cc b/src/core/lib/experiments/experiments.cc index a49b5554e88bd..9141512058514 100644 --- a/src/core/lib/experiments/experiments.cc +++ b/src/core/lib/experiments/experiments.cc @@ -155,6 +155,9 @@ const char* const additional_constraints_unconstrained_max_quota_buffer_size = const char* const description_v3_channel_idle_filters = "Use the v3 filter API version of the idle filters."; const char* const additional_constraints_v3_channel_idle_filters = "{}"; +const char* const description_v3_compression_filter = + "Use the compression filter utilizing the v3 filter api"; +const char* const additional_constraints_v3_compression_filter = "{}"; const char* const description_work_serializer_clears_time_cache = "Have the work serializer clear the time cache when it dispatches work."; const char* const additional_constraints_work_serializer_clears_time_cache = @@ -269,6 +272,8 @@ const ExperimentMetadata g_experiment_metadata[] = { false, true}, {"v3_channel_idle_filters", description_v3_channel_idle_filters, additional_constraints_v3_channel_idle_filters, nullptr, 0, false, true}, + {"v3_compression_filter", description_v3_compression_filter, + additional_constraints_v3_compression_filter, nullptr, 0, false, true}, {"work_serializer_clears_time_cache", description_work_serializer_clears_time_cache, additional_constraints_work_serializer_clears_time_cache, nullptr, 0, true, @@ -419,6 +424,9 @@ const char* const additional_constraints_unconstrained_max_quota_buffer_size = const char* const description_v3_channel_idle_filters = "Use the v3 filter API version of the idle filters."; const char* const additional_constraints_v3_channel_idle_filters = "{}"; +const char* const description_v3_compression_filter = + "Use the compression filter utilizing the v3 filter api"; +const char* const additional_constraints_v3_compression_filter = "{}"; const char* const description_work_serializer_clears_time_cache = "Have the work serializer clear the time cache when it dispatches work."; const char* const additional_constraints_work_serializer_clears_time_cache = @@ -533,6 +541,8 @@ const ExperimentMetadata g_experiment_metadata[] = { false, true}, {"v3_channel_idle_filters", description_v3_channel_idle_filters, additional_constraints_v3_channel_idle_filters, nullptr, 0, false, true}, + {"v3_compression_filter", description_v3_compression_filter, + additional_constraints_v3_compression_filter, nullptr, 0, false, true}, {"work_serializer_clears_time_cache", description_work_serializer_clears_time_cache, additional_constraints_work_serializer_clears_time_cache, nullptr, 0, true, @@ -683,6 +693,9 @@ const char* const additional_constraints_unconstrained_max_quota_buffer_size = const char* const description_v3_channel_idle_filters = "Use the v3 filter API version of the idle filters."; const char* const additional_constraints_v3_channel_idle_filters = "{}"; +const char* const description_v3_compression_filter = + "Use the compression filter utilizing the v3 filter api"; +const char* const additional_constraints_v3_compression_filter = "{}"; const char* const description_work_serializer_clears_time_cache = "Have the work serializer clear the time cache when it dispatches work."; const char* const additional_constraints_work_serializer_clears_time_cache = @@ -797,6 +810,8 @@ const ExperimentMetadata g_experiment_metadata[] = { false, true}, {"v3_channel_idle_filters", description_v3_channel_idle_filters, additional_constraints_v3_channel_idle_filters, nullptr, 0, false, true}, + {"v3_compression_filter", description_v3_compression_filter, + additional_constraints_v3_compression_filter, nullptr, 0, false, true}, {"work_serializer_clears_time_cache", description_work_serializer_clears_time_cache, additional_constraints_work_serializer_clears_time_cache, nullptr, 0, true, diff --git a/src/core/lib/experiments/experiments.h b/src/core/lib/experiments/experiments.h index 2e680ac8ead8d..d337d9da2fa92 100644 --- a/src/core/lib/experiments/experiments.h +++ b/src/core/lib/experiments/experiments.h @@ -108,6 +108,7 @@ inline bool IsTcpRcvLowatEnabled() { return false; } inline bool IsTraceRecordCallopsEnabled() { return false; } inline bool IsUnconstrainedMaxQuotaBufferSizeEnabled() { return false; } inline bool IsV3ChannelIdleFiltersEnabled() { return false; } +inline bool IsV3CompressionFilterEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_WORK_SERIALIZER_CLEARS_TIME_CACHE inline bool IsWorkSerializerClearsTimeCacheEnabled() { return true; } inline bool IsWorkSerializerDispatchEnabled() { return false; } @@ -171,6 +172,7 @@ inline bool IsTcpRcvLowatEnabled() { return false; } inline bool IsTraceRecordCallopsEnabled() { return false; } inline bool IsUnconstrainedMaxQuotaBufferSizeEnabled() { return false; } inline bool IsV3ChannelIdleFiltersEnabled() { return false; } +inline bool IsV3CompressionFilterEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_WORK_SERIALIZER_CLEARS_TIME_CACHE inline bool IsWorkSerializerClearsTimeCacheEnabled() { return true; } inline bool IsWorkSerializerDispatchEnabled() { return false; } @@ -234,6 +236,7 @@ inline bool IsTcpRcvLowatEnabled() { return false; } inline bool IsTraceRecordCallopsEnabled() { return false; } inline bool IsUnconstrainedMaxQuotaBufferSizeEnabled() { return false; } inline bool IsV3ChannelIdleFiltersEnabled() { return false; } +inline bool IsV3CompressionFilterEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_WORK_SERIALIZER_CLEARS_TIME_CACHE inline bool IsWorkSerializerClearsTimeCacheEnabled() { return true; } inline bool IsWorkSerializerDispatchEnabled() { return false; } @@ -281,6 +284,7 @@ enum ExperimentIds { kExperimentIdTraceRecordCallops, kExperimentIdUnconstrainedMaxQuotaBufferSize, kExperimentIdV3ChannelIdleFilters, + kExperimentIdV3CompressionFilter, kExperimentIdWorkSerializerClearsTimeCache, kExperimentIdWorkSerializerDispatch, kExperimentIdWriteSizePolicy, @@ -424,6 +428,10 @@ inline bool IsUnconstrainedMaxQuotaBufferSizeEnabled() { inline bool IsV3ChannelIdleFiltersEnabled() { return IsExperimentEnabled(kExperimentIdV3ChannelIdleFilters); } +#define GRPC_EXPERIMENT_IS_INCLUDED_V3_COMPRESSION_FILTER +inline bool IsV3CompressionFilterEnabled() { + return IsExperimentEnabled(kExperimentIdV3CompressionFilter); +} #define GRPC_EXPERIMENT_IS_INCLUDED_WORK_SERIALIZER_CLEARS_TIME_CACHE inline bool IsWorkSerializerClearsTimeCacheEnabled() { return IsExperimentEnabled(kExperimentIdWorkSerializerClearsTimeCache); diff --git a/src/core/lib/experiments/experiments.yaml b/src/core/lib/experiments/experiments.yaml index d42e14ee34af0..8fd03836ea966 100644 --- a/src/core/lib/experiments/experiments.yaml +++ b/src/core/lib/experiments/experiments.yaml @@ -259,6 +259,12 @@ expiry: 2024/04/04 owner: ctiller@google.com test_tags: [] +- name: v3_compression_filter + description: + Use the compression filter utilizing the v3 filter api + expiry: 2024/04/04 + owner: ctiller@google.com + test_tags: ["compression_test"] - name: work_serializer_clears_time_cache description: Have the work serializer clear the time cache when it dispatches work. diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index c0439924822f1..9c2ba0008a52f 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -89,6 +89,7 @@ 'src/core/ext/filters/http/client_authority_filter.cc', 'src/core/ext/filters/http/http_filters_plugin.cc', 'src/core/ext/filters/http/message_compress/compression_filter.cc', + 'src/core/ext/filters/http/message_compress/legacy_compression_filter.cc', 'src/core/ext/filters/http/server/http_server_filter.cc', 'src/core/ext/filters/message_size/message_size_filter.cc', 'src/core/ext/filters/rbac/rbac_filter.cc', diff --git a/test/core/end2end/BUILD b/test/core/end2end/BUILD index 01ebf2b961556..98cbf78d953c8 100644 --- a/test/core/end2end/BUILD +++ b/test/core/end2end/BUILD @@ -286,7 +286,10 @@ grpc_core_end2end_test(name = "channelz") grpc_core_end2end_test(name = "client_streaming") -grpc_core_end2end_test(name = "compressed_payload") +grpc_core_end2end_test( + name = "compressed_payload", + tags = ["compression_test"], +) grpc_core_end2end_test(name = "connectivity") diff --git a/test/core/end2end/grpc_core_end2end_test.bzl b/test/core/end2end/grpc_core_end2end_test.bzl index 16f193bc19794..9b1224db84adb 100644 --- a/test/core/end2end/grpc_core_end2end_test.bzl +++ b/test/core/end2end/grpc_core_end2end_test.bzl @@ -25,7 +25,7 @@ END2END_TEST_DATA = [ "//src/core/tsi/test_creds:server1.pem", ] -def grpc_core_end2end_test(name, shard_count = 10): +def grpc_core_end2end_test(name, shard_count = 10, tags = []): if len(name) > 60: fail("test name %s too long" % name) @@ -45,7 +45,7 @@ def grpc_core_end2end_test(name, shard_count = 10): "absl/types:optional", "gtest", ], - tags = ["core_end2end_test"], + tags = ["core_end2end_test"] + tags, deps = [ "end2end_test_main", "cq_verifier", diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index b465d10a27151..a173512c3ce5c 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -1215,6 +1215,8 @@ src/core/ext/filters/http/client_authority_filter.h \ src/core/ext/filters/http/http_filters_plugin.cc \ src/core/ext/filters/http/message_compress/compression_filter.cc \ src/core/ext/filters/http/message_compress/compression_filter.h \ +src/core/ext/filters/http/message_compress/legacy_compression_filter.cc \ +src/core/ext/filters/http/message_compress/legacy_compression_filter.h \ src/core/ext/filters/http/server/http_server_filter.cc \ src/core/ext/filters/http/server/http_server_filter.h \ src/core/ext/filters/message_size/message_size_filter.cc \ diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 7a3ea87d2ac6a..ae89c4707ccdd 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -1024,6 +1024,8 @@ src/core/ext/filters/http/client_authority_filter.h \ src/core/ext/filters/http/http_filters_plugin.cc \ src/core/ext/filters/http/message_compress/compression_filter.cc \ src/core/ext/filters/http/message_compress/compression_filter.h \ +src/core/ext/filters/http/message_compress/legacy_compression_filter.cc \ +src/core/ext/filters/http/message_compress/legacy_compression_filter.h \ src/core/ext/filters/http/server/http_server_filter.cc \ src/core/ext/filters/http/server/http_server_filter.h \ src/core/ext/filters/message_size/message_size_filter.cc \ From 9118cb1a55461c47f4afc2a5de75c1dc37dea6fb Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Mon, 11 Dec 2023 20:18:16 -0800 Subject: [PATCH 079/127] Fix fuzzer bug b/309716763 (#35278) Also cleanup a little so we're not copying redundant frame headers everywhere. Closes #35278 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35278 from ctiller:fuzz-309716763 52589ff422c6cf520c4d54bfd864468db2b7b33a PiperOrigin-RevId: 590042072 --- CMakeLists.txt | 2 +- build_autogenerated.yaml | 3 +- src/core/BUILD | 1 + .../chaotic_good/client_transport.cc | 12 ++-- .../transport/chaotic_good/client_transport.h | 65 +++++++++--------- src/core/ext/transport/chaotic_good/frame.cc | 65 ++++++++++++++---- src/core/ext/transport/chaotic_good/frame.h | 18 +++-- .../transport/chaotic_good/frame_header.cc | 18 ++++- .../ext/transport/chaotic_good/frame_header.h | 14 ++-- .../transport/chaotic_good/frame_fuzzer.cc | 10 ++- .../frame_fuzzer_corpus/5072496117219328 | Bin 0 -> 26 bytes 11 files changed, 135 insertions(+), 73 deletions(-) create mode 100644 test/core/transport/chaotic_good/frame_fuzzer_corpus/5072496117219328 diff --git a/CMakeLists.txt b/CMakeLists.txt index 90f0b5d3a4a7a..bef30891364a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12503,8 +12503,8 @@ target_include_directories(frame_header_test target_link_libraries(frame_header_test ${_gRPC_ALLTARGETS_LIBRARIES} gtest - absl::status absl::statusor + gpr ) diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index 1aeb1ad9026ae..bff13ebb1eef0 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -9610,15 +9610,14 @@ targets: language: c++ headers: - src/core/ext/transport/chaotic_good/frame_header.h - - src/core/lib/gpr/useful.h - src/core/lib/gprpp/bitset.h src: - src/core/ext/transport/chaotic_good/frame_header.cc - test/core/transport/chaotic_good/frame_header_test.cc deps: - gtest - - absl/status:status - absl/status:statusor + - gpr - name: fuzzing_event_engine_test gtest: true build: test diff --git a/src/core/BUILD b/src/core/BUILD index e5ad5240aea68..bbdba17e48679 100644 --- a/src/core/BUILD +++ b/src/core/BUILD @@ -6214,6 +6214,7 @@ grpc_cc_library( ], deps = [ "bitset", + "//:gpr", "//:gpr_platform", ], ) diff --git a/src/core/ext/transport/chaotic_good/client_transport.cc b/src/core/ext/transport/chaotic_good/client_transport.cc index 686a024827bf0..e958b03a7d88d 100644 --- a/src/core/ext/transport/chaotic_good/client_transport.cc +++ b/src/core/ext/transport/chaotic_good/client_transport.cc @@ -16,6 +16,7 @@ #include "src/core/ext/transport/chaotic_good/client_transport.h" +#include #include #include #include @@ -77,8 +78,7 @@ ClientTransport::ClientTransport( control_endpoint_write_buffer_.Append( frame->Serialize(hpack_compressor_.get())); if (frame->message != nullptr) { - std::string message_padding( - frame->frame_header.message_padding, '0'); + std::string message_padding(frame->message_padding, '0'); Slice slice(grpc_slice_from_cpp_string(message_padding)); // Append message padding to data_endpoint_buffer. data_endpoint_write_buffer_.Append(std::move(slice)); @@ -157,11 +157,9 @@ ClientTransport::ClientTransport( // Move message into frame. frame.message = arena_->MakePooled( std::move(data_endpoint_read_buffer_), 0); - auto stream_id = frame.frame_header.stream_id; - { - MutexLock lock(&mu_); - return stream_map_[stream_id]->Push(ServerFrame(std::move(frame))); - } + MutexLock lock(&mu_); + const uint32_t stream_id = frame_header_->stream_id; + return stream_map_[stream_id]->Push(ServerFrame(std::move(frame))); }, // Check if send frame to corresponding stream successfully. [](bool ret) -> LoopCtl { diff --git a/src/core/ext/transport/chaotic_good/client_transport.h b/src/core/ext/transport/chaotic_good/client_transport.h index 4972630cf9cc6..86f9072fcfc34 100644 --- a/src/core/ext/transport/chaotic_good/client_transport.h +++ b/src/core/ext/transport/chaotic_good/client_transport.h @@ -107,40 +107,37 @@ class ClientTransport { return TrySeq( TryJoin( // Continuously send client frame with client to server messages. - ForEach( - std::move(*call_args.client_to_server_messages), - [stream_id, initial_frame = true, - client_initial_metadata = - std::move(call_args.client_initial_metadata), - outgoing_frames = outgoing_frames_.MakeSender(), - this](MessageHandle result) mutable { - ClientFragmentFrame frame; - // Construct frame header (flags, header_length and - // trailer_length will be added in serialization). - uint32_t message_length = result->payload()->Length(); - uint32_t message_padding = message_length % aligned_bytes; - frame.frame_header = FrameHeader{ - FrameType::kFragment, {}, stream_id, 0, message_length, - message_padding, 0}; - frame.message = std::move(result); - if (initial_frame) { - // Send initial frame with client intial metadata. - frame.headers = std::move(client_initial_metadata); - initial_frame = false; - } - return TrySeq( - outgoing_frames.Send(ClientFrame(std::move(frame))), - [](bool success) -> absl::Status { - if (!success) { - // TODO(ladynana): propagate the actual error message - // from EventEngine. - return absl::UnavailableError( - "Transport closed due to endpoint write/read " - "failed."); - } - return absl::OkStatus(); - }); - }), + ForEach(std::move(*call_args.client_to_server_messages), + [stream_id, initial_frame = true, + client_initial_metadata = + std::move(call_args.client_initial_metadata), + outgoing_frames = outgoing_frames_.MakeSender(), + this](MessageHandle result) mutable { + ClientFragmentFrame frame; + // Construct frame header (flags, header_length and + // trailer_length will be added in serialization). + uint32_t message_length = result->payload()->Length(); + frame.stream_id = stream_id; + frame.message_padding = message_length % aligned_bytes; + frame.message = std::move(result); + if (initial_frame) { + // Send initial frame with client intial metadata. + frame.headers = std::move(client_initial_metadata); + initial_frame = false; + } + return TrySeq( + outgoing_frames.Send(ClientFrame(std::move(frame))), + [](bool success) -> absl::Status { + if (!success) { + // TODO(ladynana): propagate the actual error + // message from EventEngine. + return absl::UnavailableError( + "Transport closed due to endpoint write/read " + "failed."); + } + return absl::OkStatus(); + }); + }), // Continuously receive server frames from endpoints and save // results to call_args. Loop([server_initial_metadata = call_args.server_initial_metadata, diff --git a/src/core/ext/transport/chaotic_good/frame.cc b/src/core/ext/transport/chaotic_good/frame.cc index 2f7f938e7c3a8..f49fa4c4f3be7 100644 --- a/src/core/ext/transport/chaotic_good/frame.cc +++ b/src/core/ext/transport/chaotic_good/frame.cc @@ -50,12 +50,13 @@ const NoDestruct kZeroSlice{[] { class FrameSerializer { public: - explicit FrameSerializer(FrameHeader header) : header_(header) { + explicit FrameSerializer(FrameType frame_type, uint32_t stream_id, + uint32_t message_padding) { output_.AppendIndexed(kZeroSlice->Copy()); - // Initialize header flags, header_length, trailer_length to 0. + header_.type = frame_type; + header_.stream_id = stream_id; + header_.message_padding = message_padding; header_.flags.SetAll(false); - header_.header_length = 0; - header_.trailer_length = 0; } // If called, must be called before AddTrailers, Finish. SliceBuffer& AddHeaders() { @@ -173,11 +174,12 @@ absl::Status SettingsFrame::Deserialize(HPackParser*, const FrameHeader& header, } SliceBuffer SettingsFrame::Serialize(HPackCompressor*) const { - FrameSerializer serializer( - FrameHeader{FrameType::kSettings, {}, 0, 0, 0, 0, 0}); + FrameSerializer serializer(FrameType::kSettings, 0, 0); return serializer.Finish(); } +std::string SettingsFrame::ToString() const { return "SettingsFrame{}"; } + absl::Status ClientFragmentFrame::Deserialize(HPackParser* parser, const FrameHeader& header, absl::BitGenRef bitsrc, @@ -185,7 +187,8 @@ absl::Status ClientFragmentFrame::Deserialize(HPackParser* parser, if (header.stream_id == 0) { return absl::InvalidArgumentError("Expected non-zero stream id"); } - frame_header = header; + stream_id = header.stream_id; + message_padding = header.message_padding; if (header.type != FrameType::kFragment) { return absl::InvalidArgumentError("Expected fragment frame"); } @@ -197,6 +200,9 @@ absl::Status ClientFragmentFrame::Deserialize(HPackParser* parser, if (r.value() != nullptr) { headers = std::move(r.value()); } + } else if (header.header_length != 0) { + return absl::InvalidArgumentError(absl::StrCat( + "Unexpected non-zero header length", header.header_length)); } if (header.flags.is_set(1)) { if (header.trailer_length != 0) { @@ -210,8 +216,8 @@ absl::Status ClientFragmentFrame::Deserialize(HPackParser* parser, } SliceBuffer ClientFragmentFrame::Serialize(HPackCompressor* encoder) const { - GPR_ASSERT(frame_header.stream_id != 0); - FrameSerializer serializer(frame_header); + GPR_ASSERT(stream_id != 0); + FrameSerializer serializer(FrameType::kFragment, stream_id, message_padding); if (headers.get() != nullptr) { encoder->EncodeRawHeaders(*headers.get(), serializer.AddHeaders()); } @@ -221,6 +227,16 @@ SliceBuffer ClientFragmentFrame::Serialize(HPackCompressor* encoder) const { return serializer.Finish(); } +std::string ClientFragmentFrame::ToString() const { + return absl::StrCat( + "ClientFragmentFrame{stream_id=", stream_id, ", headers=", + headers.get() != nullptr ? headers->DebugString().c_str() : "nullptr", + ", message=", + message.get() != nullptr ? message->DebugString().c_str() : "nullptr", + ", message_padding=", message_padding, ", end_of_stream=", end_of_stream, + "}"); +} + absl::Status ServerFragmentFrame::Deserialize(HPackParser* parser, const FrameHeader& header, absl::BitGenRef bitsrc, @@ -228,7 +244,8 @@ absl::Status ServerFragmentFrame::Deserialize(HPackParser* parser, if (header.stream_id == 0) { return absl::InvalidArgumentError("Expected non-zero stream id"); } - frame_header = header; + stream_id = header.stream_id; + message_padding = header.message_padding; FrameDeserializer deserializer(header, slice_buffer); if (header.flags.is_set(0)) { auto r = @@ -238,6 +255,9 @@ absl::Status ServerFragmentFrame::Deserialize(HPackParser* parser, if (r.value() != nullptr) { headers = std::move(r.value()); } + } else if (header.header_length != 0) { + return absl::InvalidArgumentError(absl::StrCat( + "Unexpected non-zero header length", header.header_length)); } if (header.flags.is_set(1)) { auto r = @@ -247,13 +267,16 @@ absl::Status ServerFragmentFrame::Deserialize(HPackParser* parser, if (r.value() != nullptr) { trailers = std::move(r.value()); } + } else if (header.trailer_length != 0) { + return absl::InvalidArgumentError(absl::StrCat( + "Unexpected non-zero trailer length", header.trailer_length)); } return deserializer.Finish(); } SliceBuffer ServerFragmentFrame::Serialize(HPackCompressor* encoder) const { - GPR_ASSERT(frame_header.stream_id != 0); - FrameSerializer serializer(frame_header); + GPR_ASSERT(stream_id != 0); + FrameSerializer serializer(FrameType::kFragment, stream_id, message_padding); if (headers.get() != nullptr) { encoder->EncodeRawHeaders(*headers.get(), serializer.AddHeaders()); } @@ -263,6 +286,17 @@ SliceBuffer ServerFragmentFrame::Serialize(HPackCompressor* encoder) const { return serializer.Finish(); } +std::string ServerFragmentFrame::ToString() const { + return absl::StrCat( + "ServerFragmentFrame{stream_id=", stream_id, ", headers=", + headers.get() != nullptr ? headers->DebugString().c_str() : "nullptr", + ", message=", + message.get() != nullptr ? message->DebugString().c_str() : "nullptr", + ", message_padding=", message_padding, ", trailers=", + trailers.get() != nullptr ? trailers->DebugString().c_str() : "nullptr", + "}"); +} + absl::Status CancelFrame::Deserialize(HPackParser*, const FrameHeader& header, absl::BitGenRef, SliceBuffer& slice_buffer) { @@ -282,10 +316,13 @@ absl::Status CancelFrame::Deserialize(HPackParser*, const FrameHeader& header, SliceBuffer CancelFrame::Serialize(HPackCompressor*) const { GPR_ASSERT(stream_id != 0); - FrameSerializer serializer( - FrameHeader{FrameType::kCancel, {}, stream_id, 0, 0, 0, 0}); + FrameSerializer serializer(FrameType::kCancel, stream_id, 0); return serializer.Finish(); } +std::string CancelFrame::ToString() const { + return absl::StrCat("CancelFrame{stream_id=", stream_id, "}"); +} + } // namespace chaotic_good } // namespace grpc_core diff --git a/src/core/ext/transport/chaotic_good/frame.h b/src/core/ext/transport/chaotic_good/frame.h index 8e5031802e5d1..529c89570c7d3 100644 --- a/src/core/ext/transport/chaotic_good/frame.h +++ b/src/core/ext/transport/chaotic_good/frame.h @@ -43,6 +43,7 @@ class FrameInterface { absl::BitGenRef bitsrc, SliceBuffer& slice_buffer) = 0; virtual SliceBuffer Serialize(HPackCompressor* encoder) const = 0; + virtual std::string ToString() const = 0; protected: static bool EqVal(const Message& a, const Message& b) { @@ -67,6 +68,7 @@ struct SettingsFrame final : public FrameInterface { absl::BitGenRef bitsrc, SliceBuffer& slice_buffer) override; SliceBuffer Serialize(HPackCompressor* encoder) const override; + std::string ToString() const override; bool operator==(const SettingsFrame&) const { return true; } }; @@ -76,15 +78,16 @@ struct ClientFragmentFrame final : public FrameInterface { absl::BitGenRef bitsrc, SliceBuffer& slice_buffer) override; SliceBuffer Serialize(HPackCompressor* encoder) const override; + std::string ToString() const override; - FrameHeader frame_header; + uint32_t stream_id; ClientMetadataHandle headers; MessageHandle message; + uint32_t message_padding; bool end_of_stream = false; bool operator==(const ClientFragmentFrame& other) const { - return frame_header.stream_id == other.frame_header.stream_id && - EqHdl(headers, other.headers) && + return stream_id == other.stream_id && EqHdl(headers, other.headers) && end_of_stream == other.end_of_stream; } }; @@ -94,15 +97,17 @@ struct ServerFragmentFrame final : public FrameInterface { absl::BitGenRef bitsrc, SliceBuffer& slice_buffer) override; SliceBuffer Serialize(HPackCompressor* encoder) const override; + std::string ToString() const override; - FrameHeader frame_header; + uint32_t stream_id; ServerMetadataHandle headers; MessageHandle message; + uint32_t message_padding; ServerMetadataHandle trailers; bool operator==(const ServerFragmentFrame& other) const { - return frame_header.stream_id == other.frame_header.stream_id && - EqHdl(headers, other.headers) && EqHdl(trailers, other.trailers); + return stream_id == other.stream_id && EqHdl(headers, other.headers) && + EqHdl(trailers, other.trailers); } }; @@ -111,6 +116,7 @@ struct CancelFrame final : public FrameInterface { absl::BitGenRef bitsrc, SliceBuffer& slice_buffer) override; SliceBuffer Serialize(HPackCompressor* encoder) const override; + std::string ToString() const override; uint32_t stream_id; diff --git a/src/core/ext/transport/chaotic_good/frame_header.cc b/src/core/ext/transport/chaotic_good/frame_header.cc index 5e0e00d5f7d2a..e39d6a34b5836 100644 --- a/src/core/ext/transport/chaotic_good/frame_header.cc +++ b/src/core/ext/transport/chaotic_good/frame_header.cc @@ -20,6 +20,8 @@ #include "absl/status/status.h" +#include + namespace grpc_core { namespace chaotic_good { @@ -43,6 +45,8 @@ uint32_t ReadLittleEndianUint32(const uint8_t* data) { void FrameHeader::Serialize(uint8_t* data) const { WriteLittleEndianUint32( static_cast(type) | (flags.ToInt() << 8), data); + if (flags.is_set(0)) GPR_ASSERT(header_length > 0); + if (flags.is_set(1)) GPR_ASSERT(trailer_length > 0); WriteLittleEndianUint32(stream_id, data + 4); WriteLittleEndianUint32(header_length, data + 8); WriteLittleEndianUint32(message_length, data + 12); @@ -61,13 +65,15 @@ absl::StatusOr FrameHeader::Parse(const uint8_t* data) { header.stream_id = ReadLittleEndianUint32(data + 4); header.header_length = ReadLittleEndianUint32(data + 8); if (header.flags.is_set(0) && header.header_length <= 0) { - return absl::InvalidArgumentError("Invalid header length"); + return absl::InvalidArgumentError( + absl::StrCat("Invalid header length: ", header.header_length)); } header.message_length = ReadLittleEndianUint32(data + 12); header.message_padding = ReadLittleEndianUint32(data + 16); header.trailer_length = ReadLittleEndianUint32(data + 20); if (header.flags.is_set(1) && header.trailer_length <= 0) { - return absl::InvalidArgumentError("Invalid trailer length"); + return absl::InvalidArgumentError( + absl::StrCat("Invalid trailer length", header.trailer_length)); } return header; } @@ -79,5 +85,13 @@ uint32_t FrameHeader::GetFrameLength() const { return frame_length; } +std::string FrameHeader::ToString() const { + return absl::StrFormat( + "[type=0x%02x, flags=0x%02x, stream_id=%d, header_length=%d, " + "message_length=%d, message_padding=%d, trailer_length=%d]", + static_cast(type), flags.ToInt(), stream_id, + header_length, message_length, message_padding, trailer_length); +} + } // namespace chaotic_good } // namespace grpc_core diff --git a/src/core/ext/transport/chaotic_good/frame_header.h b/src/core/ext/transport/chaotic_good/frame_header.h index 7834c7d0a8370..fa236ed3342bc 100644 --- a/src/core/ext/transport/chaotic_good/frame_header.h +++ b/src/core/ext/transport/chaotic_good/frame_header.h @@ -35,13 +35,13 @@ enum class FrameType : uint8_t { }; struct FrameHeader { - FrameType type; + FrameType type = FrameType::kCancel; BitSet<2> flags; - uint32_t stream_id; - uint32_t header_length; - uint32_t message_length; - uint32_t message_padding; - uint32_t trailer_length; + uint32_t stream_id = 0; + uint32_t header_length = 0; + uint32_t message_length = 0; + uint32_t message_padding = 0; + uint32_t trailer_length = 0; // Parses a frame header from a buffer of 24 bytes. All 24 bytes are consumed. static absl::StatusOr Parse(const uint8_t* data); @@ -49,6 +49,8 @@ struct FrameHeader { void Serialize(uint8_t* data) const; // Compute frame sizes from the header. uint32_t GetFrameLength() const; + // Report contents as a string + std::string ToString() const; bool operator==(const FrameHeader& h) const { return type == h.type && flags == h.flags && stream_id == h.stream_id && diff --git a/test/core/transport/chaotic_good/frame_fuzzer.cc b/test/core/transport/chaotic_good/frame_fuzzer.cc index cf3ef86ac2334..57180ce1c20d7 100644 --- a/test/core/transport/chaotic_good/frame_fuzzer.cc +++ b/test/core/transport/chaotic_good/frame_fuzzer.cc @@ -56,7 +56,13 @@ void AssertRoundTrips(const T& input, FrameType expected_frame_type) { uint8_t header_bytes[24]; serialized.MoveFirstNBytesIntoBuffer(24, header_bytes); auto header = FrameHeader::Parse(header_bytes); - GPR_ASSERT(header.ok()); + if (!header.ok()) { + if (!squelch) { + gpr_log(GPR_ERROR, "Failed to parse header: %s", + header.status().ToString().c_str()); + } + Crash("Failed to parse header"); + } GPR_ASSERT(header->type == expected_frame_type); T output; HPackParser hpack_parser; @@ -79,6 +85,7 @@ void FinishParseAndChecks(const FrameHeader& header, const uint8_t* data, auto deser = parsed.Deserialize(&hpack_parser, header, absl::BitGenRef(bitgen), serialized); if (!deser.ok()) return; + gpr_log(GPR_INFO, "Read frame: %s", parsed.ToString().c_str()); AssertRoundTrips(parsed, header.type); } @@ -90,6 +97,7 @@ int Run(const uint8_t* data, size_t size) { if (size < 24) return 0; auto r = FrameHeader::Parse(data); if (!r.ok()) return 0; + gpr_log(GPR_INFO, "Read frame header: %s", r->ToString().c_str()); size -= 24; data += 24; MemoryAllocator memory_allocator = MemoryAllocator( diff --git a/test/core/transport/chaotic_good/frame_fuzzer_corpus/5072496117219328 b/test/core/transport/chaotic_good/frame_fuzzer_corpus/5072496117219328 new file mode 100644 index 0000000000000000000000000000000000000000..16d6e2f4fde2813246ca23877e80d539e834b3eb GIT binary patch literal 26 WcmcC+U}Ru0)K%dGQeXh&Lqq^0Hv&xn literal 0 HcmV?d00001 From 0353e5b9c4fac53a05a84d2a5ffa4bb3b50e6342 Mon Sep 17 00:00:00 2001 From: Tanvi Jagtap Date: Tue, 12 Dec 2023 06:13:15 -0800 Subject: [PATCH 080/127] Internal configuration PiperOrigin-RevId: 590178979 --- .../AuthSample.xcodeproj/project.pbxproj | 0 .../project.xcworkspace/contents.xcworkspacedata | 0 .../xcshareddata/xcschemes/AuthSample.xcscheme | 0 .../auth_sample/AuthTestService.podspec | 0 .../auth_sample/MakeRPCViewController.h | 0 .../auth_sample/MakeRPCViewController.m | 0 .../auth_sample/Misc/AppDelegate.h | 0 .../auth_sample/Misc/AppDelegate.m | 0 .../auth_sample/Misc/Base.lproj/Main.storyboard | 0 .../auth_sample/Misc/GoogleService-Info.plist | 0 .../AppIcon.appiconset/Contents.json | 0 .../Images.xcassets/first.imageset/Contents.json | 0 .../Misc/Images.xcassets/first.imageset/first.pdf | Bin .../Images.xcassets/second.imageset/Contents.json | 0 .../Misc/Images.xcassets/second.imageset/second.pdf | Bin .../auth_sample/Misc/Info.plist | 0 .../auth_sample/Misc/main.m | 0 .../auth_sample/Podfile | 0 .../auth_sample/README.md | 0 .../auth_sample/SelectUserViewController.h | 0 .../auth_sample/SelectUserViewController.m | 0 .../helloworld/HelloWorld.podspec | 0 .../helloworld/HelloWorld.xcodeproj/project.pbxproj | 0 .../project.xcworkspace/contents.xcworkspacedata | 0 .../xcshareddata/xcschemes/HelloWorld.xcscheme | 0 .../helloworld/HelloWorld/AppDelegate.h | 0 .../helloworld/HelloWorld/AppDelegate.m | 0 .../HelloWorld/Base.lproj/Main.storyboard | 0 .../AppIcon.appiconset/Contents.json | 0 .../helloworld/HelloWorld/Info.plist | 0 .../helloworld/HelloWorld/ViewController.m | 0 .../{objective-c => objective_c}/helloworld/Podfile | 0 .../helloworld/README.md | 0 .../{objective-c => objective_c}/helloworld/main.m | 0 .../helloworld_macos/HelloWorld.podspec | 0 .../HelloWorld.xcodeproj/project.pbxproj | 0 .../helloworld_macos/HelloWorld/AppDelegate.h | 0 .../helloworld_macos/HelloWorld/AppDelegate.m | 0 .../AppIcon.appiconset/Contents.json | 0 .../HelloWorld/Assets.xcassets/Contents.json | 0 .../HelloWorld/Base.lproj/Main.storyboard | 0 .../HelloWorld/HelloWorld.entitlements | 0 .../helloworld_macos/HelloWorld/Info.plist | 0 .../helloworld_macos/HelloWorld/ViewController.h | 0 .../helloworld_macos/HelloWorld/ViewController.m | 0 .../helloworld_macos/Podfile | 0 .../helloworld_macos/README.md | 0 .../helloworld_macos/main.m | 0 .../route_guide/Misc/AppDelegate.h | 0 .../route_guide/Misc/AppDelegate.m | 0 .../route_guide/Misc/Base.lproj/Main.storyboard | 0 .../AppIcon.appiconset/Contents.json | 0 .../Images.xcassets/first.imageset/Contents.json | 0 .../Misc/Images.xcassets/first.imageset/first.pdf | Bin .../Images.xcassets/second.imageset/Contents.json | 0 .../Misc/Images.xcassets/second.imageset/second.pdf | Bin .../route_guide/Misc/Info.plist | 0 .../route_guide/Misc/main.m | 0 .../route_guide/Podfile | 0 .../route_guide/README.md | 0 .../route_guide/RouteGuide.podspec | 0 .../RouteGuideClient.xcodeproj/project.pbxproj | 0 .../project.xcworkspace/contents.xcworkspacedata | 0 .../xcschemes/RouteGuideClient.xcscheme | 0 .../route_guide/ViewControllers.m | 0 .../route_guide/route_guide_db.json | 0 66 files changed, 0 insertions(+), 0 deletions(-) rename examples/{objective-c => objective_c}/auth_sample/AuthSample.xcodeproj/project.pbxproj (100%) rename examples/{objective-c => objective_c}/auth_sample/AuthSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata (100%) rename examples/{objective-c => objective_c}/auth_sample/AuthSample.xcodeproj/xcshareddata/xcschemes/AuthSample.xcscheme (100%) rename examples/{objective-c => objective_c}/auth_sample/AuthTestService.podspec (100%) rename examples/{objective-c => objective_c}/auth_sample/MakeRPCViewController.h (100%) rename examples/{objective-c => objective_c}/auth_sample/MakeRPCViewController.m (100%) rename examples/{objective-c => objective_c}/auth_sample/Misc/AppDelegate.h (100%) rename examples/{objective-c => objective_c}/auth_sample/Misc/AppDelegate.m (100%) rename examples/{objective-c => objective_c}/auth_sample/Misc/Base.lproj/Main.storyboard (100%) rename examples/{objective-c => objective_c}/auth_sample/Misc/GoogleService-Info.plist (100%) rename examples/{objective-c => objective_c}/auth_sample/Misc/Images.xcassets/AppIcon.appiconset/Contents.json (100%) rename examples/{objective-c => objective_c}/auth_sample/Misc/Images.xcassets/first.imageset/Contents.json (100%) rename examples/{objective-c => objective_c}/auth_sample/Misc/Images.xcassets/first.imageset/first.pdf (100%) rename examples/{objective-c => objective_c}/auth_sample/Misc/Images.xcassets/second.imageset/Contents.json (100%) rename examples/{objective-c => objective_c}/auth_sample/Misc/Images.xcassets/second.imageset/second.pdf (100%) rename examples/{objective-c => objective_c}/auth_sample/Misc/Info.plist (100%) rename examples/{objective-c => objective_c}/auth_sample/Misc/main.m (100%) rename examples/{objective-c => objective_c}/auth_sample/Podfile (100%) rename examples/{objective-c => objective_c}/auth_sample/README.md (100%) rename examples/{objective-c => objective_c}/auth_sample/SelectUserViewController.h (100%) rename examples/{objective-c => objective_c}/auth_sample/SelectUserViewController.m (100%) rename examples/{objective-c => objective_c}/helloworld/HelloWorld.podspec (100%) rename examples/{objective-c => objective_c}/helloworld/HelloWorld.xcodeproj/project.pbxproj (100%) rename examples/{objective-c => objective_c}/helloworld/HelloWorld.xcodeproj/project.xcworkspace/contents.xcworkspacedata (100%) rename examples/{objective-c => objective_c}/helloworld/HelloWorld.xcodeproj/xcshareddata/xcschemes/HelloWorld.xcscheme (100%) rename examples/{objective-c => objective_c}/helloworld/HelloWorld/AppDelegate.h (100%) rename examples/{objective-c => objective_c}/helloworld/HelloWorld/AppDelegate.m (100%) rename examples/{objective-c => objective_c}/helloworld/HelloWorld/Base.lproj/Main.storyboard (100%) rename examples/{objective-c => objective_c}/helloworld/HelloWorld/Images.xcassets/AppIcon.appiconset/Contents.json (100%) rename examples/{objective-c => objective_c}/helloworld/HelloWorld/Info.plist (100%) rename examples/{objective-c => objective_c}/helloworld/HelloWorld/ViewController.m (100%) rename examples/{objective-c => objective_c}/helloworld/Podfile (100%) rename examples/{objective-c => objective_c}/helloworld/README.md (100%) rename examples/{objective-c => objective_c}/helloworld/main.m (100%) rename examples/{objective-c => objective_c}/helloworld_macos/HelloWorld.podspec (100%) rename examples/{objective-c => objective_c}/helloworld_macos/HelloWorld.xcodeproj/project.pbxproj (100%) rename examples/{objective-c => objective_c}/helloworld_macos/HelloWorld/AppDelegate.h (100%) rename examples/{objective-c => objective_c}/helloworld_macos/HelloWorld/AppDelegate.m (100%) rename examples/{objective-c => objective_c}/helloworld_macos/HelloWorld/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename examples/{objective-c => objective_c}/helloworld_macos/HelloWorld/Assets.xcassets/Contents.json (100%) rename examples/{objective-c => objective_c}/helloworld_macos/HelloWorld/Base.lproj/Main.storyboard (100%) rename examples/{objective-c => objective_c}/helloworld_macos/HelloWorld/HelloWorld.entitlements (100%) rename examples/{objective-c => objective_c}/helloworld_macos/HelloWorld/Info.plist (100%) rename examples/{objective-c => objective_c}/helloworld_macos/HelloWorld/ViewController.h (100%) rename examples/{objective-c => objective_c}/helloworld_macos/HelloWorld/ViewController.m (100%) rename examples/{objective-c => objective_c}/helloworld_macos/Podfile (100%) rename examples/{objective-c => objective_c}/helloworld_macos/README.md (100%) rename examples/{objective-c => objective_c}/helloworld_macos/main.m (100%) rename examples/{objective-c => objective_c}/route_guide/Misc/AppDelegate.h (100%) rename examples/{objective-c => objective_c}/route_guide/Misc/AppDelegate.m (100%) rename examples/{objective-c => objective_c}/route_guide/Misc/Base.lproj/Main.storyboard (100%) rename examples/{objective-c => objective_c}/route_guide/Misc/Images.xcassets/AppIcon.appiconset/Contents.json (100%) rename examples/{objective-c => objective_c}/route_guide/Misc/Images.xcassets/first.imageset/Contents.json (100%) rename examples/{objective-c => objective_c}/route_guide/Misc/Images.xcassets/first.imageset/first.pdf (100%) rename examples/{objective-c => objective_c}/route_guide/Misc/Images.xcassets/second.imageset/Contents.json (100%) rename examples/{objective-c => objective_c}/route_guide/Misc/Images.xcassets/second.imageset/second.pdf (100%) rename examples/{objective-c => objective_c}/route_guide/Misc/Info.plist (100%) rename examples/{objective-c => objective_c}/route_guide/Misc/main.m (100%) rename examples/{objective-c => objective_c}/route_guide/Podfile (100%) rename examples/{objective-c => objective_c}/route_guide/README.md (100%) rename examples/{objective-c => objective_c}/route_guide/RouteGuide.podspec (100%) rename examples/{objective-c => objective_c}/route_guide/RouteGuideClient.xcodeproj/project.pbxproj (100%) rename examples/{objective-c => objective_c}/route_guide/RouteGuideClient.xcodeproj/project.xcworkspace/contents.xcworkspacedata (100%) rename examples/{objective-c => objective_c}/route_guide/RouteGuideClient.xcodeproj/xcshareddata/xcschemes/RouteGuideClient.xcscheme (100%) rename examples/{objective-c => objective_c}/route_guide/ViewControllers.m (100%) rename examples/{objective-c => objective_c}/route_guide/route_guide_db.json (100%) diff --git a/examples/objective-c/auth_sample/AuthSample.xcodeproj/project.pbxproj b/examples/objective_c/auth_sample/AuthSample.xcodeproj/project.pbxproj similarity index 100% rename from examples/objective-c/auth_sample/AuthSample.xcodeproj/project.pbxproj rename to examples/objective_c/auth_sample/AuthSample.xcodeproj/project.pbxproj diff --git a/examples/objective-c/auth_sample/AuthSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/examples/objective_c/auth_sample/AuthSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from examples/objective-c/auth_sample/AuthSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to examples/objective_c/auth_sample/AuthSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/examples/objective-c/auth_sample/AuthSample.xcodeproj/xcshareddata/xcschemes/AuthSample.xcscheme b/examples/objective_c/auth_sample/AuthSample.xcodeproj/xcshareddata/xcschemes/AuthSample.xcscheme similarity index 100% rename from examples/objective-c/auth_sample/AuthSample.xcodeproj/xcshareddata/xcschemes/AuthSample.xcscheme rename to examples/objective_c/auth_sample/AuthSample.xcodeproj/xcshareddata/xcschemes/AuthSample.xcscheme diff --git a/examples/objective-c/auth_sample/AuthTestService.podspec b/examples/objective_c/auth_sample/AuthTestService.podspec similarity index 100% rename from examples/objective-c/auth_sample/AuthTestService.podspec rename to examples/objective_c/auth_sample/AuthTestService.podspec diff --git a/examples/objective-c/auth_sample/MakeRPCViewController.h b/examples/objective_c/auth_sample/MakeRPCViewController.h similarity index 100% rename from examples/objective-c/auth_sample/MakeRPCViewController.h rename to examples/objective_c/auth_sample/MakeRPCViewController.h diff --git a/examples/objective-c/auth_sample/MakeRPCViewController.m b/examples/objective_c/auth_sample/MakeRPCViewController.m similarity index 100% rename from examples/objective-c/auth_sample/MakeRPCViewController.m rename to examples/objective_c/auth_sample/MakeRPCViewController.m diff --git a/examples/objective-c/auth_sample/Misc/AppDelegate.h b/examples/objective_c/auth_sample/Misc/AppDelegate.h similarity index 100% rename from examples/objective-c/auth_sample/Misc/AppDelegate.h rename to examples/objective_c/auth_sample/Misc/AppDelegate.h diff --git a/examples/objective-c/auth_sample/Misc/AppDelegate.m b/examples/objective_c/auth_sample/Misc/AppDelegate.m similarity index 100% rename from examples/objective-c/auth_sample/Misc/AppDelegate.m rename to examples/objective_c/auth_sample/Misc/AppDelegate.m diff --git a/examples/objective-c/auth_sample/Misc/Base.lproj/Main.storyboard b/examples/objective_c/auth_sample/Misc/Base.lproj/Main.storyboard similarity index 100% rename from examples/objective-c/auth_sample/Misc/Base.lproj/Main.storyboard rename to examples/objective_c/auth_sample/Misc/Base.lproj/Main.storyboard diff --git a/examples/objective-c/auth_sample/Misc/GoogleService-Info.plist b/examples/objective_c/auth_sample/Misc/GoogleService-Info.plist similarity index 100% rename from examples/objective-c/auth_sample/Misc/GoogleService-Info.plist rename to examples/objective_c/auth_sample/Misc/GoogleService-Info.plist diff --git a/examples/objective-c/auth_sample/Misc/Images.xcassets/AppIcon.appiconset/Contents.json b/examples/objective_c/auth_sample/Misc/Images.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from examples/objective-c/auth_sample/Misc/Images.xcassets/AppIcon.appiconset/Contents.json rename to examples/objective_c/auth_sample/Misc/Images.xcassets/AppIcon.appiconset/Contents.json diff --git a/examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/Contents.json b/examples/objective_c/auth_sample/Misc/Images.xcassets/first.imageset/Contents.json similarity index 100% rename from examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/Contents.json rename to examples/objective_c/auth_sample/Misc/Images.xcassets/first.imageset/Contents.json diff --git a/examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/first.pdf b/examples/objective_c/auth_sample/Misc/Images.xcassets/first.imageset/first.pdf similarity index 100% rename from examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/first.pdf rename to examples/objective_c/auth_sample/Misc/Images.xcassets/first.imageset/first.pdf diff --git a/examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/Contents.json b/examples/objective_c/auth_sample/Misc/Images.xcassets/second.imageset/Contents.json similarity index 100% rename from examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/Contents.json rename to examples/objective_c/auth_sample/Misc/Images.xcassets/second.imageset/Contents.json diff --git a/examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/second.pdf b/examples/objective_c/auth_sample/Misc/Images.xcassets/second.imageset/second.pdf similarity index 100% rename from examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/second.pdf rename to examples/objective_c/auth_sample/Misc/Images.xcassets/second.imageset/second.pdf diff --git a/examples/objective-c/auth_sample/Misc/Info.plist b/examples/objective_c/auth_sample/Misc/Info.plist similarity index 100% rename from examples/objective-c/auth_sample/Misc/Info.plist rename to examples/objective_c/auth_sample/Misc/Info.plist diff --git a/examples/objective-c/auth_sample/Misc/main.m b/examples/objective_c/auth_sample/Misc/main.m similarity index 100% rename from examples/objective-c/auth_sample/Misc/main.m rename to examples/objective_c/auth_sample/Misc/main.m diff --git a/examples/objective-c/auth_sample/Podfile b/examples/objective_c/auth_sample/Podfile similarity index 100% rename from examples/objective-c/auth_sample/Podfile rename to examples/objective_c/auth_sample/Podfile diff --git a/examples/objective-c/auth_sample/README.md b/examples/objective_c/auth_sample/README.md similarity index 100% rename from examples/objective-c/auth_sample/README.md rename to examples/objective_c/auth_sample/README.md diff --git a/examples/objective-c/auth_sample/SelectUserViewController.h b/examples/objective_c/auth_sample/SelectUserViewController.h similarity index 100% rename from examples/objective-c/auth_sample/SelectUserViewController.h rename to examples/objective_c/auth_sample/SelectUserViewController.h diff --git a/examples/objective-c/auth_sample/SelectUserViewController.m b/examples/objective_c/auth_sample/SelectUserViewController.m similarity index 100% rename from examples/objective-c/auth_sample/SelectUserViewController.m rename to examples/objective_c/auth_sample/SelectUserViewController.m diff --git a/examples/objective-c/helloworld/HelloWorld.podspec b/examples/objective_c/helloworld/HelloWorld.podspec similarity index 100% rename from examples/objective-c/helloworld/HelloWorld.podspec rename to examples/objective_c/helloworld/HelloWorld.podspec diff --git a/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.pbxproj b/examples/objective_c/helloworld/HelloWorld.xcodeproj/project.pbxproj similarity index 100% rename from examples/objective-c/helloworld/HelloWorld.xcodeproj/project.pbxproj rename to examples/objective_c/helloworld/HelloWorld.xcodeproj/project.pbxproj diff --git a/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/examples/objective_c/helloworld/HelloWorld.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from examples/objective-c/helloworld/HelloWorld.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to examples/objective_c/helloworld/HelloWorld.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/examples/objective-c/helloworld/HelloWorld.xcodeproj/xcshareddata/xcschemes/HelloWorld.xcscheme b/examples/objective_c/helloworld/HelloWorld.xcodeproj/xcshareddata/xcschemes/HelloWorld.xcscheme similarity index 100% rename from examples/objective-c/helloworld/HelloWorld.xcodeproj/xcshareddata/xcschemes/HelloWorld.xcscheme rename to examples/objective_c/helloworld/HelloWorld.xcodeproj/xcshareddata/xcschemes/HelloWorld.xcscheme diff --git a/examples/objective-c/helloworld/HelloWorld/AppDelegate.h b/examples/objective_c/helloworld/HelloWorld/AppDelegate.h similarity index 100% rename from examples/objective-c/helloworld/HelloWorld/AppDelegate.h rename to examples/objective_c/helloworld/HelloWorld/AppDelegate.h diff --git a/examples/objective-c/helloworld/HelloWorld/AppDelegate.m b/examples/objective_c/helloworld/HelloWorld/AppDelegate.m similarity index 100% rename from examples/objective-c/helloworld/HelloWorld/AppDelegate.m rename to examples/objective_c/helloworld/HelloWorld/AppDelegate.m diff --git a/examples/objective-c/helloworld/HelloWorld/Base.lproj/Main.storyboard b/examples/objective_c/helloworld/HelloWorld/Base.lproj/Main.storyboard similarity index 100% rename from examples/objective-c/helloworld/HelloWorld/Base.lproj/Main.storyboard rename to examples/objective_c/helloworld/HelloWorld/Base.lproj/Main.storyboard diff --git a/examples/objective-c/helloworld/HelloWorld/Images.xcassets/AppIcon.appiconset/Contents.json b/examples/objective_c/helloworld/HelloWorld/Images.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from examples/objective-c/helloworld/HelloWorld/Images.xcassets/AppIcon.appiconset/Contents.json rename to examples/objective_c/helloworld/HelloWorld/Images.xcassets/AppIcon.appiconset/Contents.json diff --git a/examples/objective-c/helloworld/HelloWorld/Info.plist b/examples/objective_c/helloworld/HelloWorld/Info.plist similarity index 100% rename from examples/objective-c/helloworld/HelloWorld/Info.plist rename to examples/objective_c/helloworld/HelloWorld/Info.plist diff --git a/examples/objective-c/helloworld/HelloWorld/ViewController.m b/examples/objective_c/helloworld/HelloWorld/ViewController.m similarity index 100% rename from examples/objective-c/helloworld/HelloWorld/ViewController.m rename to examples/objective_c/helloworld/HelloWorld/ViewController.m diff --git a/examples/objective-c/helloworld/Podfile b/examples/objective_c/helloworld/Podfile similarity index 100% rename from examples/objective-c/helloworld/Podfile rename to examples/objective_c/helloworld/Podfile diff --git a/examples/objective-c/helloworld/README.md b/examples/objective_c/helloworld/README.md similarity index 100% rename from examples/objective-c/helloworld/README.md rename to examples/objective_c/helloworld/README.md diff --git a/examples/objective-c/helloworld/main.m b/examples/objective_c/helloworld/main.m similarity index 100% rename from examples/objective-c/helloworld/main.m rename to examples/objective_c/helloworld/main.m diff --git a/examples/objective-c/helloworld_macos/HelloWorld.podspec b/examples/objective_c/helloworld_macos/HelloWorld.podspec similarity index 100% rename from examples/objective-c/helloworld_macos/HelloWorld.podspec rename to examples/objective_c/helloworld_macos/HelloWorld.podspec diff --git a/examples/objective-c/helloworld_macos/HelloWorld.xcodeproj/project.pbxproj b/examples/objective_c/helloworld_macos/HelloWorld.xcodeproj/project.pbxproj similarity index 100% rename from examples/objective-c/helloworld_macos/HelloWorld.xcodeproj/project.pbxproj rename to examples/objective_c/helloworld_macos/HelloWorld.xcodeproj/project.pbxproj diff --git a/examples/objective-c/helloworld_macos/HelloWorld/AppDelegate.h b/examples/objective_c/helloworld_macos/HelloWorld/AppDelegate.h similarity index 100% rename from examples/objective-c/helloworld_macos/HelloWorld/AppDelegate.h rename to examples/objective_c/helloworld_macos/HelloWorld/AppDelegate.h diff --git a/examples/objective-c/helloworld_macos/HelloWorld/AppDelegate.m b/examples/objective_c/helloworld_macos/HelloWorld/AppDelegate.m similarity index 100% rename from examples/objective-c/helloworld_macos/HelloWorld/AppDelegate.m rename to examples/objective_c/helloworld_macos/HelloWorld/AppDelegate.m diff --git a/examples/objective-c/helloworld_macos/HelloWorld/Assets.xcassets/AppIcon.appiconset/Contents.json b/examples/objective_c/helloworld_macos/HelloWorld/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from examples/objective-c/helloworld_macos/HelloWorld/Assets.xcassets/AppIcon.appiconset/Contents.json rename to examples/objective_c/helloworld_macos/HelloWorld/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/examples/objective-c/helloworld_macos/HelloWorld/Assets.xcassets/Contents.json b/examples/objective_c/helloworld_macos/HelloWorld/Assets.xcassets/Contents.json similarity index 100% rename from examples/objective-c/helloworld_macos/HelloWorld/Assets.xcassets/Contents.json rename to examples/objective_c/helloworld_macos/HelloWorld/Assets.xcassets/Contents.json diff --git a/examples/objective-c/helloworld_macos/HelloWorld/Base.lproj/Main.storyboard b/examples/objective_c/helloworld_macos/HelloWorld/Base.lproj/Main.storyboard similarity index 100% rename from examples/objective-c/helloworld_macos/HelloWorld/Base.lproj/Main.storyboard rename to examples/objective_c/helloworld_macos/HelloWorld/Base.lproj/Main.storyboard diff --git a/examples/objective-c/helloworld_macos/HelloWorld/HelloWorld.entitlements b/examples/objective_c/helloworld_macos/HelloWorld/HelloWorld.entitlements similarity index 100% rename from examples/objective-c/helloworld_macos/HelloWorld/HelloWorld.entitlements rename to examples/objective_c/helloworld_macos/HelloWorld/HelloWorld.entitlements diff --git a/examples/objective-c/helloworld_macos/HelloWorld/Info.plist b/examples/objective_c/helloworld_macos/HelloWorld/Info.plist similarity index 100% rename from examples/objective-c/helloworld_macos/HelloWorld/Info.plist rename to examples/objective_c/helloworld_macos/HelloWorld/Info.plist diff --git a/examples/objective-c/helloworld_macos/HelloWorld/ViewController.h b/examples/objective_c/helloworld_macos/HelloWorld/ViewController.h similarity index 100% rename from examples/objective-c/helloworld_macos/HelloWorld/ViewController.h rename to examples/objective_c/helloworld_macos/HelloWorld/ViewController.h diff --git a/examples/objective-c/helloworld_macos/HelloWorld/ViewController.m b/examples/objective_c/helloworld_macos/HelloWorld/ViewController.m similarity index 100% rename from examples/objective-c/helloworld_macos/HelloWorld/ViewController.m rename to examples/objective_c/helloworld_macos/HelloWorld/ViewController.m diff --git a/examples/objective-c/helloworld_macos/Podfile b/examples/objective_c/helloworld_macos/Podfile similarity index 100% rename from examples/objective-c/helloworld_macos/Podfile rename to examples/objective_c/helloworld_macos/Podfile diff --git a/examples/objective-c/helloworld_macos/README.md b/examples/objective_c/helloworld_macos/README.md similarity index 100% rename from examples/objective-c/helloworld_macos/README.md rename to examples/objective_c/helloworld_macos/README.md diff --git a/examples/objective-c/helloworld_macos/main.m b/examples/objective_c/helloworld_macos/main.m similarity index 100% rename from examples/objective-c/helloworld_macos/main.m rename to examples/objective_c/helloworld_macos/main.m diff --git a/examples/objective-c/route_guide/Misc/AppDelegate.h b/examples/objective_c/route_guide/Misc/AppDelegate.h similarity index 100% rename from examples/objective-c/route_guide/Misc/AppDelegate.h rename to examples/objective_c/route_guide/Misc/AppDelegate.h diff --git a/examples/objective-c/route_guide/Misc/AppDelegate.m b/examples/objective_c/route_guide/Misc/AppDelegate.m similarity index 100% rename from examples/objective-c/route_guide/Misc/AppDelegate.m rename to examples/objective_c/route_guide/Misc/AppDelegate.m diff --git a/examples/objective-c/route_guide/Misc/Base.lproj/Main.storyboard b/examples/objective_c/route_guide/Misc/Base.lproj/Main.storyboard similarity index 100% rename from examples/objective-c/route_guide/Misc/Base.lproj/Main.storyboard rename to examples/objective_c/route_guide/Misc/Base.lproj/Main.storyboard diff --git a/examples/objective-c/route_guide/Misc/Images.xcassets/AppIcon.appiconset/Contents.json b/examples/objective_c/route_guide/Misc/Images.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from examples/objective-c/route_guide/Misc/Images.xcassets/AppIcon.appiconset/Contents.json rename to examples/objective_c/route_guide/Misc/Images.xcassets/AppIcon.appiconset/Contents.json diff --git a/examples/objective-c/route_guide/Misc/Images.xcassets/first.imageset/Contents.json b/examples/objective_c/route_guide/Misc/Images.xcassets/first.imageset/Contents.json similarity index 100% rename from examples/objective-c/route_guide/Misc/Images.xcassets/first.imageset/Contents.json rename to examples/objective_c/route_guide/Misc/Images.xcassets/first.imageset/Contents.json diff --git a/examples/objective-c/route_guide/Misc/Images.xcassets/first.imageset/first.pdf b/examples/objective_c/route_guide/Misc/Images.xcassets/first.imageset/first.pdf similarity index 100% rename from examples/objective-c/route_guide/Misc/Images.xcassets/first.imageset/first.pdf rename to examples/objective_c/route_guide/Misc/Images.xcassets/first.imageset/first.pdf diff --git a/examples/objective-c/route_guide/Misc/Images.xcassets/second.imageset/Contents.json b/examples/objective_c/route_guide/Misc/Images.xcassets/second.imageset/Contents.json similarity index 100% rename from examples/objective-c/route_guide/Misc/Images.xcassets/second.imageset/Contents.json rename to examples/objective_c/route_guide/Misc/Images.xcassets/second.imageset/Contents.json diff --git a/examples/objective-c/route_guide/Misc/Images.xcassets/second.imageset/second.pdf b/examples/objective_c/route_guide/Misc/Images.xcassets/second.imageset/second.pdf similarity index 100% rename from examples/objective-c/route_guide/Misc/Images.xcassets/second.imageset/second.pdf rename to examples/objective_c/route_guide/Misc/Images.xcassets/second.imageset/second.pdf diff --git a/examples/objective-c/route_guide/Misc/Info.plist b/examples/objective_c/route_guide/Misc/Info.plist similarity index 100% rename from examples/objective-c/route_guide/Misc/Info.plist rename to examples/objective_c/route_guide/Misc/Info.plist diff --git a/examples/objective-c/route_guide/Misc/main.m b/examples/objective_c/route_guide/Misc/main.m similarity index 100% rename from examples/objective-c/route_guide/Misc/main.m rename to examples/objective_c/route_guide/Misc/main.m diff --git a/examples/objective-c/route_guide/Podfile b/examples/objective_c/route_guide/Podfile similarity index 100% rename from examples/objective-c/route_guide/Podfile rename to examples/objective_c/route_guide/Podfile diff --git a/examples/objective-c/route_guide/README.md b/examples/objective_c/route_guide/README.md similarity index 100% rename from examples/objective-c/route_guide/README.md rename to examples/objective_c/route_guide/README.md diff --git a/examples/objective-c/route_guide/RouteGuide.podspec b/examples/objective_c/route_guide/RouteGuide.podspec similarity index 100% rename from examples/objective-c/route_guide/RouteGuide.podspec rename to examples/objective_c/route_guide/RouteGuide.podspec diff --git a/examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.pbxproj b/examples/objective_c/route_guide/RouteGuideClient.xcodeproj/project.pbxproj similarity index 100% rename from examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.pbxproj rename to examples/objective_c/route_guide/RouteGuideClient.xcodeproj/project.pbxproj diff --git a/examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/examples/objective_c/route_guide/RouteGuideClient.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to examples/objective_c/route_guide/RouteGuideClient.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/examples/objective-c/route_guide/RouteGuideClient.xcodeproj/xcshareddata/xcschemes/RouteGuideClient.xcscheme b/examples/objective_c/route_guide/RouteGuideClient.xcodeproj/xcshareddata/xcschemes/RouteGuideClient.xcscheme similarity index 100% rename from examples/objective-c/route_guide/RouteGuideClient.xcodeproj/xcshareddata/xcschemes/RouteGuideClient.xcscheme rename to examples/objective_c/route_guide/RouteGuideClient.xcodeproj/xcshareddata/xcschemes/RouteGuideClient.xcscheme diff --git a/examples/objective-c/route_guide/ViewControllers.m b/examples/objective_c/route_guide/ViewControllers.m similarity index 100% rename from examples/objective-c/route_guide/ViewControllers.m rename to examples/objective_c/route_guide/ViewControllers.m diff --git a/examples/objective-c/route_guide/route_guide_db.json b/examples/objective_c/route_guide/route_guide_db.json similarity index 100% rename from examples/objective-c/route_guide/route_guide_db.json rename to examples/objective_c/route_guide/route_guide_db.json From eaf1a922648ef8deca9e7098009edd7df38bcd90 Mon Sep 17 00:00:00 2001 From: alto-ruby Date: Tue, 12 Dec 2023 09:02:57 -0800 Subject: [PATCH 081/127] [Ruby] remove #include (#34178) #34168 Closes #34178 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/34178 from alto-ruby:no-sys-time-h 42c5ad0f793893ec936cf90d6099abfeb82775ac PiperOrigin-RevId: 590223092 --- src/ruby/ext/grpc/rb_grpc.c | 1 - src/ruby/ext/grpc/rb_grpc.h | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c index 30281b54630ae..4896323bc026a 100644 --- a/src/ruby/ext/grpc/rb_grpc.c +++ b/src/ruby/ext/grpc/rb_grpc.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/src/ruby/ext/grpc/rb_grpc.h b/src/ruby/ext/grpc/rb_grpc.h index ea5f719647401..1e7d391935f44 100644 --- a/src/ruby/ext/grpc/rb_grpc.h +++ b/src/ruby/ext/grpc/rb_grpc.h @@ -21,8 +21,6 @@ #include -#include - #include /* grpc_rb_mGrpcCore is the module containing the ruby wrapper GRPC classes. */ From 75686ed19df265379923b4e97323aa8439fb1adf Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 12 Dec 2023 10:11:28 -0800 Subject: [PATCH 082/127] [channel-args] Optimize channel args to string (#35286) One of the more major CPU sinks for b/311358095 Closes #35286 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35286 from ctiller:fuzz-311358095 ad4278937f682bc205c775bcc85ad0a1815eaa91 PiperOrigin-RevId: 590247206 --- src/core/lib/channel/channel_args.cc | 38 ++++++++++++++++++---------- src/core/lib/channel/channel_args.h | 2 +- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/core/lib/channel/channel_args.cc b/src/core/lib/channel/channel_args.cc index 95010e332f075..80ac7f7569c73 100644 --- a/src/core/lib/channel/channel_args.cc +++ b/src/core/lib/channel/channel_args.cc @@ -280,25 +280,35 @@ absl::optional ChannelArgs::GetBool(absl::string_view name) const { } } -std::string ChannelArgs::Value::ToString() const { - if (rep_.c_vtable() == &int_vtable_) { - return std::to_string(reinterpret_cast(rep_.c_pointer())); - } +absl::string_view ChannelArgs::Value::ToString( + std::list& backing_strings) const { if (rep_.c_vtable() == &string_vtable_) { - return std::string( - static_cast(rep_.c_pointer())->as_string_view()); + return static_cast(rep_.c_pointer())->as_string_view(); + } + if (rep_.c_vtable() == &int_vtable_) { + backing_strings.emplace_back( + std::to_string(reinterpret_cast(rep_.c_pointer()))); + return backing_strings.back(); } - return absl::StrFormat("%p", rep_.c_pointer()); + backing_strings.emplace_back(absl::StrFormat("%p", rep_.c_pointer())); + return backing_strings.back(); } std::string ChannelArgs::ToString() const { - std::vector arg_strings; - args_.ForEach( - [&arg_strings](const RefCountedStringValue& key, const Value& value) { - arg_strings.push_back( - absl::StrCat(key.as_string_view(), "=", value.ToString())); - }); - return absl::StrCat("{", absl::StrJoin(arg_strings, ", "), "}"); + std::vector strings; + std::list backing_strings; + strings.push_back("{"); + bool first = true; + args_.ForEach([&strings, &first, &backing_strings]( + const RefCountedStringValue& key, const Value& value) { + if (!first) strings.push_back(", "); + first = false; + strings.push_back(key.as_string_view()); + strings.push_back("="); + strings.push_back(value.ToString(backing_strings)); + }); + strings.push_back("}"); + return absl::StrJoin(strings, ""); } ChannelArgs ChannelArgs::UnionWith(ChannelArgs other) const { diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h index 2c10d955127f4..c6fc539587d1f 100644 --- a/src/core/lib/channel/channel_args.h +++ b/src/core/lib/channel/channel_args.h @@ -345,7 +345,7 @@ class ChannelArgs { return &rep_; } - std::string ToString() const; + absl::string_view ToString(std::list& backing) const; grpc_arg MakeCArg(const char* name) const; From 2cc1550e77ab84b5d0fd7f141ed09db1db1878d2 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Tue, 12 Dec 2023 10:39:49 -0800 Subject: [PATCH 083/127] [release] add 1.60 to interop matrix (#35274) Closes #35274 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35274 from markdroth:release_interop_matrix_update b1cfcad14be9e321134b05741c124f4509525165 PiperOrigin-RevId: 590257600 --- tools/interop_matrix/client_matrix.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/interop_matrix/client_matrix.py b/tools/interop_matrix/client_matrix.py index 836485bdb6949..3bf95efe0a638 100644 --- a/tools/interop_matrix/client_matrix.py +++ b/tools/interop_matrix/client_matrix.py @@ -129,6 +129,7 @@ def __init__(self, patch=[], runtimes=[], testcases_file=None): ("v1.56.0", ReleaseInfo()), ("v1.57.0", ReleaseInfo()), ("v1.58.0", ReleaseInfo()), + ("v1.60.0", ReleaseInfo()), ] ), "go": OrderedDict( @@ -753,6 +754,12 @@ def __init__(self, patch=[], runtimes=[], testcases_file=None): runtimes=["python"], testcases_file="python__master" ), ), + ( + "v1.60.0", + ReleaseInfo( + runtimes=["python"], testcases_file="python__master" + ), + ), ] ), "node": OrderedDict( @@ -846,6 +853,7 @@ def __init__(self, patch=[], runtimes=[], testcases_file=None): ("v1.56.0", ReleaseInfo()), ("v1.57.0", ReleaseInfo()), ("v1.58.0", ReleaseInfo()), + ("v1.60.0", ReleaseInfo()), ] ), "php": OrderedDict( @@ -903,6 +911,7 @@ def __init__(self, patch=[], runtimes=[], testcases_file=None): ("v1.56.0", ReleaseInfo()), ("v1.57.0", ReleaseInfo()), ("v1.58.0", ReleaseInfo()), + ("v1.60.0", ReleaseInfo()), ] ), "csharp": OrderedDict( From 7f2ecdb3f8af8463c3d291443b1c867cdab8547d Mon Sep 17 00:00:00 2001 From: Xuan Wang Date: Tue, 12 Dec 2023 10:40:59 -0800 Subject: [PATCH 084/127] [Python Observability] Building package and add to run_test (#34207) ### Changes in this PR * Refactor and remove some Core/C++ dependencies to simplify Python Observability package build process. * Refactored code to read config at Python layer. * Enable observability build from source. * Add observability to run_test. * Currently it's only enabled in Linux. * Add error handler in run_test loaders. * Current framework will always visit modules in test directory then decide which tests to skip. * Since we're not building Observability for MacOS and Windows this step will fail with error `No module named 'grpc_observability'`. * After the change we'll just skip those modules. * We still have `_sanity_test` to make sure all tests are loaded correctly for each platform. * Remov OC dependency as we're migrating to OTel. * Also removed trace from testing. * Note that trace propagation function was also removed because of this. ### Testing * Passed existing tests. * Tested locally, able to build observability from source using `GRPC_PYTHON_BUILD_WITH_CYTHON=1 pip install .`. Closes #34207 PiperOrigin-RevId: 590258014 --- BUILD | 23 -- requirements.bazel.txt | 3 +- src/python/grpcio_observability/.gitignore | 5 +- src/python/grpcio_observability/MANIFEST.in | 8 + .../_parallel_compile_patch.py | 77 +++++ .../grpc_observability/BUILD.bazel | 17 +- .../grpc_observability/_cyobservability.pyx | 29 +- .../grpc_observability/_gcp_observability.py | 98 +----- .../_observability_config.py | 129 ++++++++ .../_open_census_exporter.py | 11 +- .../grpc_observability/client_call_tracer.cc | 27 +- .../grpc_observability/client_call_tracer.h | 25 +- .../grpc_observability/observability_util.cc | 63 +--- .../grpc_observability/observability_util.h | 42 +-- .../python_census_context.cc | 17 +- .../python_census_context.h | 16 +- .../grpc_observability/rpc_encoding.cc | 29 ++ .../grpc_observability/rpc_encoding.h | 108 +++++++ .../grpc_observability/sampler.cc | 2 +- .../grpc_observability/server_call_tracer.cc | 23 +- .../grpc_observability/server_call_tracer.h | 6 +- .../grpcio_observability/grpc_version.py | 17 + .../make_grpcio_observability.py | 215 +++++++++++++ .../observability_lib_deps.py | 193 ++++++++++++ src/python/grpcio_observability/setup.py | 297 ++++++++++++++++++ src/python/grpcio_tests/tests/_loader.py | 15 +- .../tests/_sanity/_sanity_test.py | 12 + .../tests/observability/__init__.py | 13 + .../observability/_observability_test.py | 120 +------ src/python/grpcio_tests/tests/tests.json | 1 + .../grpc_version.py.template | 19 ++ .../run_tests/helper_scripts/build_python.sh | 15 +- 32 files changed, 1247 insertions(+), 428 deletions(-) create mode 100644 src/python/grpcio_observability/MANIFEST.in create mode 100644 src/python/grpcio_observability/_parallel_compile_patch.py create mode 100644 src/python/grpcio_observability/grpc_observability/_observability_config.py create mode 100644 src/python/grpcio_observability/grpc_observability/rpc_encoding.cc create mode 100644 src/python/grpcio_observability/grpc_observability/rpc_encoding.h create mode 100644 src/python/grpcio_observability/grpc_version.py create mode 100755 src/python/grpcio_observability/make_grpcio_observability.py create mode 100644 src/python/grpcio_observability/observability_lib_deps.py create mode 100644 src/python/grpcio_observability/setup.py create mode 100644 src/python/grpcio_tests/tests/observability/__init__.py create mode 100644 templates/src/python/grpcio_observability/grpc_version.py.template diff --git a/BUILD b/BUILD index 4c668a9e393af..6d5130d4ebbef 100644 --- a/BUILD +++ b/BUILD @@ -2308,29 +2308,6 @@ grpc_cc_library( ], ) -grpc_cc_library( - name = "grpc_rpc_encoding", - srcs = [ - "src/cpp/ext/filters/census/rpc_encoding.cc", - ], - hdrs = [ - "src/cpp/ext/filters/census/rpc_encoding.h", - ], - external_deps = [ - "absl/base", - "absl/base:core_headers", - "absl/base:endian", - "absl/meta:type_traits", - "absl/status", - "absl/strings", - "absl/time", - ], - language = "c++", - tags = ["nofixdeps"], - visibility = ["@grpc:grpc_python_observability"], - deps = ["gpr_platform"], -) - grpc_cc_library( name = "grpc_opencensus_plugin", srcs = [ diff --git a/requirements.bazel.txt b/requirements.bazel.txt index 532562389fd8e..0c8ec0cfbd79b 100644 --- a/requirements.bazel.txt +++ b/requirements.bazel.txt @@ -3,6 +3,7 @@ coverage==4.5.4 cython==0.29.21 protobuf>=3.5.0.post1, < 4.0dev wheel==0.38.1 +google-auth==1.24.0 oauth2client==4.1.0 requests==2.25.1 urllib3==1.26.5 @@ -13,7 +14,5 @@ gevent==22.08.0 zope.event==4.5.0 setuptools==44.1.1 xds-protos==0.0.11 -opencensus==0.10.0 -opencensus-ext-stackdriver==0.8.0 absl-py==1.4.0 googleapis-common-protos==1.61.0 diff --git a/src/python/grpcio_observability/.gitignore b/src/python/grpcio_observability/.gitignore index 1516c11f4fb13..288073fc29b34 100644 --- a/src/python/grpcio_observability/.gitignore +++ b/src/python/grpcio_observability/.gitignore @@ -1,6 +1,7 @@ build/ -include/ +grpc_root/ +third_party/ +*.egg-info/ *.c *.cpp -*.egg-info *.so diff --git a/src/python/grpcio_observability/MANIFEST.in b/src/python/grpcio_observability/MANIFEST.in new file mode 100644 index 0000000000000..8efdc8f6f2179 --- /dev/null +++ b/src/python/grpcio_observability/MANIFEST.in @@ -0,0 +1,8 @@ +graft src/python/grpcio_observability/grpcio_observability.egg-info +graft grpc_observability +graft grpc_root +graft third_party +include _parallel_compile_patch.py +include grpc_version.py +include observability_lib_deps.py +include README.rst diff --git a/src/python/grpcio_observability/_parallel_compile_patch.py b/src/python/grpcio_observability/_parallel_compile_patch.py new file mode 100644 index 0000000000000..34ba53792164b --- /dev/null +++ b/src/python/grpcio_observability/_parallel_compile_patch.py @@ -0,0 +1,77 @@ +# Copyright 2023 The gRPC Authors +# +# Licensed 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. +"""Patches the compile() to allow enable parallel compilation of C/C++. + +build_ext has lots of C/C++ files and normally them one by one. +Enabling parallel build helps a lot. +""" + +import os + +try: + BUILD_EXT_COMPILER_JOBS = int( + os.environ["GRPC_PYTHON_BUILD_EXT_COMPILER_JOBS"] + ) +except KeyError: + import multiprocessing + + BUILD_EXT_COMPILER_JOBS = multiprocessing.cpu_count() + + +# monkey-patch for parallel compilation +# TODO(xuanwn): Use a template for this file. +def _parallel_compile( + self, + sources, + output_dir=None, + macros=None, + include_dirs=None, + debug=0, + extra_preargs=None, + extra_postargs=None, + depends=None, +): + # setup the same way as distutils.ccompiler.CCompiler + # https://github.com/python/cpython/blob/31368a4f0e531c19affe2a1becd25fc316bc7501/Lib/distutils/ccompiler.py#L564 + macros, objects, extra_postargs, pp_opts, build = self._setup_compile( + output_dir, macros, include_dirs, sources, depends, extra_postargs + ) + cc_args = self._get_cc_args(pp_opts, debug, extra_preargs) + + def _compile_single_file(obj): + try: + src, ext = build[obj] + except KeyError: + return + self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts) + + # run compilation of individual files in parallel + import multiprocessing.pool + + multiprocessing.pool.ThreadPool(BUILD_EXT_COMPILER_JOBS).map( + _compile_single_file, objects + ) + return objects + + +def monkeypatch_compile_maybe(): + """ + Monkeypatching is dumb, but the build speed gain is worth it. + After python 3.12, we won't find distutils if SETUPTOOLS_USE_DISTUTILS=stdlib. + """ + use_distutils = os.environ.get("SETUPTOOLS_USE_DISTUTILS", "") + if BUILD_EXT_COMPILER_JOBS > 1 and use_distutils != "stdlib": + import distutils.ccompiler # pylint: disable=wrong-import-position + + distutils.ccompiler.CCompiler.compile = _parallel_compile diff --git a/src/python/grpcio_observability/grpc_observability/BUILD.bazel b/src/python/grpcio_observability/grpc_observability/BUILD.bazel index 3be7bf5f970ff..2fbfb01aa0908 100644 --- a/src/python/grpcio_observability/grpc_observability/BUILD.bazel +++ b/src/python/grpcio_observability/grpc_observability/BUILD.bazel @@ -12,12 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@grpc_python_dependencies//:requirements.bzl", "requirement") load("//bazel:cython_library.bzl", "pyx_library") -package(default_visibility = ["//visibility:public"]) - -# TODO(xuanwn): We also need support Python-native build +package(default_visibility = ["//visibility:private"]) cc_library( name = "observability", @@ -25,6 +22,7 @@ cc_library( "client_call_tracer.cc", "observability_util.cc", "python_census_context.cc", + "rpc_encoding.cc", "sampler.cc", "server_call_tracer.cc", ], @@ -33,15 +31,13 @@ cc_library( "constants.h", "observability_util.h", "python_census_context.h", + "rpc_encoding.h", "sampler.h", "server_call_tracer.h", ], includes = ["."], deps = [ - #TODO(xuanwn): Confirm only referenced code is inlcuded in shared object library - "//:grpc", - "//:grpc_rpc_encoding", - "//src/cpp/ext/gcp:observability_config", + "//:grpc_base", ], ) @@ -65,7 +61,7 @@ py_library( "_gcp_observability.py", "_measures.py", "_observability.py", - "_open_census_exporter.py", + "_observability_config.py", "_views.py", ], imports = [ @@ -78,8 +74,5 @@ py_library( ], deps = [ ":cyobservability", - "//src/python/grpcio/grpc:grpcio", - requirement("opencensus"), - requirement("opencensus-ext-stackdriver"), ], ) diff --git a/src/python/grpcio_observability/grpc_observability/_cyobservability.pyx b/src/python/grpcio_observability/grpc_observability/_cyobservability.pyx index 5da61cc7a41d7..f48674e01e25c 100644 --- a/src/python/grpcio_observability/grpc_observability/_cyobservability.pyx +++ b/src/python/grpcio_observability/grpc_observability/_cyobservability.pyx @@ -22,7 +22,7 @@ import os from threading import Thread from typing import List, Mapping, Tuple, Union -import _observability +from grpc_observability import _observability # Time we wait for batch exporting census data # TODO(xuanwn): change interval to a more appropriate number @@ -72,7 +72,6 @@ class MetricsName(enum.Enum): CLIENT_RETRIES_PER_CALL = _CyMetricsName.CY_CLIENT_RETRIES_PER_CALL CLIENT_TRANSPARENT_RETRIES_PER_CALL = _CyMetricsName.CY_CLIENT_TRANSPARENT_RETRIES_PER_CALL CLIENT_RETRY_DELAY_PER_CALL = _CyMetricsName.CY_CLIENT_RETRY_DELAY_PER_CALL - CLIENT_TRANSPORT_LATENCY = _CyMetricsName.CY_CLIENT_TRANSPORT_LATENCY SERVER_SENT_MESSAGES_PER_RPC = _CyMetricsName.CY_SERVER_SENT_MESSAGES_PER_RPC SERVER_SENT_BYTES_PER_RPC = _CyMetricsName.CY_SERVER_SENT_BYTES_PER_RPC SERVER_RECEIVED_MESSAGES_PER_RPC = _CyMetricsName.CY_SERVER_RECEIVED_MESSAGES_PER_RPC @@ -101,28 +100,16 @@ def _start_exporting_thread(object exporter) -> None: GLOBAL_EXPORT_THREAD = Thread(target=_export_census_data, args=(exporter,)) GLOBAL_EXPORT_THREAD.start() +def activate_config(object py_config) -> None: + py_config: "_observability_config.GcpObservabilityConfig" -def set_gcp_observability_config(object py_config) -> bool: - py_config: _gcp_observability.GcpObservabilityPythonConfig - - py_labels = {} - sampling_rate = 0.0 - - cdef cGcpObservabilityConfig c_config = ReadAndActivateObservabilityConfig() - if not c_config.is_valid: - return False - - for label in c_config.labels: - py_labels[_decode(label.key)] = _decode(label.value) - - if PythonCensusTracingEnabled(): - sampling_rate = c_config.cloud_trace.sampling_rate + if (py_config.tracing_enabled): + EnablePythonCensusTracing(True); # Save sampling rate to global sampler. - ProbabilitySampler.Get().SetThreshold(sampling_rate) + ProbabilitySampler.Get().SetThreshold(py_config.sampling_rate) - py_config.set_configuration(_decode(c_config.project_id), sampling_rate, py_labels, - PythonCensusTracingEnabled(), PythonCensusStatsEnabled()) - return True + if (py_config.stats_enabled): + EnablePythonCensusStats(True); def create_client_call_tracer(bytes method_name, bytes trace_id, diff --git a/src/python/grpcio_observability/grpc_observability/_gcp_observability.py b/src/python/grpcio_observability/grpc_observability/_gcp_observability.py index d62653bcd58af..58e9a9d47a838 100644 --- a/src/python/grpcio_observability/grpc_observability/_gcp_observability.py +++ b/src/python/grpcio_observability/grpc_observability/_gcp_observability.py @@ -13,20 +13,15 @@ # limitations under the License. from __future__ import annotations -from dataclasses import dataclass -from dataclasses import field import logging -import threading import time -from typing import Any, Mapping, Optional +from typing import Any import grpc -from grpc_observability import _cyobservability # pytype: disable=pyi-error -from grpc_observability._open_census_exporter import CENSUS_UPLOAD_INTERVAL_SECS -from grpc_observability._open_census_exporter import OpenCensusExporter -from opencensus.trace import execution_context -from opencensus.trace import span_context as span_context_module -from opencensus.trace import trace_options as trace_options_module + +# pytype: disable=pyi-error +from grpc_observability import _cyobservability +from grpc_observability import _observability_config _LOGGER = logging.getLogger(__name__) @@ -56,42 +51,6 @@ grpc.StatusCode.DATA_LOSS: "DATA_LOSS", } -GRPC_SPAN_CONTEXT = "grpc_span_context" - - -@dataclass -class GcpObservabilityPythonConfig: - _singleton = None - _lock: threading.RLock = threading.RLock() - project_id: str = "" - stats_enabled: bool = False - tracing_enabled: bool = False - labels: Optional[Mapping[str, str]] = field(default_factory=dict) - sampling_rate: Optional[float] = 0.0 - - @staticmethod - def get(): - with GcpObservabilityPythonConfig._lock: - if GcpObservabilityPythonConfig._singleton is None: - GcpObservabilityPythonConfig._singleton = ( - GcpObservabilityPythonConfig() - ) - return GcpObservabilityPythonConfig._singleton - - def set_configuration( - self, - project_id: str, - sampling_rate: Optional[float] = 0.0, - labels: Optional[Mapping[str, str]] = None, - tracing_enabled: bool = False, - stats_enabled: bool = False, - ) -> None: - self.project_id = project_id - self.stats_enabled = stats_enabled - self.tracing_enabled = tracing_enabled - self.labels = labels - self.sampling_rate = sampling_rate - # pylint: disable=no-self-use class GCPOpenCensusObservability(grpc._observability.ObservabilityPlugin): @@ -108,25 +67,22 @@ class GCPOpenCensusObservability(grpc._observability.ObservabilityPlugin): exporter: Exporter used to export data. """ - config: GcpObservabilityPythonConfig + config: _observability_config.GcpObservabilityConfig exporter: "grpc_observability.Exporter" - use_open_census_exporter: bool def __init__(self, exporter: "grpc_observability.Exporter" = None): self.exporter = None - self.config = GcpObservabilityPythonConfig.get() - self.use_open_census_exporter = False - config_valid = _cyobservability.set_gcp_observability_config( - self.config - ) - if not config_valid: - raise ValueError("Invalid configuration") + self.config = None + try: + self.config = _observability_config.read_config() + _cyobservability.activate_config(self.config) + except Exception as e: # pylint: disable=broad-except + raise ValueError(f"Reading configuration failed with: {e}") if exporter: self.exporter = exporter else: - self.exporter = OpenCensusExporter(self.config) - self.use_open_census_exporter = True + raise ValueError(f"Please provide an exporter!") if self.config.tracing_enabled: self.set_tracing(True) @@ -156,9 +112,6 @@ def exit(self) -> None: # TODO(xuanwn): explicit synchronization # https://github.com/grpc/grpc/issues/33262 time.sleep(_cyobservability.CENSUS_EXPORT_BATCH_INTERVAL_SECS) - if self.use_open_census_exporter: - # Sleep so StackDriver can upload data to GCP. - time.sleep(CENSUS_UPLOAD_INTERVAL_SECS) self.set_tracing(False) self.set_stats(False) _cyobservability.observability_deinit() @@ -167,20 +120,10 @@ def exit(self) -> None: def create_client_call_tracer( self, method_name: bytes ) -> ClientCallTracerCapsule: - grpc_span_context = execution_context.get_opencensus_attr( - GRPC_SPAN_CONTEXT + trace_id = b"TRACE_ID" + capsule = _cyobservability.create_client_call_tracer( + method_name, trace_id ) - if grpc_span_context: - trace_id = grpc_span_context.trace_id.encode("utf8") - parent_span_id = grpc_span_context.span_id.encode("utf8") - capsule = _cyobservability.create_client_call_tracer( - method_name, trace_id, parent_span_id - ) - else: - trace_id = span_context_module.generate_trace_id().encode("utf8") - capsule = _cyobservability.create_client_call_tracer( - method_name, trace_id - ) return capsule def create_server_call_tracer_factory( @@ -197,14 +140,7 @@ def delete_client_call_tracer( def save_trace_context( self, trace_id: str, span_id: str, is_sampled: bool ) -> None: - trace_options = trace_options_module.TraceOptions(0) - trace_options.set_enabled(is_sampled) - span_context = span_context_module.SpanContext( - trace_id=trace_id, - span_id=span_id, - trace_options=trace_options, - ) - execution_context.set_opencensus_attr(GRPC_SPAN_CONTEXT, span_context) + pass def record_rpc_latency( self, method: str, rpc_latency: float, status_code: grpc.StatusCode diff --git a/src/python/grpcio_observability/grpc_observability/_observability_config.py b/src/python/grpcio_observability/grpc_observability/_observability_config.py new file mode 100644 index 0000000000000..f0105b7d33ba2 --- /dev/null +++ b/src/python/grpcio_observability/grpc_observability/_observability_config.py @@ -0,0 +1,129 @@ +# Copyright 2023 gRPC authors. +# +# Licensed 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. +"""Helper to read observability config.""" + +from dataclasses import dataclass +from dataclasses import field +import json +import os +from typing import Mapping, Optional + +GRPC_GCP_OBSERVABILITY_CONFIG_FILE_ENV = "GRPC_GCP_OBSERVABILITY_CONFIG_FILE" +GRPC_GCP_OBSERVABILITY_CONFIG_ENV = "GRPC_GCP_OBSERVABILITY_CONFIG" + + +@dataclass +class GcpObservabilityConfig: + project_id: str = "" + stats_enabled: bool = False + tracing_enabled: bool = False + labels: Optional[Mapping[str, str]] = field(default_factory=dict) + sampling_rate: Optional[float] = 0.0 + + def load_from_string_content(self, config_contents: str) -> None: + """Loads the configuration from a string. + + Args: + config_contents: The configuration string. + + Raises: + ValueError: If the configuration is invalid. + """ + try: + config_json = json.loads(config_contents) + except json.decoder.JSONDecodeError: + raise ValueError("Failed to load Json configuration.") + + if config_json and not isinstance(config_json, dict): + raise ValueError("Found invalid configuration.") + + self.project_id = config_json.get("project_id", "") + self.labels = config_json.get("labels", {}) + self.stats_enabled = "cloud_monitoring" in config_json.keys() + self.tracing_enabled = "cloud_trace" in config_json.keys() + tracing_config = config_json.get("cloud_trace", {}) + self.sampling_rate = tracing_config.get("sampling_rate", 0.0) + + +def read_config() -> GcpObservabilityConfig: + """Reads the GCP observability config from the environment variables. + + Returns: + The GCP observability config. + + Raises: + ValueError: If the configuration is invalid. + """ + config_contents = _get_gcp_observability_config_contents() + config = GcpObservabilityConfig() + config.load_from_string_content(config_contents) + + if not config.project_id: + # Get project ID from GCP environment variables since project ID was not + # set it in the GCP observability config. + config.project_id = _get_gcp_project_id_from_env_var() + if not config.project_id: + # Could not find project ID from GCP environment variables either. + raise ValueError("GCP Project ID not found.") + return config + + +def _get_gcp_project_id_from_env_var() -> Optional[str]: + """Gets the project ID from the GCP environment variables. + + Returns: + The project ID, or an empty string if the project ID could not be found. + """ + + project_id = "" + project_id = os.getenv("GCP_PROJECT") + if project_id: + return project_id + + project_id = os.getenv("GCLOUD_PROJECT") + if project_id: + return project_id + + project_id = os.getenv("GOOGLE_CLOUD_PROJECT") + if project_id: + return project_id + + return project_id + + +def _get_gcp_observability_config_contents() -> str: + """Get the contents of the observability config from environment variable or file. + + Returns: + The content from environment variable. + + Raises: + ValueError: If no configuration content was found. + """ + + contents_str = "" + # First try get config from GRPC_GCP_OBSERVABILITY_CONFIG_FILE_ENV. + config_path = os.getenv(GRPC_GCP_OBSERVABILITY_CONFIG_FILE_ENV) + if config_path: + with open(config_path, "r") as f: + contents_str = f.read() + + # Next, try GRPC_GCP_OBSERVABILITY_CONFIG_ENV env var. + if not contents_str: + contents_str = os.getenv(GRPC_GCP_OBSERVABILITY_CONFIG_ENV) + + if not contents_str: + raise ValueError("Configuration content not found.") + + return contents_str diff --git a/src/python/grpcio_observability/grpc_observability/_open_census_exporter.py b/src/python/grpcio_observability/grpc_observability/_open_census_exporter.py index b3b557ca695a0..8dbccfdd15699 100644 --- a/src/python/grpcio_observability/grpc_observability/_open_census_exporter.py +++ b/src/python/grpcio_observability/grpc_observability/_open_census_exporter.py @@ -14,10 +14,11 @@ from datetime import datetime import os -from typing import Any, List, Mapping, Optional, Tuple +from typing import List, Mapping, Optional, Tuple from google.rpc import code_pb2 from grpc_observability import _observability # pytype: disable=pyi-error +from grpc_observability import _observability_config from grpc_observability import _views from opencensus.common.transports import async_ from opencensus.ext.stackdriver import stats_exporter @@ -38,8 +39,6 @@ from opencensus.trace import trace_options from opencensus.trace import tracer -_gcp_observability = Any # grpc_observability.py imports this module. - # 60s is the default time for open census to call export. CENSUS_UPLOAD_INTERVAL_SECS = int( os.environ.get("GRPC_PYTHON_CENSUS_EXPORT_UPLOAD_INTERVAL_SECS", 20) @@ -61,16 +60,14 @@ def __init__(self, exporter): class OpenCensusExporter(_observability.Exporter): - config: "_gcp_observability.GcpObservabilityPythonConfig" + config: _observability_config.GcpObservabilityConfig default_labels: Optional[Mapping[str, str]] project_id: str tracer: Optional[tracer.Tracer] stats_recorder: Optional[StatsRecorder] view_manager: Optional[ViewManager] - def __init__( - self, config: "_gcp_observability.GcpObservabilityPythonConfig" - ): + def __init__(self, config: _observability_config.GcpObservabilityConfig): self.config = config.get() self.default_labels = self.config.labels self.project_id = self.config.project_id diff --git a/src/python/grpcio_observability/grpc_observability/client_call_tracer.cc b/src/python/grpcio_observability/grpc_observability/client_call_tracer.cc index 4af7d423beebd..46a091a8fa275 100644 --- a/src/python/grpcio_observability/grpc_observability/client_call_tracer.cc +++ b/src/python/grpcio_observability/grpc_observability/client_call_tracer.cc @@ -12,24 +12,21 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "src/python/grpcio_observability/grpc_observability/client_call_tracer.h" +#include "client_call_tracer.h" -#include -#include -#include #include #include #include #include "absl/strings/str_cat.h" -#include "absl/strings/string_view.h" #include "absl/time/clock.h" +#include "constants.h" +#include "observability_util.h" +#include "python_census_context.h" #include -#include "src/core/lib/experiments/experiments.h" -#include "src/core/lib/gprpp/sync.h" #include "src/core/lib/slice/slice.h" namespace grpc_observability { @@ -56,7 +53,7 @@ void PythonOpenCensusCallTracer::GenerateContext() {} void PythonOpenCensusCallTracer::RecordAnnotation( absl::string_view annotation) { - if (!context_.SpanContext().IsSampled()) { + if (!context_.GetSpanContext().IsSampled()) { return; } context_.AddSpanAnnotation(annotation); @@ -64,7 +61,7 @@ void PythonOpenCensusCallTracer::RecordAnnotation( void PythonOpenCensusCallTracer::RecordAnnotation( const Annotation& annotation) { - if (!context_.SpanContext().IsSampled()) { + if (!context_.GetSpanContext().IsSampled()) { return; } @@ -93,7 +90,7 @@ PythonOpenCensusCallTracer::~PythonOpenCensusCallTracer() { if (tracing_enabled_) { context_.EndSpan(); if (IsSampled()) { - RecordSpan(context_.Span().ToCensusData()); + RecordSpan(context_.GetSpan().ToCensusData()); } } } @@ -101,7 +98,7 @@ PythonOpenCensusCallTracer::~PythonOpenCensusCallTracer() { PythonCensusContext PythonOpenCensusCallTracer::CreateCensusContextForCallAttempt() { auto context = PythonCensusContext(absl::StrCat("Attempt.", method_), - &(context_.Span()), context_.Labels()); + &(context_.GetSpan()), context_.Labels()); return context; } @@ -274,11 +271,11 @@ void PythonOpenCensusCallTracer::PythonOpenCensusCallAttemptTracer::RecordEnd( if (parent_->tracing_enabled_) { if (status_code_ != absl::StatusCode::kOk) { - context_.Span().SetStatus(StatusCodeToString(status_code_)); + context_.GetSpan().SetStatus(StatusCodeToString(status_code_)); } context_.EndSpan(); if (IsSampled()) { - RecordSpan(context_.Span().ToCensusData()); + RecordSpan(context_.GetSpan().ToCensusData()); } } @@ -289,7 +286,7 @@ void PythonOpenCensusCallTracer::PythonOpenCensusCallAttemptTracer::RecordEnd( void PythonOpenCensusCallTracer::PythonOpenCensusCallAttemptTracer:: RecordAnnotation(absl::string_view annotation) { - if (!context_.SpanContext().IsSampled()) { + if (!context_.GetSpanContext().IsSampled()) { return; } context_.AddSpanAnnotation(annotation); @@ -297,7 +294,7 @@ void PythonOpenCensusCallTracer::PythonOpenCensusCallAttemptTracer:: void PythonOpenCensusCallTracer::PythonOpenCensusCallAttemptTracer:: RecordAnnotation(const Annotation& annotation) { - if (!context_.SpanContext().IsSampled()) { + if (!context_.GetSpanContext().IsSampled()) { return; } diff --git a/src/python/grpcio_observability/grpc_observability/client_call_tracer.h b/src/python/grpcio_observability/grpc_observability/client_call_tracer.h index b94f57bbb76dd..47a279865af41 100644 --- a/src/python/grpcio_observability/grpc_observability/client_call_tracer.h +++ b/src/python/grpcio_observability/grpc_observability/client_call_tracer.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef GRPC_PYRHON_OPENCENSUS_CLIENT_CALL_TRACER_H -#define GRPC_PYRHON_OPENCENSUS_CLIENT_CALL_TRACER_H +#ifndef GRPC_PYTHON_OPENCENSUS_CLIENT_CALL_TRACER_H +#define GRPC_PYTHON_OPENCENSUS_CLIENT_CALL_TRACER_H #include @@ -24,16 +24,11 @@ #include "absl/strings/escaping.h" #include "absl/strings/string_view.h" #include "absl/time/time.h" +#include "python_census_context.h" #include #include "src/core/lib/channel/call_tracer.h" -#include "src/core/lib/gprpp/sync.h" -#include "src/core/lib/iomgr/error.h" -#include "src/core/lib/slice/slice_buffer.h" -#include "src/core/lib/transport/metadata_batch.h" -#include "src/core/lib/transport/transport.h" -#include "src/python/grpcio_observability/grpc_observability/python_census_context.h" namespace grpc_observability { @@ -46,15 +41,15 @@ class PythonOpenCensusCallTracer : public grpc_core::ClientCallTracer { bool is_transparent_retry); std::string TraceId() override { return absl::BytesToHexString( - absl::string_view(context_.SpanContext().TraceId())); + absl::string_view(context_.GetSpanContext().TraceId())); } std::string SpanId() override { return absl::BytesToHexString( - absl::string_view(context_.SpanContext().SpanId())); + absl::string_view(context_.GetSpanContext().SpanId())); } - bool IsSampled() override { return context_.SpanContext().IsSampled(); } + bool IsSampled() override { return context_.GetSpanContext().IsSampled(); } void RecordSendInitialMetadata( grpc_metadata_batch* send_initial_metadata) override; @@ -102,15 +97,15 @@ class PythonOpenCensusCallTracer : public grpc_core::ClientCallTracer { std::string TraceId() override { return absl::BytesToHexString( - absl::string_view(context_.SpanContext().TraceId())); + absl::string_view(context_.GetSpanContext().TraceId())); } std::string SpanId() override { return absl::BytesToHexString( - absl::string_view(context_.SpanContext().SpanId())); + absl::string_view(context_.GetSpanContext().SpanId())); } - bool IsSampled() override { return context_.SpanContext().IsSampled(); } + bool IsSampled() override { return context_.GetSpanContext().IsSampled(); } void GenerateContext(); PythonOpenCensusCallAttemptTracer* StartNewAttempt( @@ -139,4 +134,4 @@ class PythonOpenCensusCallTracer : public grpc_core::ClientCallTracer { } // namespace grpc_observability -#endif // GRPC_PYRHON_OPENCENSUS_CLIENT_CALL_TRACER_H +#endif // GRPC_PYTHON_OPENCENSUS_CLIENT_CALL_TRACER_H diff --git a/src/python/grpcio_observability/grpc_observability/observability_util.cc b/src/python/grpcio_observability/grpc_observability/observability_util.cc index 3225543773dd7..cbbab6a8c93e9 100644 --- a/src/python/grpcio_observability/grpc_observability/observability_util.cc +++ b/src/python/grpcio_observability/grpc_observability/observability_util.cc @@ -12,10 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "src/python/grpcio_observability/grpc_observability/observability_util.h" - -#include -#include +#include "observability_util.h" #include #include @@ -25,13 +22,13 @@ #include "absl/status/statusor.h" #include "absl/strings/string_view.h" #include "absl/types/optional.h" +#include "client_call_tracer.h" +#include "constants.h" +#include "python_census_context.h" +#include "server_call_tracer.h" #include -#include "src/cpp/ext/gcp/observability_config.h" -#include "src/python/grpcio_observability/grpc_observability/client_call_tracer.h" -#include "src/python/grpcio_observability/grpc_observability/server_call_tracer.h" - namespace grpc_observability { std::queue* g_census_data_buffer; @@ -128,56 +125,6 @@ void AddCensusDataToBuffer(const CensusData& data) { } } -GcpObservabilityConfig ReadAndActivateObservabilityConfig() { - auto config = grpc::internal::GcpObservabilityConfig::ReadFromEnv(); - if (!config.ok()) { - return GcpObservabilityConfig(); - } - - if (!config->cloud_trace.has_value() && - !config->cloud_monitoring.has_value() && - !config->cloud_logging.has_value()) { - return GcpObservabilityConfig(true); - } - - if (config->cloud_trace.has_value()) { - EnablePythonCensusTracing(true); - } - if (config->cloud_monitoring.has_value()) { - EnablePythonCensusStats(true); - } - - std::vector