diff --git a/BUILD b/BUILD index 79ee22f7510..f2caa63ed0d 100644 --- a/BUILD +++ b/BUILD @@ -1797,16 +1797,17 @@ grpc_cc_library( "gpr", "grpc_public_hdrs", "grpc_trace", - "orphanable", "ref_counted_ptr", "stats", "//src/core:arena", + "//src/core:call_arena_allocator", "//src/core:channel_args", "//src/core:channel_stack_type", "//src/core:compression", "//src/core:connectivity_state", "//src/core:iomgr_fwd", "//src/core:ref_counted", + "//src/core:resource_quota", "//src/core:slice", "//src/core:stats_data", "//src/core:time", @@ -1885,6 +1886,7 @@ grpc_cc_library( "config", "gpr", "grpc_base", + "grpc_client_channel", "grpc_public_hdrs", "legacy_channel", "ref_counted_ptr", @@ -1892,6 +1894,7 @@ grpc_cc_library( "//src/core:arena", "//src/core:channel_args", "//src/core:channel_stack_type", + "//src/core:experiments", "//src/core:iomgr_fwd", "//src/core:ref_counted", "//src/core:slice", @@ -3698,11 +3701,13 @@ grpc_cc_library( grpc_cc_library( name = "grpc_client_channel", srcs = [ + "//src/core:client_channel/client_channel.cc", "//src/core:client_channel/client_channel_factory.cc", "//src/core:client_channel/client_channel_filter.cc", "//src/core:client_channel/client_channel_plugin.cc", "//src/core:client_channel/dynamic_filters.cc", "//src/core:client_channel/global_subchannel_pool.cc", + "//src/core:client_channel/load_balanced_call_destination.cc", "//src/core:client_channel/local_subchannel_pool.cc", "//src/core:client_channel/retry_filter.cc", "//src/core:client_channel/retry_filter_legacy_call_data.cc", @@ -3710,10 +3715,12 @@ grpc_cc_library( "//src/core:client_channel/subchannel_stream_client.cc", ], hdrs = [ + "//src/core:client_channel/client_channel.h", "//src/core:client_channel/client_channel_factory.h", "//src/core:client_channel/client_channel_filter.h", "//src/core:client_channel/dynamic_filters.h", "//src/core:client_channel/global_subchannel_pool.h", + "//src/core:client_channel/load_balanced_call_destination.h", "//src/core:client_channel/local_subchannel_pool.h", "//src/core:client_channel/retry_filter.h", "//src/core:client_channel/retry_filter_legacy_call_data.h", @@ -3735,21 +3742,17 @@ grpc_cc_library( "absl/strings:cord", "absl/types:optional", "absl/types:variant", - "@com_google_protobuf//upb:base", - "@com_google_protobuf//upb:mem", - "@com_google_protobuf//upb:message", ], language = "c++", visibility = ["@grpc:client_channel"], deps = [ - "api_trace", "backoff", "call_combiner", "call_tracer", + "channel", "channel_arg_names", "channelz", "config", - "config_vars", "debug_location", "endpoint_addresses", "exec_ctx", @@ -3760,26 +3763,23 @@ grpc_cc_library( "grpc_security_base", "grpc_service_config_impl", "grpc_trace", - "http_connect_handshaker", "iomgr", - "iomgr_timer", "lb_child_policy_handler", "legacy_context", "orphanable", - "parse_address", "promise", - "protobuf_duration_upb", "ref_counted_ptr", "sockaddr_utils", "stats", "uri_parser", "work_serializer", - "xds_orca_service_upb", - "xds_orca_upb", "//src/core:activity", "//src/core:arena", "//src/core:arena_promise", "//src/core:backend_metric_parser", + "//src/core:call_destination", + "//src/core:call_filters", + "//src/core:call_spine", "//src/core:cancel_callback", "//src/core:channel_args", "//src/core:channel_fwd", @@ -3793,33 +3793,33 @@ grpc_cc_library( "//src/core:connectivity_state", "//src/core:construct_destruct", "//src/core:context", - "//src/core:delegating_helper", "//src/core:dual_ref_counted", - "//src/core:env", "//src/core:error", "//src/core:error_utils", + "//src/core:exec_ctx_wakeup_scheduler", "//src/core:experiments", - "//src/core:gpr_atm", "//src/core:gpr_manual_constructor", "//src/core:grpc_backend_metric_data", - "//src/core:grpc_message_size_filter", + "//src/core:grpc_channel_idle_filter", "//src/core:grpc_service_config", + "//src/core:idle_filter_state", "//src/core:init_internally", + "//src/core:interception_chain", "//src/core:iomgr_fwd", "//src/core:json", - "//src/core:json_args", - "//src/core:json_channel_args", - "//src/core:json_object_loader", "//src/core:latch", "//src/core:lb_policy", "//src/core:lb_policy_registry", + "//src/core:loop", "//src/core:map", "//src/core:memory_quota", + "//src/core:metadata", "//src/core:metadata_batch", + "//src/core:metrics", + "//src/core:observable", "//src/core:pipe", "//src/core:poll", "//src/core:pollset_set", - "//src/core:proxy_mapper", "//src/core:proxy_mapper_registry", "//src/core:ref_counted", "//src/core:resolved_address", @@ -3827,11 +3827,13 @@ grpc_cc_library( "//src/core:retry_service_config", "//src/core:retry_throttle", "//src/core:seq", - "//src/core:service_config_parser", + "//src/core:single_set_ptr", + "//src/core:sleep", "//src/core:slice", "//src/core:slice_buffer", "//src/core:slice_refcount", "//src/core:stats_data", + "//src/core:status_flag", "//src/core:status_helper", "//src/core:subchannel_connector", "//src/core:subchannel_interface", @@ -3840,7 +3842,6 @@ grpc_cc_library( "//src/core:try_seq", "//src/core:unique_type_name", "//src/core:useful", - "//src/core:validation_errors", ], ) @@ -3915,14 +3916,14 @@ grpc_cc_library( grpc_cc_library( name = "httpcli", srcs = [ - "//src/core:lib/http/format_request.cc", - "//src/core:lib/http/httpcli.cc", - "//src/core:lib/http/parser.cc", + "//src/core:util/http_client/format_request.cc", + "//src/core:util/http_client/httpcli.cc", + "//src/core:util/http_client/parser.cc", ], hdrs = [ - "//src/core:lib/http/format_request.h", - "//src/core:lib/http/httpcli.h", - "//src/core:lib/http/parser.h", + "//src/core:util/http_client/format_request.h", + "//src/core:util/http_client/httpcli.h", + "//src/core:util/http_client/parser.h", ], external_deps = [ "absl/base:core_headers", diff --git a/BoringSSL-Package.swift b/BoringSSL-Package.swift index 8a4f6a6d639..1300fb1aec7 100644 --- a/BoringSSL-Package.swift +++ b/BoringSSL-Package.swift @@ -104,6 +104,7 @@ let package = Package( "src/crypto/dh_extra/dh_asn1.c", "src/crypto/dh_extra/params.c", "src/crypto/digest_extra/digest_extra.c", + "src/crypto/dilithium/dilithium.c", "src/crypto/dsa/dsa.c", "src/crypto/dsa/dsa_asn1.c", "src/crypto/ec_extra/ec_asn1.c", diff --git a/CMakeLists.txt b/CMakeLists.txt index 32839763f43..6595ee1d494 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1002,7 +1002,9 @@ if(gRPC_BUILD_TESTS) add_dependencies(buildtests_cxx client_authority_filter_test) add_dependencies(buildtests_cxx client_callback_end2end_test) add_dependencies(buildtests_cxx client_channel_service_config_test) - add_dependencies(buildtests_cxx client_channel_test) + if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) + add_dependencies(buildtests_cxx client_channel_test) + endif() add_dependencies(buildtests_cxx client_context_test_peer_test) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) add_dependencies(buildtests_cxx client_fork_test) @@ -1026,6 +1028,9 @@ if(gRPC_BUILD_TESTS) add_dependencies(buildtests_cxx compressed_payload_test) add_dependencies(buildtests_cxx compression_test) add_dependencies(buildtests_cxx concurrent_connectivity_test) + if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) + add_dependencies(buildtests_cxx connected_subchannel_test) + endif() add_dependencies(buildtests_cxx connection_prefix_bad_client_test) add_dependencies(buildtests_cxx connection_refused_test) add_dependencies(buildtests_cxx connectivity_state_test) @@ -1194,6 +1199,9 @@ if(gRPC_BUILD_TESTS) add_dependencies(buildtests_cxx latch_test) add_dependencies(buildtests_cxx lb_get_cpu_stats_test) add_dependencies(buildtests_cxx lb_load_data_store_test) + if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) + add_dependencies(buildtests_cxx load_balanced_call_destination_test) + endif() add_dependencies(buildtests_cxx load_config_test) add_dependencies(buildtests_cxx load_file_test) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) @@ -1436,6 +1444,7 @@ if(gRPC_BUILD_TESTS) add_dependencies(buildtests_cxx streams_not_seen_test) add_dependencies(buildtests_cxx string_ref_test) add_dependencies(buildtests_cxx string_test) + add_dependencies(buildtests_cxx subchannel_args_test) add_dependencies(buildtests_cxx switch_test) add_dependencies(buildtests_cxx sync_test) add_dependencies(buildtests_cxx system_roots_test) @@ -1830,6 +1839,7 @@ add_library(grpc src/core/channelz/channelz.cc src/core/channelz/channelz_registry.cc src/core/client_channel/backup_poller.cc + src/core/client_channel/client_channel.cc src/core/client_channel/client_channel_factory.cc src/core/client_channel/client_channel_filter.cc src/core/client_channel/client_channel_plugin.cc @@ -1837,6 +1847,7 @@ add_library(grpc src/core/client_channel/config_selector.cc src/core/client_channel/dynamic_filters.cc src/core/client_channel/global_subchannel_pool.cc + src/core/client_channel/load_balanced_call_destination.cc src/core/client_channel/local_subchannel_pool.cc src/core/client_channel/retry_filter.cc src/core/client_channel/retry_filter_legacy_call_data.cc @@ -2292,6 +2303,7 @@ add_library(grpc src/core/lib/event_engine/work_queue/basic_work_queue.cc src/core/lib/experiments/config.cc src/core/lib/experiments/experiments.cc + src/core/lib/gprpp/dump_args.cc src/core/lib/gprpp/load_file.cc src/core/lib/gprpp/per_cpu.cc src/core/lib/gprpp/posix/directory_reader.cc @@ -2303,10 +2315,6 @@ add_library(grpc src/core/lib/gprpp/validation_errors.cc src/core/lib/gprpp/windows/directory_reader.cc src/core/lib/gprpp/work_serializer.cc - src/core/lib/http/format_request.cc - src/core/lib/http/httpcli.cc - src/core/lib/http/httpcli_security_connector.cc - src/core/lib/http/parser.cc src/core/lib/iomgr/buffer_list.cc src/core/lib/iomgr/call_combiner.cc src/core/lib/iomgr/cfstream_handle.cc @@ -2596,6 +2604,10 @@ add_library(grpc src/core/tsi/ssl_transport_security_utils.cc src/core/tsi/transport_security.cc src/core/tsi/transport_security_grpc.cc + src/core/util/http_client/format_request.cc + src/core/util/http_client/httpcli.cc + src/core/util/http_client/httpcli_security_connector.cc + src/core/util/http_client/parser.cc src/core/util/json/json_object_loader.cc src/core/util/json/json_reader.cc src/core/util/json/json_util.cc @@ -2927,6 +2939,7 @@ add_library(grpc_unsecure src/core/channelz/channelz.cc src/core/channelz/channelz_registry.cc src/core/client_channel/backup_poller.cc + src/core/client_channel/client_channel.cc src/core/client_channel/client_channel_factory.cc src/core/client_channel/client_channel_filter.cc src/core/client_channel/client_channel_plugin.cc @@ -2934,6 +2947,7 @@ add_library(grpc_unsecure src/core/client_channel/config_selector.cc src/core/client_channel/dynamic_filters.cc src/core/client_channel/global_subchannel_pool.cc + src/core/client_channel/load_balanced_call_destination.cc src/core/client_channel/local_subchannel_pool.cc src/core/client_channel/retry_filter.cc src/core/client_channel/retry_filter_legacy_call_data.cc @@ -3085,6 +3099,7 @@ add_library(grpc_unsecure src/core/lib/event_engine/work_queue/basic_work_queue.cc src/core/lib/experiments/config.cc src/core/lib/experiments/experiments.cc + src/core/lib/gprpp/dump_args.cc src/core/lib/gprpp/load_file.cc src/core/lib/gprpp/per_cpu.cc src/core/lib/gprpp/ref_counted_string.cc @@ -3094,9 +3109,6 @@ add_library(grpc_unsecure src/core/lib/gprpp/uuid_v4.cc src/core/lib/gprpp/validation_errors.cc src/core/lib/gprpp/work_serializer.cc - src/core/lib/http/format_request.cc - src/core/lib/http/httpcli.cc - src/core/lib/http/parser.cc src/core/lib/iomgr/buffer_list.cc src/core/lib/iomgr/call_combiner.cc src/core/lib/iomgr/cfstream_handle.cc @@ -3314,6 +3326,9 @@ add_library(grpc_unsecure src/core/tsi/local_transport_security.cc src/core/tsi/transport_security.cc src/core/tsi/transport_security_grpc.cc + src/core/util/http_client/format_request.cc + src/core/util/http_client/httpcli.cc + src/core/util/http_client/parser.cc src/core/util/json/json_object_loader.cc src/core/util/json/json_reader.cc src/core/util/json/json_writer.cc @@ -5203,6 +5218,7 @@ add_library(grpc_authorization_provider src/core/lib/event_engine/work_queue/basic_work_queue.cc src/core/lib/experiments/config.cc src/core/lib/experiments/experiments.cc + src/core/lib/gprpp/dump_args.cc src/core/lib/gprpp/load_file.cc src/core/lib/gprpp/per_cpu.cc src/core/lib/gprpp/ref_counted_string.cc @@ -8506,6 +8522,7 @@ add_executable(call_filters_test src/core/lib/debug/trace.cc src/core/lib/experiments/config.cc src/core/lib/experiments/experiments.cc + src/core/lib/gprpp/dump_args.cc src/core/lib/gprpp/ref_counted_string.cc src/core/lib/gprpp/status_helper.cc src/core/lib/gprpp/time.cc @@ -8518,8 +8535,11 @@ add_executable(call_filters_test src/core/lib/promise/activity.cc src/core/lib/promise/trace.cc src/core/lib/resource_quota/arena.cc + src/core/lib/resource_quota/connection_quota.cc src/core/lib/resource_quota/memory_quota.cc src/core/lib/resource_quota/periodic_update.cc + src/core/lib/resource_quota/resource_quota.cc + src/core/lib/resource_quota/thread_quota.cc src/core/lib/resource_quota/trace.cc src/core/lib/slice/percent_encoding.cc src/core/lib/slice/slice.cc @@ -10526,46 +10546,56 @@ target_link_libraries(client_channel_service_config_test endif() if(gRPC_BUILD_TESTS) +if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) -add_executable(client_channel_test - test/core/client_channel/client_channel_test.cc -) -if(WIN32 AND MSVC) - if(BUILD_SHARED_LIBS) - target_compile_definitions(client_channel_test - PRIVATE - "GPR_DLL_IMPORTS" - "GRPC_DLL_IMPORTS" - ) + add_executable(client_channel_test + ${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.pb.cc + ${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.grpc.pb.cc + ${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.pb.h + ${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.grpc.pb.h + test/core/call/yodel/test_main.cc + test/core/call/yodel/yodel_test.cc + test/core/client_channel/client_channel_test.cc + test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc + ) + if(WIN32 AND MSVC) + if(BUILD_SHARED_LIBS) + target_compile_definitions(client_channel_test + PRIVATE + "GPR_DLL_IMPORTS" + "GRPC_DLL_IMPORTS" + ) + endif() endif() -endif() -target_compile_features(client_channel_test PUBLIC cxx_std_14) -target_include_directories(client_channel_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_compile_features(client_channel_test PUBLIC cxx_std_14) + target_include_directories(client_channel_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(client_channel_test - ${_gRPC_ALLTARGETS_LIBRARIES} - gtest - grpc_test_util -) + target_link_libraries(client_channel_test + ${_gRPC_ALLTARGETS_LIBRARIES} + gtest + ${_gRPC_PROTOBUF_LIBRARIES} + grpc_test_util + ) +endif() endif() if(gRPC_BUILD_TESTS) @@ -11340,6 +11370,58 @@ target_link_libraries(concurrent_connectivity_test ) +endif() +if(gRPC_BUILD_TESTS) +if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) + + add_executable(connected_subchannel_test + ${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.pb.cc + ${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.grpc.pb.cc + ${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.pb.h + ${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.grpc.pb.h + test/core/call/yodel/test_main.cc + test/core/call/yodel/yodel_test.cc + test/core/client_channel/connected_subchannel_test.cc + test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc + ) + if(WIN32 AND MSVC) + if(BUILD_SHARED_LIBS) + target_compile_definitions(connected_subchannel_test + PRIVATE + "GPR_DLL_IMPORTS" + "GRPC_DLL_IMPORTS" + ) + endif() + endif() + target_compile_features(connected_subchannel_test PUBLIC cxx_std_14) + target_include_directories(connected_subchannel_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(connected_subchannel_test + ${_gRPC_ALLTARGETS_LIBRARIES} + gtest + ${_gRPC_PROTOBUF_LIBRARIES} + grpc_test_util + ) + + +endif() endif() if(gRPC_BUILD_TESTS) @@ -17562,15 +17644,15 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) ${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.grpc.pb.cc ${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.pb.h ${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.grpc.pb.h + test/core/call/yodel/test_main.cc + test/core/call/yodel/yodel_test.cc test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc test/core/transport/test_suite/call_content.cc test/core/transport/test_suite/call_shapes.cc - test/core/transport/test_suite/fixture.cc test/core/transport/test_suite/inproc_fixture.cc test/core/transport/test_suite/no_op.cc test/core/transport/test_suite/stress.cc - test/core/transport/test_suite/test.cc - test/core/transport/test_suite/test_main.cc + test/core/transport/test_suite/transport_test.cc ) if(WIN32 AND MSVC) if(BUILD_SHARED_LIBS) @@ -17832,6 +17914,7 @@ add_executable(interception_chain_test src/core/lib/event_engine/work_queue/basic_work_queue.cc src/core/lib/experiments/config.cc src/core/lib/experiments/experiments.cc + src/core/lib/gprpp/dump_args.cc src/core/lib/gprpp/load_file.cc src/core/lib/gprpp/per_cpu.cc src/core/lib/gprpp/ref_counted_string.cc @@ -18985,6 +19068,58 @@ target_link_libraries(lb_load_data_store_test ) +endif() +if(gRPC_BUILD_TESTS) +if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) + + add_executable(load_balanced_call_destination_test + ${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.pb.cc + ${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.grpc.pb.cc + ${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.pb.h + ${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.grpc.pb.h + test/core/call/yodel/test_main.cc + test/core/call/yodel/yodel_test.cc + test/core/client_channel/load_balanced_call_destination_test.cc + test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc + ) + if(WIN32 AND MSVC) + if(BUILD_SHARED_LIBS) + target_compile_definitions(load_balanced_call_destination_test + PRIVATE + "GPR_DLL_IMPORTS" + "GRPC_DLL_IMPORTS" + ) + endif() + endif() + target_compile_features(load_balanced_call_destination_test PUBLIC cxx_std_14) + target_include_directories(load_balanced_call_destination_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(load_balanced_call_destination_test + ${_gRPC_ALLTARGETS_LIBRARIES} + gtest + ${_gRPC_PROTOBUF_LIBRARIES} + grpc_test_util + ) + + +endif() endif() if(gRPC_BUILD_TESTS) @@ -29324,6 +29459,48 @@ target_link_libraries(string_test ) +endif() +if(gRPC_BUILD_TESTS) + +add_executable(subchannel_args_test + test/core/client_channel/subchannel_args_test.cc +) +if(WIN32 AND MSVC) + if(BUILD_SHARED_LIBS) + target_compile_definitions(subchannel_args_test + PRIVATE + "GPR_DLL_IMPORTS" + "GRPC_DLL_IMPORTS" + ) + endif() +endif() +target_compile_features(subchannel_args_test PUBLIC cxx_std_14) +target_include_directories(subchannel_args_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(subchannel_args_test + ${_gRPC_ALLTARGETS_LIBRARIES} + gtest + grpc_test_util +) + + endif() if(gRPC_BUILD_TESTS) @@ -30294,15 +30471,15 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) src/core/ext/transport/chaotic_good/frame_header.cc src/core/ext/transport/chaotic_good/server_transport.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/yodel/test_main.cc + test/core/call/yodel/yodel_test.cc test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc test/core/transport/test_suite/call_content.cc test/core/transport/test_suite/call_shapes.cc test/core/transport/test_suite/chaotic_good_fixture.cc - test/core/transport/test_suite/fixture.cc test/core/transport/test_suite/no_op.cc test/core/transport/test_suite/stress.cc - test/core/transport/test_suite/test.cc - test/core/transport/test_suite/test_main.cc + test/core/transport/test_suite/transport_test.cc ) if(WIN32 AND MSVC) if(BUILD_SHARED_LIBS) @@ -37015,3 +37192,14 @@ generate_pkgconfig( "-lgrpc++_unsecure" "-laddress_sorting -lupb_message_lib -lupb_mem_lib -lupb_base_lib -lutf8_range_lib" "grpc++_unsecure.pc") + +# grpcpp_otel_plugin .pc file +generate_pkgconfig( + "gRPC++ OpenTelemetry Plugin" + "OpenTelemetry Plugin for gRPC C++" + "${gRPC_CPP_VERSION}" + "absl_algorithm_container absl_any_invocable absl_base absl_bind_front absl_check absl_cleanup absl_config absl_cord absl_core_headers absl_flags absl_flags_marshalling absl_flat_hash_map absl_flat_hash_set absl_function_ref absl_hash absl_inlined_vector absl_log absl_log_globals absl_log_severity absl_memory absl_no_destructor absl_optional absl_random_bit_gen_ref absl_random_distributions absl_random_random absl_span absl_status absl_statusor absl_str_format absl_strings absl_synchronization absl_time absl_type_traits absl_utility absl_variant gpr grpc grpc++ opentelemetry_api" + "libcares openssl re2 zlib" + "-lgrpcpp_otel_plugin" + "-laddress_sorting -lupb_textformat_lib -lupb_json_lib -lupb_message_lib -lupb_mem_lib -lupb_base_lib -lutf8_range_lib" + "grpcpp_otel_plugin.pc") diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 5c36c24f156..3fefae1797b 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -31,6 +31,7 @@ for general contribution guidelines. - [pfreixes](https://github.com/pfreixes), Skyscanner Ltd - [ran-su](https://github.com/ran-su), Google LLC - [sanjaypujare](https://github.com/sanjaypujare), Google LLC +- [sastryvp](https://github.com/sastryvp), Google LLC - [sergiitk](https://github.com/sergiitk), Google LLC - [soheilhy](https://github.com/soheilhy), Google LLC - [stanley-cheung](https://github.com/stanley-cheung), Google LLC diff --git a/Makefile b/Makefile index 0cc5cc6a80b..fc3701d0415 100644 --- a/Makefile +++ b/Makefile @@ -670,6 +670,7 @@ LIBGRPC_SRC = \ src/core/channelz/channelz.cc \ src/core/channelz/channelz_registry.cc \ src/core/client_channel/backup_poller.cc \ + src/core/client_channel/client_channel.cc \ src/core/client_channel/client_channel_factory.cc \ src/core/client_channel/client_channel_filter.cc \ src/core/client_channel/client_channel_plugin.cc \ @@ -677,6 +678,7 @@ LIBGRPC_SRC = \ src/core/client_channel/config_selector.cc \ src/core/client_channel/dynamic_filters.cc \ src/core/client_channel/global_subchannel_pool.cc \ + src/core/client_channel/load_balanced_call_destination.cc \ src/core/client_channel/local_subchannel_pool.cc \ src/core/client_channel/retry_filter.cc \ src/core/client_channel/retry_filter_legacy_call_data.cc \ @@ -1137,6 +1139,7 @@ LIBGRPC_SRC = \ src/core/lib/experiments/config.cc \ src/core/lib/experiments/experiments.cc \ src/core/lib/gprpp/crash.cc \ + src/core/lib/gprpp/dump_args.cc \ src/core/lib/gprpp/examine_stack.cc \ src/core/lib/gprpp/fork.cc \ src/core/lib/gprpp/host_port.cc \ @@ -1162,10 +1165,6 @@ LIBGRPC_SRC = \ src/core/lib/gprpp/windows/stat.cc \ src/core/lib/gprpp/windows/thd.cc \ src/core/lib/gprpp/work_serializer.cc \ - src/core/lib/http/format_request.cc \ - src/core/lib/http/httpcli.cc \ - src/core/lib/http/httpcli_security_connector.cc \ - src/core/lib/http/parser.cc \ src/core/lib/iomgr/buffer_list.cc \ src/core/lib/iomgr/call_combiner.cc \ src/core/lib/iomgr/cfstream_handle.cc \ @@ -1458,6 +1457,10 @@ LIBGRPC_SRC = \ src/core/util/alloc.cc \ src/core/util/android/log.cc \ src/core/util/atm.cc \ + src/core/util/http_client/format_request.cc \ + src/core/util/http_client/httpcli.cc \ + src/core/util/http_client/httpcli_security_connector.cc \ + src/core/util/http_client/parser.cc \ src/core/util/iphone/cpu.cc \ src/core/util/json/json_object_loader.cc \ src/core/util/json/json_reader.cc \ @@ -1935,6 +1938,7 @@ LIBBORINGSSL_SRC = \ third_party/boringssl-with-bazel/src/crypto/dh_extra/dh_asn1.c \ third_party/boringssl-with-bazel/src/crypto/dh_extra/params.c \ third_party/boringssl-with-bazel/src/crypto/digest_extra/digest_extra.c \ + third_party/boringssl-with-bazel/src/crypto/dilithium/dilithium.c \ third_party/boringssl-with-bazel/src/crypto/dsa/dsa.c \ third_party/boringssl-with-bazel/src/crypto/dsa/dsa_asn1.c \ third_party/boringssl-with-bazel/src/crypto/ec_extra/ec_asn1.c \ diff --git a/Package.swift b/Package.swift index 75efbc101c2..6b411d73c85 100644 --- a/Package.swift +++ b/Package.swift @@ -126,6 +126,8 @@ let package = Package( "src/core/channelz/channelz_registry.h", "src/core/client_channel/backup_poller.cc", "src/core/client_channel/backup_poller.h", + "src/core/client_channel/client_channel.cc", + "src/core/client_channel/client_channel.h", "src/core/client_channel/client_channel_factory.cc", "src/core/client_channel/client_channel_factory.h", "src/core/client_channel/client_channel_filter.cc", @@ -141,6 +143,8 @@ let package = Package( "src/core/client_channel/dynamic_filters.h", "src/core/client_channel/global_subchannel_pool.cc", "src/core/client_channel/global_subchannel_pool.h", + "src/core/client_channel/load_balanced_call_destination.cc", + "src/core/client_channel/load_balanced_call_destination.h", "src/core/client_channel/local_subchannel_pool.cc", "src/core/client_channel/local_subchannel_pool.h", "src/core/client_channel/retry_filter.cc", @@ -1255,6 +1259,8 @@ let package = Package( "src/core/lib/gprpp/directory_reader.h", "src/core/lib/gprpp/down_cast.h", "src/core/lib/gprpp/dual_ref_counted.h", + "src/core/lib/gprpp/dump_args.cc", + "src/core/lib/gprpp/dump_args.h", "src/core/lib/gprpp/env.h", "src/core/lib/gprpp/examine_stack.cc", "src/core/lib/gprpp/examine_stack.h", @@ -1317,14 +1323,6 @@ let package = Package( "src/core/lib/gprpp/work_serializer.cc", "src/core/lib/gprpp/work_serializer.h", "src/core/lib/gprpp/xxhash_inline.h", - "src/core/lib/http/format_request.cc", - "src/core/lib/http/format_request.h", - "src/core/lib/http/httpcli.cc", - "src/core/lib/http/httpcli.h", - "src/core/lib/http/httpcli_security_connector.cc", - "src/core/lib/http/httpcli_ssl_credentials.h", - "src/core/lib/http/parser.cc", - "src/core/lib/http/parser.h", "src/core/lib/iomgr/block_annotate.h", "src/core/lib/iomgr/buffer_list.cc", "src/core/lib/iomgr/buffer_list.h", @@ -1488,6 +1486,7 @@ let package = Package( "src/core/lib/promise/latch.h", "src/core/lib/promise/loop.h", "src/core/lib/promise/map.h", + "src/core/lib/promise/observable.h", "src/core/lib/promise/party.cc", "src/core/lib/promise/party.h", "src/core/lib/promise/pipe.h", @@ -1917,6 +1916,14 @@ let package = Package( "src/core/util/alloc.h", "src/core/util/android/log.cc", "src/core/util/atm.cc", + "src/core/util/http_client/format_request.cc", + "src/core/util/http_client/format_request.h", + "src/core/util/http_client/httpcli.cc", + "src/core/util/http_client/httpcli.h", + "src/core/util/http_client/httpcli_security_connector.cc", + "src/core/util/http_client/httpcli_ssl_credentials.h", + "src/core/util/http_client/parser.cc", + "src/core/util/http_client/parser.h", "src/core/util/iphone/cpu.cc", "src/core/util/json/json.h", "src/core/util/json/json_args.h", diff --git a/bazel/experiments.bzl b/bazel/experiments.bzl index e3aeb05464d..8dffc68bf21 100644 --- a/bazel/experiments.bzl +++ b/bazel/experiments.bzl @@ -18,7 +18,6 @@ EXPERIMENT_ENABLES = { "call_status_override_on_cancellation": "call_status_override_on_cancellation", - "call_v3": "call_v3", "canary_client_privacy": "canary_client_privacy", "client_privacy": "client_privacy", "event_engine_client": "event_engine_client", @@ -28,6 +27,7 @@ EXPERIMENT_ENABLES = { "http2_stats_fix": "http2_stats_fix", "keepalive_fix": "keepalive_fix", "keepalive_server_fix": "keepalive_server_fix", + "max_pings_wo_data_throttle": "max_pings_wo_data_throttle", "monitoring_experiment": "monitoring_experiment", "multiping": "multiping", "peer_state_based_framing": "peer_state_based_framing", @@ -44,6 +44,7 @@ EXPERIMENT_ENABLES = { "unconstrained_max_quota_buffer_size": "unconstrained_max_quota_buffer_size", "work_serializer_clears_time_cache": "work_serializer_clears_time_cache", "work_serializer_dispatch": "event_engine_client,work_serializer_dispatch", + "call_v3": "call_v3,event_engine_client,event_engine_listener,work_serializer_dispatch", } EXPERIMENT_POLLERS = [ @@ -57,10 +58,16 @@ EXPERIMENTS = { "dbg": { }, "off": { + "core_end2end_test": [ + "event_engine_client", + ], "endpoint_test": [ "tcp_frame_size_tuning", "tcp_rcv_lowat", ], + "event_engine_client_test": [ + "event_engine_client", + ], "flow_control_test": [ "multiping", "peer_state_based_framing", @@ -78,15 +85,11 @@ EXPERIMENTS = { "event_engine_dns", ], "core_end2end_test": [ - "event_engine_client", "event_engine_listener", ], "cpp_lb_end2end_test": [ "pick_first_new", ], - "event_engine_client_test": [ - "event_engine_client", - ], "event_engine_listener_test": [ "event_engine_listener", ], diff --git a/bazel/grpc_build_system.bzl b/bazel/grpc_build_system.bzl index e26b1b34873..153002b7d57 100644 --- a/bazel/grpc_build_system.bzl +++ b/bazel/grpc_build_system.bzl @@ -235,6 +235,7 @@ def grpc_proto_library( name, srcs = [], deps = [], + visibility = None, well_known_protos = False, has_services = True, use_external = False, @@ -243,6 +244,7 @@ def grpc_proto_library( name = name, srcs = srcs, deps = deps, + visibility = visibility, well_known_protos = well_known_protos, proto_only = not has_services, use_external = use_external, diff --git a/bazel/grpc_deps.bzl b/bazel/grpc_deps.bzl index d0099ab6163..caa68583f6d 100644 --- a/bazel/grpc_deps.bzl +++ b/bazel/grpc_deps.bzl @@ -190,11 +190,11 @@ def grpc_deps(): name = "boringssl", # Use github mirror instead of https://boringssl.googlesource.com/boringssl # to obtain a boringssl archive with consistent sha256 - sha256 = "c4cccc0ea8b149d2853da77254655c0d5a5739dd4bbdff9a5b586c06a627de6c", - strip_prefix = "boringssl-5a2bca2124800f2861263959b72bc35cdf18949b", + sha256 = "9f441d72fccb9a3faf96470478c8ccfaaeb8db1cffd4d78b698f782124dad1b0", + strip_prefix = "boringssl-b8a2bffc598f230484ff48a247526a9820facfc2", urls = [ - "https://storage.googleapis.com/grpc-bazel-mirror/github.com/google/boringssl/archive/5a2bca2124800f2861263959b72bc35cdf18949b.tar.gz", - "https://github.com/google/boringssl/archive/5a2bca2124800f2861263959b72bc35cdf18949b.tar.gz", + "https://storage.googleapis.com/grpc-bazel-mirror/github.com/google/boringssl/archive/b8a2bffc598f230484ff48a247526a9820facfc2.tar.gz", + "https://github.com/google/boringssl/archive/b8a2bffc598f230484ff48a247526a9820facfc2.tar.gz", ], ) @@ -406,10 +406,10 @@ def grpc_deps(): if "bazel_gazelle" not in native.existing_rules(): http_archive( name = "bazel_gazelle", - sha256 = "de69a09dc70417580aabf20a28619bb3ef60d038470c7cf8442fafcf627c21cb", + sha256 = "d76bf7a60fd8b050444090dfa2837a4eaf9829e1165618ee35dceca5cbdf58d5", urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.24.0/bazel-gazelle-v0.24.0.tar.gz", - "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.24.0/bazel-gazelle-v0.24.0.tar.gz", + "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz", + "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz", ], ) diff --git a/bazel/grpc_extra_deps.bzl b/bazel/grpc_extra_deps.bzl index eb3c3fc29c5..a370fe44966 100644 --- a/bazel/grpc_extra_deps.bzl +++ b/bazel/grpc_extra_deps.bzl @@ -52,7 +52,7 @@ def grpc_extra_deps(ignore_version_differences = False): api_dependencies() go_rules_dependencies() - go_register_toolchains(version = "1.18") + go_register_toolchains(version = "1.20") gazelle_dependencies() # Pull-in the go 3rd party dependencies for protoc_gen_validate, which is diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index b505f641e0f..26b1d9d6beb 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -227,6 +227,7 @@ libs: - src/core/channelz/channelz.h - src/core/channelz/channelz_registry.h - src/core/client_channel/backup_poller.h + - src/core/client_channel/client_channel.h - src/core/client_channel/client_channel_factory.h - src/core/client_channel/client_channel_filter.h - src/core/client_channel/client_channel_internal.h @@ -235,6 +236,7 @@ libs: - src/core/client_channel/connector.h - src/core/client_channel/dynamic_filters.h - src/core/client_channel/global_subchannel_pool.h + - src/core/client_channel/load_balanced_call_destination.h - src/core/client_channel/local_subchannel_pool.h - src/core/client_channel/retry_filter.h - src/core/client_channel/retry_filter_legacy_call_data.h @@ -883,6 +885,7 @@ libs: - src/core/lib/gprpp/directory_reader.h - src/core/lib/gprpp/down_cast.h - src/core/lib/gprpp/dual_ref_counted.h + - src/core/lib/gprpp/dump_args.h - src/core/lib/gprpp/if_list.h - src/core/lib/gprpp/load_file.h - src/core/lib/gprpp/manual_constructor.h @@ -907,10 +910,6 @@ libs: - src/core/lib/gprpp/validation_errors.h - src/core/lib/gprpp/work_serializer.h - src/core/lib/gprpp/xxhash_inline.h - - src/core/lib/http/format_request.h - - src/core/lib/http/httpcli.h - - src/core/lib/http/httpcli_ssl_credentials.h - - src/core/lib/http/parser.h - src/core/lib/iomgr/block_annotate.h - src/core/lib/iomgr/buffer_list.h - src/core/lib/iomgr/call_combiner.h @@ -995,6 +994,7 @@ libs: - src/core/lib/promise/latch.h - src/core/lib/promise/loop.h - src/core/lib/promise/map.h + - src/core/lib/promise/observable.h - src/core/lib/promise/party.h - src/core/lib/promise/pipe.h - src/core/lib/promise/poll.h @@ -1206,6 +1206,10 @@ libs: - src/core/tsi/transport_security.h - src/core/tsi/transport_security_grpc.h - src/core/tsi/transport_security_interface.h + - src/core/util/http_client/format_request.h + - src/core/util/http_client/httpcli.h + - src/core/util/http_client/httpcli_ssl_credentials.h + - src/core/util/http_client/parser.h - src/core/util/json/json.h - src/core/util/json/json_args.h - src/core/util/json/json_channel_args.h @@ -1251,6 +1255,7 @@ libs: - src/core/channelz/channelz.cc - src/core/channelz/channelz_registry.cc - src/core/client_channel/backup_poller.cc + - src/core/client_channel/client_channel.cc - src/core/client_channel/client_channel_factory.cc - src/core/client_channel/client_channel_filter.cc - src/core/client_channel/client_channel_plugin.cc @@ -1258,6 +1263,7 @@ libs: - src/core/client_channel/config_selector.cc - src/core/client_channel/dynamic_filters.cc - src/core/client_channel/global_subchannel_pool.cc + - src/core/client_channel/load_balanced_call_destination.cc - src/core/client_channel/local_subchannel_pool.cc - src/core/client_channel/retry_filter.cc - src/core/client_channel/retry_filter_legacy_call_data.cc @@ -1713,6 +1719,7 @@ libs: - src/core/lib/event_engine/work_queue/basic_work_queue.cc - src/core/lib/experiments/config.cc - src/core/lib/experiments/experiments.cc + - src/core/lib/gprpp/dump_args.cc - src/core/lib/gprpp/load_file.cc - src/core/lib/gprpp/per_cpu.cc - src/core/lib/gprpp/posix/directory_reader.cc @@ -1724,10 +1731,6 @@ libs: - src/core/lib/gprpp/validation_errors.cc - src/core/lib/gprpp/windows/directory_reader.cc - src/core/lib/gprpp/work_serializer.cc - - src/core/lib/http/format_request.cc - - src/core/lib/http/httpcli.cc - - src/core/lib/http/httpcli_security_connector.cc - - src/core/lib/http/parser.cc - src/core/lib/iomgr/buffer_list.cc - src/core/lib/iomgr/call_combiner.cc - src/core/lib/iomgr/cfstream_handle.cc @@ -2017,6 +2020,10 @@ libs: - src/core/tsi/ssl_transport_security_utils.cc - src/core/tsi/transport_security.cc - src/core/tsi/transport_security_grpc.cc + - src/core/util/http_client/format_request.cc + - src/core/util/http_client/httpcli.cc + - src/core/util/http_client/httpcli_security_connector.cc + - src/core/util/http_client/parser.cc - src/core/util/json/json_object_loader.cc - src/core/util/json/json_reader.cc - src/core/util/json/json_util.cc @@ -2215,6 +2222,7 @@ libs: - src/core/channelz/channelz.h - src/core/channelz/channelz_registry.h - src/core/client_channel/backup_poller.h + - src/core/client_channel/client_channel.h - src/core/client_channel/client_channel_factory.h - src/core/client_channel/client_channel_filter.h - src/core/client_channel/client_channel_internal.h @@ -2223,6 +2231,7 @@ libs: - src/core/client_channel/connector.h - src/core/client_channel/dynamic_filters.h - src/core/client_channel/global_subchannel_pool.h + - src/core/client_channel/load_balanced_call_destination.h - src/core/client_channel/local_subchannel_pool.h - src/core/client_channel/retry_filter.h - src/core/client_channel/retry_filter_legacy_call_data.h @@ -2420,6 +2429,7 @@ libs: - src/core/lib/gprpp/cpp_impl_of.h - src/core/lib/gprpp/down_cast.h - src/core/lib/gprpp/dual_ref_counted.h + - src/core/lib/gprpp/dump_args.h - src/core/lib/gprpp/if_list.h - src/core/lib/gprpp/load_file.h - src/core/lib/gprpp/manual_constructor.h @@ -2443,9 +2453,6 @@ libs: - src/core/lib/gprpp/uuid_v4.h - src/core/lib/gprpp/validation_errors.h - src/core/lib/gprpp/work_serializer.h - - src/core/lib/http/format_request.h - - src/core/lib/http/httpcli.h - - src/core/lib/http/parser.h - src/core/lib/iomgr/block_annotate.h - src/core/lib/iomgr/buffer_list.h - src/core/lib/iomgr/call_combiner.h @@ -2529,6 +2536,7 @@ libs: - src/core/lib/promise/latch.h - src/core/lib/promise/loop.h - src/core/lib/promise/map.h + - src/core/lib/promise/observable.h - src/core/lib/promise/party.h - src/core/lib/promise/pipe.h - src/core/lib/promise/poll.h @@ -2677,6 +2685,9 @@ libs: - src/core/tsi/transport_security.h - src/core/tsi/transport_security_grpc.h - src/core/tsi/transport_security_interface.h + - src/core/util/http_client/format_request.h + - src/core/util/http_client/httpcli.h + - src/core/util/http_client/parser.h - src/core/util/json/json.h - src/core/util/json/json_args.h - src/core/util/json/json_channel_args.h @@ -2708,6 +2719,7 @@ libs: - src/core/channelz/channelz.cc - src/core/channelz/channelz_registry.cc - src/core/client_channel/backup_poller.cc + - src/core/client_channel/client_channel.cc - src/core/client_channel/client_channel_factory.cc - src/core/client_channel/client_channel_filter.cc - src/core/client_channel/client_channel_plugin.cc @@ -2715,6 +2727,7 @@ libs: - src/core/client_channel/config_selector.cc - src/core/client_channel/dynamic_filters.cc - src/core/client_channel/global_subchannel_pool.cc + - src/core/client_channel/load_balanced_call_destination.cc - src/core/client_channel/local_subchannel_pool.cc - src/core/client_channel/retry_filter.cc - src/core/client_channel/retry_filter_legacy_call_data.cc @@ -2866,6 +2879,7 @@ libs: - src/core/lib/event_engine/work_queue/basic_work_queue.cc - src/core/lib/experiments/config.cc - src/core/lib/experiments/experiments.cc + - src/core/lib/gprpp/dump_args.cc - src/core/lib/gprpp/load_file.cc - src/core/lib/gprpp/per_cpu.cc - src/core/lib/gprpp/ref_counted_string.cc @@ -2875,9 +2889,6 @@ libs: - src/core/lib/gprpp/uuid_v4.cc - src/core/lib/gprpp/validation_errors.cc - src/core/lib/gprpp/work_serializer.cc - - src/core/lib/http/format_request.cc - - src/core/lib/http/httpcli.cc - - src/core/lib/http/parser.cc - src/core/lib/iomgr/buffer_list.cc - src/core/lib/iomgr/call_combiner.cc - src/core/lib/iomgr/cfstream_handle.cc @@ -3095,6 +3106,9 @@ libs: - src/core/tsi/local_transport_security.cc - src/core/tsi/transport_security.cc - src/core/tsi/transport_security_grpc.cc + - src/core/util/http_client/format_request.cc + - src/core/util/http_client/httpcli.cc + - src/core/util/http_client/parser.cc - src/core/util/json/json_object_loader.cc - src/core/util/json/json_reader.cc - src/core/util/json/json_writer.cc @@ -4510,6 +4524,7 @@ libs: - src/core/lib/gprpp/cpp_impl_of.h - src/core/lib/gprpp/down_cast.h - src/core/lib/gprpp/dual_ref_counted.h + - src/core/lib/gprpp/dump_args.h - src/core/lib/gprpp/if_list.h - src/core/lib/gprpp/load_file.h - src/core/lib/gprpp/manual_constructor.h @@ -4618,6 +4633,7 @@ libs: - src/core/lib/promise/party.h - src/core/lib/promise/pipe.h - src/core/lib/promise/poll.h + - src/core/lib/promise/prioritized_race.h - src/core/lib/promise/promise.h - src/core/lib/promise/race.h - src/core/lib/promise/seq.h @@ -4833,6 +4849,7 @@ libs: - src/core/lib/event_engine/work_queue/basic_work_queue.cc - src/core/lib/experiments/config.cc - src/core/lib/experiments/experiments.cc + - src/core/lib/gprpp/dump_args.cc - src/core/lib/gprpp/load_file.cc - src/core/lib/gprpp/per_cpu.cc - src/core/lib/gprpp/ref_counted_string.cc @@ -6376,8 +6393,10 @@ targets: - src/core/lib/gprpp/atomic_utils.h - src/core/lib/gprpp/bitset.h - src/core/lib/gprpp/chunked_vector.h + - src/core/lib/gprpp/cpp_impl_of.h - src/core/lib/gprpp/down_cast.h - src/core/lib/gprpp/dual_ref_counted.h + - src/core/lib/gprpp/dump_args.h - src/core/lib/gprpp/if_list.h - src/core/lib/gprpp/manual_constructor.h - src/core/lib/gprpp/orphanable.h @@ -6414,8 +6433,11 @@ targets: - src/core/lib/promise/status_flag.h - src/core/lib/promise/trace.h - src/core/lib/resource_quota/arena.h + - src/core/lib/resource_quota/connection_quota.h - src/core/lib/resource_quota/memory_quota.h - src/core/lib/resource_quota/periodic_update.h + - src/core/lib/resource_quota/resource_quota.h + - src/core/lib/resource_quota/thread_quota.h - src/core/lib/resource_quota/trace.h - src/core/lib/slice/percent_encoding.h - src/core/lib/slice/slice.h @@ -6468,6 +6490,7 @@ targets: - src/core/lib/debug/trace.cc - src/core/lib/experiments/config.cc - src/core/lib/experiments/experiments.cc + - src/core/lib/gprpp/dump_args.cc - src/core/lib/gprpp/ref_counted_string.cc - src/core/lib/gprpp/status_helper.cc - src/core/lib/gprpp/time.cc @@ -6480,8 +6503,11 @@ targets: - src/core/lib/promise/activity.cc - src/core/lib/promise/trace.cc - src/core/lib/resource_quota/arena.cc + - src/core/lib/resource_quota/connection_quota.cc - src/core/lib/resource_quota/memory_quota.cc - src/core/lib/resource_quota/periodic_update.cc + - src/core/lib/resource_quota/resource_quota.cc + - src/core/lib/resource_quota/thread_quota.cc - src/core/lib/resource_quota/trace.cc - src/core/lib/slice/percent_encoding.cc - src/core/lib/slice/slice.cc @@ -7869,12 +7895,22 @@ targets: gtest: true build: test language: c++ - headers: [] + headers: + - test/core/call/yodel/yodel_test.h + - test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h src: + - test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.proto + - test/core/call/yodel/test_main.cc + - test/core/call/yodel/yodel_test.cc - test/core/client_channel/client_channel_test.cc + - test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc deps: - gtest + - protobuf - grpc_test_util + platforms: + - linux + - posix uses_polling: false - name: client_context_test_peer_test gtest: true @@ -8225,6 +8261,27 @@ targets: deps: - gtest - grpc_test_util +- name: connected_subchannel_test + gtest: true + build: test + language: c++ + headers: + - test/core/call/yodel/yodel_test.h + - test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h + src: + - test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.proto + - test/core/call/yodel/test_main.cc + - test/core/call/yodel/yodel_test.cc + - test/core/client_channel/connected_subchannel_test.cc + - test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc + deps: + - gtest + - protobuf + - grpc_test_util + platforms: + - linux + - posix + uses_polling: false - name: connection_prefix_bad_client_test gtest: true build: test @@ -11453,20 +11510,20 @@ targets: build: test language: c++ headers: + - test/core/call/yodel/yodel_test.h - test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h - - test/core/transport/test_suite/fixture.h - - test/core/transport/test_suite/test.h + - test/core/transport/test_suite/transport_test.h src: - test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.proto + - test/core/call/yodel/test_main.cc + - test/core/call/yodel/yodel_test.cc - test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc - test/core/transport/test_suite/call_content.cc - test/core/transport/test_suite/call_shapes.cc - - test/core/transport/test_suite/fixture.cc - test/core/transport/test_suite/inproc_fixture.cc - test/core/transport/test_suite/no_op.cc - test/core/transport/test_suite/stress.cc - - test/core/transport/test_suite/test.cc - - test/core/transport/test_suite/test_main.cc + - test/core/transport/test_suite/transport_test.cc deps: - gtest - protobuf @@ -11669,6 +11726,7 @@ targets: - src/core/lib/gprpp/cpp_impl_of.h - src/core/lib/gprpp/down_cast.h - src/core/lib/gprpp/dual_ref_counted.h + - src/core/lib/gprpp/dump_args.h - src/core/lib/gprpp/if_list.h - src/core/lib/gprpp/load_file.h - src/core/lib/gprpp/manual_constructor.h @@ -11776,6 +11834,7 @@ targets: - src/core/lib/promise/party.h - src/core/lib/promise/pipe.h - src/core/lib/promise/poll.h + - src/core/lib/promise/prioritized_race.h - src/core/lib/promise/promise.h - src/core/lib/promise/race.h - src/core/lib/promise/seq.h @@ -11961,6 +12020,7 @@ targets: - src/core/lib/event_engine/work_queue/basic_work_queue.cc - src/core/lib/experiments/config.cc - src/core/lib/experiments/experiments.cc + - src/core/lib/gprpp/dump_args.cc - src/core/lib/gprpp/load_file.cc - src/core/lib/gprpp/per_cpu.cc - src/core/lib/gprpp/ref_counted_string.cc @@ -12733,6 +12793,27 @@ targets: - gtest - grpc++ - grpc_test_util +- name: load_balanced_call_destination_test + gtest: true + build: test + language: c++ + headers: + - test/core/call/yodel/yodel_test.h + - test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h + src: + - test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.proto + - test/core/call/yodel/test_main.cc + - test/core/call/yodel/yodel_test.cc + - test/core/client_channel/load_balanced_call_destination_test.cc + - test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc + deps: + - gtest + - protobuf + - grpc_test_util + platforms: + - linux + - posix + uses_polling: false - name: load_config_test gtest: true build: test @@ -14639,6 +14720,7 @@ targets: - src/core/lib/promise/map.h - src/core/lib/promise/poll.h - src/core/lib/promise/promise.h + - test/core/promise/poll_matcher.h src: - test/core/promise/map_test.cc deps: @@ -18993,6 +19075,17 @@ targets: - gtest - grpc_test_util uses_polling: false +- name: subchannel_args_test + gtest: true + build: test + language: c++ + headers: [] + src: + - test/core/client_channel/subchannel_args_test.cc + deps: + - gtest + - grpc_test_util + uses_polling: false - name: switch_test gtest: true build: test @@ -19488,9 +19581,9 @@ targets: - src/core/lib/promise/switch.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/yodel/yodel_test.h - test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h - - test/core/transport/test_suite/fixture.h - - test/core/transport/test_suite/test.h + - test/core/transport/test_suite/transport_test.h src: - test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.proto - src/core/ext/transport/chaotic_good/chaotic_good_transport.cc @@ -19499,15 +19592,15 @@ targets: - src/core/ext/transport/chaotic_good/frame_header.cc - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/yodel/test_main.cc + - test/core/call/yodel/yodel_test.cc - test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc - test/core/transport/test_suite/call_content.cc - test/core/transport/test_suite/call_shapes.cc - test/core/transport/test_suite/chaotic_good_fixture.cc - - test/core/transport/test_suite/fixture.cc - test/core/transport/test_suite/no_op.cc - test/core/transport/test_suite/stress.cc - - test/core/transport/test_suite/test.cc - - test/core/transport/test_suite/test_main.cc + - test/core/transport/test_suite/transport_test.cc deps: - gtest - protobuf diff --git a/config.m4 b/config.m4 index 804c3aa0de5..695063579c5 100644 --- a/config.m4 +++ b/config.m4 @@ -45,6 +45,7 @@ if test "$PHP_GRPC" != "no"; then src/core/channelz/channelz.cc \ src/core/channelz/channelz_registry.cc \ src/core/client_channel/backup_poller.cc \ + src/core/client_channel/client_channel.cc \ src/core/client_channel/client_channel_factory.cc \ src/core/client_channel/client_channel_filter.cc \ src/core/client_channel/client_channel_plugin.cc \ @@ -52,6 +53,7 @@ if test "$PHP_GRPC" != "no"; then src/core/client_channel/config_selector.cc \ src/core/client_channel/dynamic_filters.cc \ src/core/client_channel/global_subchannel_pool.cc \ + src/core/client_channel/load_balanced_call_destination.cc \ src/core/client_channel/local_subchannel_pool.cc \ src/core/client_channel/retry_filter.cc \ src/core/client_channel/retry_filter_legacy_call_data.cc \ @@ -512,6 +514,7 @@ if test "$PHP_GRPC" != "no"; then src/core/lib/experiments/config.cc \ src/core/lib/experiments/experiments.cc \ src/core/lib/gprpp/crash.cc \ + src/core/lib/gprpp/dump_args.cc \ src/core/lib/gprpp/examine_stack.cc \ src/core/lib/gprpp/fork.cc \ src/core/lib/gprpp/host_port.cc \ @@ -537,10 +540,6 @@ if test "$PHP_GRPC" != "no"; then src/core/lib/gprpp/windows/stat.cc \ src/core/lib/gprpp/windows/thd.cc \ src/core/lib/gprpp/work_serializer.cc \ - src/core/lib/http/format_request.cc \ - src/core/lib/http/httpcli.cc \ - src/core/lib/http/httpcli_security_connector.cc \ - src/core/lib/http/parser.cc \ src/core/lib/iomgr/buffer_list.cc \ src/core/lib/iomgr/call_combiner.cc \ src/core/lib/iomgr/cfstream_handle.cc \ @@ -833,6 +832,10 @@ if test "$PHP_GRPC" != "no"; then src/core/util/alloc.cc \ src/core/util/android/log.cc \ src/core/util/atm.cc \ + src/core/util/http_client/format_request.cc \ + src/core/util/http_client/httpcli.cc \ + src/core/util/http_client/httpcli_security_connector.cc \ + src/core/util/http_client/parser.cc \ src/core/util/iphone/cpu.cc \ src/core/util/json/json_object_loader.cc \ src/core/util/json/json_reader.cc \ @@ -1112,6 +1115,7 @@ if test "$PHP_GRPC" != "no"; then third_party/boringssl-with-bazel/src/crypto/dh_extra/dh_asn1.c \ third_party/boringssl-with-bazel/src/crypto/dh_extra/params.c \ third_party/boringssl-with-bazel/src/crypto/digest_extra/digest_extra.c \ + third_party/boringssl-with-bazel/src/crypto/dilithium/dilithium.c \ third_party/boringssl-with-bazel/src/crypto/dsa/dsa.c \ third_party/boringssl-with-bazel/src/crypto/dsa/dsa_asn1.c \ third_party/boringssl-with-bazel/src/crypto/ec_extra/ec_asn1.c \ @@ -1530,7 +1534,6 @@ if test "$PHP_GRPC" != "no"; then PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/gprpp/linux) PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/gprpp/posix) PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/gprpp/windows) - PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/http) PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/iomgr) PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/iomgr/event_engine_shims) PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/matchers) @@ -1601,6 +1604,7 @@ if test "$PHP_GRPC" != "no"; then PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi/ssl/session_cache) PHP_ADD_BUILD_DIR($ext_builddir/src/core/util) PHP_ADD_BUILD_DIR($ext_builddir/src/core/util/android) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/util/http_client) PHP_ADD_BUILD_DIR($ext_builddir/src/core/util/iphone) PHP_ADD_BUILD_DIR($ext_builddir/src/core/util/json) PHP_ADD_BUILD_DIR($ext_builddir/src/core/util/linux) @@ -1652,6 +1656,7 @@ if test "$PHP_GRPC" != "no"; then PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl-with-bazel/src/crypto/des) PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl-with-bazel/src/crypto/dh_extra) PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl-with-bazel/src/crypto/digest_extra) + PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl-with-bazel/src/crypto/dilithium) PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl-with-bazel/src/crypto/dsa) PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl-with-bazel/src/crypto/ec_extra) PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl-with-bazel/src/crypto/ecdh_extra) diff --git a/config.w32 b/config.w32 index 9bf2bf2d20d..85a32dc6704 100644 --- a/config.w32 +++ b/config.w32 @@ -10,6 +10,7 @@ if (PHP_GRPC != "no") { "src\\core\\channelz\\channelz.cc " + "src\\core\\channelz\\channelz_registry.cc " + "src\\core\\client_channel\\backup_poller.cc " + + "src\\core\\client_channel\\client_channel.cc " + "src\\core\\client_channel\\client_channel_factory.cc " + "src\\core\\client_channel\\client_channel_filter.cc " + "src\\core\\client_channel\\client_channel_plugin.cc " + @@ -17,6 +18,7 @@ if (PHP_GRPC != "no") { "src\\core\\client_channel\\config_selector.cc " + "src\\core\\client_channel\\dynamic_filters.cc " + "src\\core\\client_channel\\global_subchannel_pool.cc " + + "src\\core\\client_channel\\load_balanced_call_destination.cc " + "src\\core\\client_channel\\local_subchannel_pool.cc " + "src\\core\\client_channel\\retry_filter.cc " + "src\\core\\client_channel\\retry_filter_legacy_call_data.cc " + @@ -477,6 +479,7 @@ if (PHP_GRPC != "no") { "src\\core\\lib\\experiments\\config.cc " + "src\\core\\lib\\experiments\\experiments.cc " + "src\\core\\lib\\gprpp\\crash.cc " + + "src\\core\\lib\\gprpp\\dump_args.cc " + "src\\core\\lib\\gprpp\\examine_stack.cc " + "src\\core\\lib\\gprpp\\fork.cc " + "src\\core\\lib\\gprpp\\host_port.cc " + @@ -502,10 +505,6 @@ if (PHP_GRPC != "no") { "src\\core\\lib\\gprpp\\windows\\stat.cc " + "src\\core\\lib\\gprpp\\windows\\thd.cc " + "src\\core\\lib\\gprpp\\work_serializer.cc " + - "src\\core\\lib\\http\\format_request.cc " + - "src\\core\\lib\\http\\httpcli.cc " + - "src\\core\\lib\\http\\httpcli_security_connector.cc " + - "src\\core\\lib\\http\\parser.cc " + "src\\core\\lib\\iomgr\\buffer_list.cc " + "src\\core\\lib\\iomgr\\call_combiner.cc " + "src\\core\\lib\\iomgr\\cfstream_handle.cc " + @@ -798,6 +797,10 @@ if (PHP_GRPC != "no") { "src\\core\\util\\alloc.cc " + "src\\core\\util\\android\\log.cc " + "src\\core\\util\\atm.cc " + + "src\\core\\util\\http_client\\format_request.cc " + + "src\\core\\util\\http_client\\httpcli.cc " + + "src\\core\\util\\http_client\\httpcli_security_connector.cc " + + "src\\core\\util\\http_client\\parser.cc " + "src\\core\\util\\iphone\\cpu.cc " + "src\\core\\util\\json\\json_object_loader.cc " + "src\\core\\util\\json\\json_reader.cc " + @@ -1077,6 +1080,7 @@ if (PHP_GRPC != "no") { "third_party\\boringssl-with-bazel\\src\\crypto\\dh_extra\\dh_asn1.c " + "third_party\\boringssl-with-bazel\\src\\crypto\\dh_extra\\params.c " + "third_party\\boringssl-with-bazel\\src\\crypto\\digest_extra\\digest_extra.c " + + "third_party\\boringssl-with-bazel\\src\\crypto\\dilithium\\dilithium.c " + "third_party\\boringssl-with-bazel\\src\\crypto\\dsa\\dsa.c " + "third_party\\boringssl-with-bazel\\src\\crypto\\dsa\\dsa_asn1.c " + "third_party\\boringssl-with-bazel\\src\\crypto\\ec_extra\\ec_asn1.c " + @@ -1667,7 +1671,6 @@ if (PHP_GRPC != "no") { FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\gprpp\\linux"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\gprpp\\posix"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\gprpp\\windows"); - FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\http"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\iomgr"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\iomgr\\event_engine_shims"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\matchers"); @@ -1741,6 +1744,7 @@ if (PHP_GRPC != "no") { FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\tsi\\ssl\\session_cache"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\util"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\util\\android"); + FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\util\\http_client"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\util\\iphone"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\util\\json"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\util\\linux"); @@ -1805,6 +1809,7 @@ if (PHP_GRPC != "no") { FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl-with-bazel\\src\\crypto\\des"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl-with-bazel\\src\\crypto\\dh_extra"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl-with-bazel\\src\\crypto\\digest_extra"); + FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl-with-bazel\\src\\crypto\\dilithium"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl-with-bazel\\src\\crypto\\dsa"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl-with-bazel\\src\\crypto\\ec_extra"); FSO.CreateFolder(base_dir+"\\ext\\grpc\\third_party\\boringssl-with-bazel\\src\\crypto\\ecdh_extra"); diff --git a/doc/grpc_xds_features.md b/doc/grpc_xds_features.md index ab5f6235bdc..bc33b1cf8f2 100644 --- a/doc/grpc_xds_features.md +++ b/doc/grpc_xds_features.md @@ -78,5 +78,5 @@ Ignore Resource Deletion | [A53](https://github.com/grpc/proposal/blob/master/A5 Pick First | [A62](https://github.com/grpc/proposal/blob/master/A62-pick-first.md) | v1.58.0 | v1.58.1 | v1.56.0 | | [StringMatcher for Header Matching](https://github.com/envoyproxy/envoy/blob/3fe4b8d335fa339ef6f17325c8d31f87ade7bb1a/api/envoy/config/route/v3/route_components.proto#L2280) | [A63](https://github.com/grpc/proposal/blob/master/A63-xds-string-matcher-in-header-matching.md) | v1.56.0 | v1.53.0 | v1.56.0 | v1.9.0 | LRS Custom Metrics Support | [A64](https://github.com/grpc/proposal/blob/master/A64-lrs-custom-metrics.md) | v1.54.0 | | | | -mTLS Credentials in xDS Bootstrap File | [A65](https://github.com/grpc/proposal/blob/master/A65-xds-mtls-creds-in-bootstrap.md) | v1.57.0 | | v1.61.0 | | +mTLS Credentials in xDS Bootstrap File | [A65](https://github.com/grpc/proposal/blob/master/A65-xds-mtls-creds-in-bootstrap.md) | v1.65.0 | | v1.61.0 | | Stateful Session Affinity | [A55](https://github.com/grpc/proposal/blob/master/A55-xds-stateful-session-affinity.md), [A60](https://github.com/grpc/proposal/blob/master/A60-xds-stateful-session-affinity-weighted-clusters.md), [A75](https://github.com/grpc/proposal/blob/master/A75-xds-aggregate-cluster-behavior-fixes.md) | v1.61.0 | | | | diff --git a/examples/cpp/otel/BUILD b/examples/cpp/otel/BUILD index 561ce270df2..ff1ec187a19 100644 --- a/examples/cpp/otel/BUILD +++ b/examples/cpp/otel/BUILD @@ -14,12 +14,19 @@ licenses(["notice"]) +package( + default_visibility = ["//examples/cpp/otel:__subpackages__"], +) + cc_library( name = "util", srcs = ["util.cc"], hdrs = ["util.h"], + defines = ["BAZEL_BUILD"], deps = [ "//:grpc++", + "//:grpc++_reflection", + "//examples/protos:helloworld_cc_grpc", "@io_opentelemetry_cpp//sdk/src/metrics", ], ) @@ -32,7 +39,6 @@ cc_binary( "util", "//:grpc++", "//:grpcpp_otel_plugin", - "//examples/protos:helloworld_cc_grpc", "@com_google_absl//absl/flags:flag", "@com_google_absl//absl/flags:parse", "@io_opentelemetry_cpp//exporters/prometheus:prometheus_exporter", @@ -47,9 +53,7 @@ cc_binary( deps = [ "util", "//:grpc++", - "//:grpc++_reflection", "//:grpcpp_otel_plugin", - "//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/otel/CMakeLists.txt b/examples/cpp/otel/CMakeLists.txt index e4028a214f9..b81a2538a89 100644 --- a/examples/cpp/otel/CMakeLists.txt +++ b/examples/cpp/otel/CMakeLists.txt @@ -67,22 +67,21 @@ target_link_libraries(hw_grpc_proto add_library(util "util.cc") target_link_libraries(util + hw_grpc_proto opentelemetry-cpp::metrics - ${_GRPC_GRPCPP}) + ${_GRPC_GRPCPP} + ${_REFLECTION} + ${_PROTOBUF_LIBPROTOBUF}) # Targets greeter_callback_(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 opentelemetry-cpp::metrics opentelemetry-cpp::prometheus_exporter - ${_REFLECTION} - ${_GRPC_GRPCPP} gRPC::grpcpp_otel_plugin - util - ${_PROTOBUF_LIBPROTOBUF}) + util) endforeach() diff --git a/examples/cpp/otel/Makefile b/examples/cpp/otel/Makefile new file mode 100644 index 00000000000..0286a777a6a --- /dev/null +++ b/examples/cpp/otel/Makefile @@ -0,0 +1,124 @@ +# +# 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. +# + +# TODO(jtattermusch): Remove the hack to workaround protobuf bug. See https://github.com/protocolbuffers/protobuf/issues/12439 +# Hack: protobuf currently doesn't declare it's absl dependencies when protobuf.pc pkgconfig file is used. +PROTOBUF_ABSL_DEPS = absl_absl_check absl_absl_log absl_algorithm absl_base absl_bind_front absl_bits absl_btree absl_cleanup absl_cord absl_core_headers absl_debugging absl_die_if_null absl_dynamic_annotations absl_flags absl_flat_hash_map absl_flat_hash_set absl_function_ref absl_hash absl_layout absl_log_initialize absl_log_severity absl_memory absl_node_hash_map absl_node_hash_set absl_optional absl_span absl_status absl_statusor absl_strings absl_synchronization absl_time absl_type_traits absl_utility absl_variant +# TODO(jtattermusch): Remove the hack to workaround protobuf/utf8_range bug. See https://github.com/protocolbuffers/utf8_range/issues/20 +# Hack: utf8_range (which is protobuf's dependency) currently doesn't have a pkgconfig file, so we need to explicitly +# tweak the list of libraries to link against to fix the build. +PROTOBUF_UTF8_RANGE_LINK_LIBS = -lutf8_validity +OPENTELEMETRY_LINK_LIBS = -lopentelemetry_metrics -lopentelemetry_exporter_prometheus -lopentelemetry_common -lopentelemetry_resources -lprometheus-cpp-pull -lprometheus-cpp-core + +HOST_SYSTEM = $(shell uname | cut -f 1 -d_) +SYSTEM ?= $(HOST_SYSTEM) +CXX = g++ +CPPFLAGS += `pkg-config --cflags protobuf grpc absl_flags absl_flags_parse` +ifeq ($(SYSTEM),Darwin) +LDFLAGS += -L/usr/local/lib `pkg-config --libs --static protobuf grpc++ grpcpp_otel_plugin absl_flags absl_flags_parse $(PROTOBUF_ABSL_DEPS)` \ + $(PROTOBUF_UTF8_RANGE_LINK_LIBS) \ + $(OPENTELEMETRY_LINK_LIBS) \ + -pthread \ + -lgrpc++_reflection \ + -ldl +else +LDFLAGS += -L/usr/local/lib `pkg-config --libs --static protobuf grpc++ grpcpp_otel_plugin absl_flags absl_flags_parse $(PROTOBUF_ABSL_DEPS)` \ + $(PROTOBUF_UTF8_RANGE_LINK_LIBS) \ + $(OPENTELEMETRY_LINK_LIBS) \ + -pthread \ + -Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed \ + -ldl +endif +PROTOC = protoc +GRPC_CPP_PLUGIN = grpc_cpp_plugin +GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)` + +PROTOS_PATH = ../../protos + +vpath %.proto $(PROTOS_PATH) + +all: system-check greeter_callback_client greeter_callback_server + +greeter_callback_client: util.o helloworld.pb.o helloworld.grpc.pb.o greeter_callback_client.o + $(CXX) $^ $(LDFLAGS) -o $@ + +greeter_callback_server: util.o helloworld.pb.o helloworld.grpc.pb.o greeter_callback_server.o + $(CXX) $^ $(LDFLAGS) -o $@ + +.PRECIOUS: %.grpc.pb.cc +%.grpc.pb.cc: %.proto + $(PROTOC) -I $(PROTOS_PATH) --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN_PATH) $< + +.PRECIOUS: %.pb.cc +%.pb.cc: %.proto + $(PROTOC) -I $(PROTOS_PATH) --cpp_out=. $< + +clean: + rm -f *.o *.pb.cc *.pb.h greeter_callback_client greeter_callback_server + + +# The following is to test your system and ensure a smoother experience. +# They are by no means necessary to actually compile a grpc-enabled software. + +PROTOC_CMD = which $(PROTOC) +PROTOC_CHECK_CMD = $(PROTOC) --version | grep -q 'libprotoc.3\|libprotoc [0-9][0-9]\.' +PLUGIN_CHECK_CMD = which $(GRPC_CPP_PLUGIN) +HAS_PROTOC = $(shell $(PROTOC_CMD) > /dev/null && echo true || echo false) +ifeq ($(HAS_PROTOC),true) +HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false) +endif +HAS_PLUGIN = $(shell $(PLUGIN_CHECK_CMD) > /dev/null && echo true || echo false) + +SYSTEM_OK = false +ifeq ($(HAS_VALID_PROTOC),true) +ifeq ($(HAS_PLUGIN),true) +SYSTEM_OK = true +endif +endif + +system-check: +ifneq ($(HAS_VALID_PROTOC),true) + @echo " DEPENDENCY ERROR" + @echo + @echo "You don't have protoc 3.0.0 or newer installed in your path." + @echo "Please install an up-to-date version of Google protocol buffers." + @echo "You can find it here:" + @echo + @echo " https://github.com/protocolbuffers/protobuf/releases" + @echo + @echo "Here is what I get when trying to evaluate your version of protoc:" + @echo + -$(PROTOC) --version + @echo + @echo +endif +ifneq ($(HAS_PLUGIN),true) + @echo " DEPENDENCY ERROR" + @echo + @echo "You don't have the grpc c++ protobuf plugin installed in your path." + @echo "Please install grpc. You can find it here:" + @echo + @echo " https://github.com/grpc/grpc" + @echo + @echo "Here is what I get when trying to detect if you have the plugin:" + @echo + -which $(GRPC_CPP_PLUGIN) + @echo + @echo +endif +ifneq ($(SYSTEM_OK),true) + @false +endif diff --git a/examples/cpp/otel/greeter_callback_client.cc b/examples/cpp/otel/greeter_callback_client.cc index 32a2049b4cf..f166bd9f5e6 100644 --- a/examples/cpp/otel/greeter_callback_client.cc +++ b/examples/cpp/otel/greeter_callback_client.cc @@ -16,12 +16,14 @@ * */ -#include -#include -#include -#include +// Explicitly define HAVE_ABSEIL to avoid conflict with OTel's Abseil +// version. Refer +// https://github.com/open-telemetry/opentelemetry-cpp/issues/1042. +#ifndef HAVE_ABSEIL +#define HAVE_ABSEIL +#endif + #include -#include #include "absl/flags/flag.h" #include "absl/flags/parse.h" @@ -30,13 +32,10 @@ #include "opentelemetry/sdk/metrics/meter_provider.h" #include -#include #ifdef BAZEL_BUILD #include "examples/cpp/otel/util.h" -#include "examples/protos/helloworld.grpc.pb.h" #else -#include "helloworld.grpc.pb.h" #include "util.h" #endif @@ -44,64 +43,6 @@ ABSL_FLAG(std::string, target, "localhost:50051", "Server address"); ABSL_FLAG(std::string, prometheus_endpoint, "localhost:9465", "Prometheus exporter endpoint"); -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. - 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. - if (status.ok()) { - return reply.message(); - } else { - std::cout << status.error_code() << ": " << status.error_message() - << std::endl; - return "RPC failed"; - } - } - - private: - std::unique_ptr stub_; -}; - int main(int argc, char** argv) { absl::ParseCommandLine(argc, argv); // Register a global gRPC OpenTelemetry plugin configured with a prometheus @@ -125,20 +66,9 @@ int main(int argc, char** argv) { << status.ToString() << std::endl; return static_cast(status.code()); } - // 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); - grpc::ChannelArguments args; + // Continuously send RPCs every second. - while (true) { - GreeterClient greeter(grpc::CreateCustomChannel( - target_str, grpc::InsecureChannelCredentials(), args)); - std::string user("world"); - std::string reply = greeter.SayHello(user); - std::cout << "Greeter received: " << reply << std::endl; - std::this_thread::sleep_for(std::chrono::seconds(1)); - } + RunClient(absl::GetFlag(FLAGS_target)); return 0; } diff --git a/examples/cpp/otel/greeter_callback_server.cc b/examples/cpp/otel/greeter_callback_server.cc index 8e7e7cda052..408b52d685d 100644 --- a/examples/cpp/otel/greeter_callback_server.cc +++ b/examples/cpp/otel/greeter_callback_server.cc @@ -16,6 +16,13 @@ * */ +// Explicitly define HAVE_ABSEIL to avoid conflict with OTel's Abseil +// version. Refer +// https://github.com/open-telemetry/opentelemetry-cpp/issues/1042. +#ifndef HAVE_ABSEIL +#define HAVE_ABSEIL +#endif + #include #include #include @@ -28,15 +35,10 @@ #include "opentelemetry/sdk/metrics/meter_provider.h" #include -#include -#include -#include #ifdef BAZEL_BUILD #include "examples/cpp/otel/util.h" -#include "examples/protos/helloworld.grpc.pb.h" #else -#include "helloworld.grpc.pb.h" #include "util.h" #endif @@ -44,50 +46,6 @@ ABSL_FLAG(uint16_t, port, 50051, "Server port for the service"); ABSL_FLAG(std::string, prometheus_endpoint, "localhost:9464", "Prometheus exporter endpoint"); -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; - // 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); // Register a global gRPC OpenTelemetry plugin configured with a prometheus diff --git a/examples/cpp/otel/ostream/BUILD b/examples/cpp/otel/ostream/BUILD new file mode 100644 index 00000000000..3195902160e --- /dev/null +++ b/examples/cpp/otel/ostream/BUILD @@ -0,0 +1,44 @@ +# Copyright 2023 the gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +licenses(["notice"]) + +cc_binary( + name = "greeter_callback_client", + srcs = ["greeter_callback_client.cc"], + defines = ["BAZEL_BUILD"], + deps = [ + "//:grpcpp_otel_plugin", + "//examples/cpp/otel:util", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/flags:parse", + "@io_opentelemetry_cpp//exporters/ostream:ostream_metric_exporter", + "@io_opentelemetry_cpp//sdk/src/metrics", + ], +) + +cc_binary( + name = "greeter_callback_server", + srcs = ["greeter_callback_server.cc"], + defines = ["BAZEL_BUILD"], + deps = [ + "//:grpcpp_otel_plugin", + "//examples/cpp/otel:util", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/flags:parse", + "@com_google_absl//absl/strings:str_format", + "@io_opentelemetry_cpp//exporters/ostream:ostream_metric_exporter", + "@io_opentelemetry_cpp//sdk/src/metrics", + ], +) diff --git a/examples/cpp/otel/ostream/CMakeLists.txt b/examples/cpp/otel/ostream/CMakeLists.txt new file mode 100644 index 00000000000..c0d9a58a988 --- /dev/null +++ b/examples/cpp/otel/ostream/CMakeLists.txt @@ -0,0 +1,85 @@ +# 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++ gRPC OpenTelemetry example. +# Assumes absl, protobuf, prometheus-cpp, opentelemetry-cpp and gRPC (with -DgRPC_BUILD_OPENTELEMETRY_PLUGIN=ON) 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.13) + +project(grpc_opentelemetry_example C CXX) + +include(../../cmake/common.cmake) + +# Find opentelemetry-cpp package +find_package(opentelemetry-cpp CONFIG REQUIRED) + +# 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}") +include_directories("${CMAKE_SOURCE_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}) + +# util +add_library(util + "../util.cc") +target_link_libraries(util + hw_grpc_proto + opentelemetry-cpp::metrics + ${_GRPC_GRPCPP} + ${_REFLECTION} + ${_PROTOBUF_LIBPROTOBUF}) + +# Targets greeter_callback_(client|server) +foreach(_target + greeter_callback_client greeter_callback_server) + add_executable(${_target} "${_target}.cc") + target_link_libraries(${_target} + absl::flags + absl::flags_parse + opentelemetry-cpp::metrics + opentelemetry-cpp::ostream_metrics_exporter + gRPC::grpcpp_otel_plugin + util + ${_PROTOBUF_LIBPROTOBUF}) +endforeach() diff --git a/examples/cpp/otel/ostream/Makefile b/examples/cpp/otel/ostream/Makefile new file mode 100644 index 00000000000..9adf470da10 --- /dev/null +++ b/examples/cpp/otel/ostream/Makefile @@ -0,0 +1,127 @@ +# +# 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. +# + +# TODO(jtattermusch): Remove the hack to workaround protobuf bug. See https://github.com/protocolbuffers/protobuf/issues/12439 +# Hack: protobuf currently doesn't declare it's absl dependencies when protobuf.pc pkgconfig file is used. +PROTOBUF_ABSL_DEPS = absl_absl_check absl_absl_log absl_algorithm absl_base absl_bind_front absl_bits absl_btree absl_cleanup absl_cord absl_core_headers absl_debugging absl_die_if_null absl_dynamic_annotations absl_flags absl_flat_hash_map absl_flat_hash_set absl_function_ref absl_hash absl_layout absl_log_initialize absl_log_severity absl_memory absl_node_hash_map absl_node_hash_set absl_optional absl_span absl_status absl_statusor absl_strings absl_synchronization absl_time absl_type_traits absl_utility absl_variant +# TODO(jtattermusch): Remove the hack to workaround protobuf/utf8_range bug. See https://github.com/protocolbuffers/utf8_range/issues/20 +# Hack: utf8_range (which is protobuf's dependency) currently doesn't have a pkgconfig file, so we need to explicitly +# tweak the list of libraries to link against to fix the build. +PROTOBUF_UTF8_RANGE_LINK_LIBS = -lutf8_validity +OPENTELEMETRY_LINK_LIBS = -lopentelemetry_metrics -lopentelemetry_exporter_ostream_metrics -lopentelemetry_resources -lopentelemetry_common + +HOST_SYSTEM = $(shell uname | cut -f 1 -d_) +SYSTEM ?= $(HOST_SYSTEM) +CXX = g++ +CPPFLAGS += `pkg-config --cflags protobuf grpc absl_flags absl_flags_parse` +ifeq ($(SYSTEM),Darwin) +LDFLAGS += -L/usr/local/lib `pkg-config --libs --static protobuf grpc++ grpcpp_otel_plugin absl_flags absl_flags_parse $(PROTOBUF_ABSL_DEPS)` \ + $(PROTOBUF_UTF8_RANGE_LINK_LIBS) \ + $(OPENTELEMETRY_LINK_LIBS) \ + -pthread \ + -lgrpc++_reflection \ + -ldl +else +LDFLAGS += -L/usr/local/lib `pkg-config --libs --static protobuf grpc++ grpcpp_otel_plugin absl_flags absl_flags_parse $(PROTOBUF_ABSL_DEPS)` \ + $(PROTOBUF_UTF8_RANGE_LINK_LIBS) \ + $(OPENTELEMETRY_LINK_LIBS) \ + -pthread \ + -Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed \ + -ldl +endif +PROTOC = protoc +GRPC_CPP_PLUGIN = grpc_cpp_plugin +GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)` + +PROTOS_PATH = ../../../protos + +vpath %.proto $(PROTOS_PATH) + +all: system-check greeter_callback_client greeter_callback_server + +greeter_callback_client: util.o helloworld.pb.o helloworld.grpc.pb.o greeter_callback_client.o + $(CXX) $^ $(LDFLAGS) -o $@ + +greeter_callback_server: util.o helloworld.pb.o helloworld.grpc.pb.o greeter_callback_server.o + $(CXX) $^ $(LDFLAGS) -o $@ + +.PRECIOUS: %.grpc.pb.cc +%.grpc.pb.cc: %.proto + $(PROTOC) -I $(PROTOS_PATH) --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN_PATH) $< + +.PRECIOUS: %.pb.cc +%.pb.cc: %.proto + $(PROTOC) -I $(PROTOS_PATH) --cpp_out=. $< + +util.o: ../util.cc + $(CXX) $^ -I . -I $(CPPFLAGS) -c -o $@ + +clean: + rm -f *.o *.pb.cc *.pb.h greeter_callback_client greeter_callback_server + + +# The following is to test your system and ensure a smoother experience. +# They are by no means necessary to actually compile a grpc-enabled software. + +PROTOC_CMD = which $(PROTOC) +PROTOC_CHECK_CMD = $(PROTOC) --version | grep -q 'libprotoc.3\|libprotoc [0-9][0-9]\.' +PLUGIN_CHECK_CMD = which $(GRPC_CPP_PLUGIN) +HAS_PROTOC = $(shell $(PROTOC_CMD) > /dev/null && echo true || echo false) +ifeq ($(HAS_PROTOC),true) +HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false) +endif +HAS_PLUGIN = $(shell $(PLUGIN_CHECK_CMD) > /dev/null && echo true || echo false) + +SYSTEM_OK = false +ifeq ($(HAS_VALID_PROTOC),true) +ifeq ($(HAS_PLUGIN),true) +SYSTEM_OK = true +endif +endif + +system-check: +ifneq ($(HAS_VALID_PROTOC),true) + @echo " DEPENDENCY ERROR" + @echo + @echo "You don't have protoc 3.0.0 or newer installed in your path." + @echo "Please install an up-to-date version of Google protocol buffers." + @echo "You can find it here:" + @echo + @echo " https://github.com/protocolbuffers/protobuf/releases" + @echo + @echo "Here is what I get when trying to evaluate your version of protoc:" + @echo + -$(PROTOC) --version + @echo + @echo +endif +ifneq ($(HAS_PLUGIN),true) + @echo " DEPENDENCY ERROR" + @echo + @echo "You don't have the grpc c++ protobuf plugin installed in your path." + @echo "Please install grpc. You can find it here:" + @echo + @echo " https://github.com/grpc/grpc" + @echo + @echo "Here is what I get when trying to detect if you have the plugin:" + @echo + -which $(GRPC_CPP_PLUGIN) + @echo + @echo +endif +ifneq ($(SYSTEM_OK),true) + @false +endif diff --git a/examples/cpp/otel/ostream/greeter_callback_client.cc b/examples/cpp/otel/ostream/greeter_callback_client.cc new file mode 100644 index 00000000000..24e141fd7b5 --- /dev/null +++ b/examples/cpp/otel/ostream/greeter_callback_client.cc @@ -0,0 +1,79 @@ +/* + * + * 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. + * + */ + +// Explicitly define HAVE_ABSEIL to avoid conflict with OTel's Abseil +// version. Refer +// https://github.com/open-telemetry/opentelemetry-cpp/issues/1042. +#ifndef HAVE_ABSEIL +#define HAVE_ABSEIL +#endif + +#include + +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "opentelemetry/exporters/ostream/metric_exporter.h" +#include "opentelemetry/exporters/ostream/metric_exporter_factory.h" +#include "opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader.h" +#include "opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader_factory.h" +#include "opentelemetry/sdk/metrics/meter_provider.h" + +#include + +#ifdef BAZEL_BUILD +#include "examples/cpp/otel/util.h" +#else +#include "../util.h" +#endif + +ABSL_FLAG(std::string, target, "localhost:50051", "Server address"); + +int main(int argc, char** argv) { + absl::ParseCommandLine(argc, argv); + // Register a global gRPC OpenTelemetry plugin configured with an ostream + // exporter. + auto ostream_exporter = + opentelemetry::exporter::metrics::OStreamMetricExporterFactory::Create(); + opentelemetry::sdk::metrics::PeriodicExportingMetricReaderOptions + reader_options; + reader_options.export_interval_millis = std::chrono::milliseconds(1000); + reader_options.export_timeout_millis = std::chrono::milliseconds(500); + auto reader = + opentelemetry::sdk::metrics::PeriodicExportingMetricReaderFactory::Create( + std::move(ostream_exporter), reader_options); + auto meter_provider = + std::make_shared(); + // The default histogram boundaries are not granular enough for RPCs. Override + // the "grpc.client.attempt.duration" view as recommended by + // https://github.com/grpc/proposal/blob/master/A66-otel-stats.md. + AddLatencyView(meter_provider.get(), "grpc.client.attempt.duration", "s"); + meter_provider->AddMetricReader(std::move(reader)); + auto status = grpc::OpenTelemetryPluginBuilder() + .SetMeterProvider(std::move(meter_provider)) + .BuildAndRegisterGlobal(); + if (!status.ok()) { + std::cerr << "Failed to register gRPC OpenTelemetry Plugin: " + << status.ToString() << std::endl; + return static_cast(status.code()); + } + + // Continuously send RPCs every second. + RunClient(absl::GetFlag(FLAGS_target)); + + return 0; +} diff --git a/examples/cpp/otel/ostream/greeter_callback_server.cc b/examples/cpp/otel/ostream/greeter_callback_server.cc new file mode 100644 index 00000000000..ab539efd305 --- /dev/null +++ b/examples/cpp/otel/ostream/greeter_callback_server.cc @@ -0,0 +1,78 @@ +/* + * + * 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. + * + */ + +// Explicitly define HAVE_ABSEIL to avoid conflict with OTel's Abseil +// version. Refer +// https://github.com/open-telemetry/opentelemetry-cpp/issues/1042. +#ifndef HAVE_ABSEIL +#define HAVE_ABSEIL +#endif + +#include +#include +#include + +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "opentelemetry/exporters/ostream/metric_exporter.h" +#include "opentelemetry/exporters/ostream/metric_exporter_factory.h" +#include "opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader.h" +#include "opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader_factory.h" +#include "opentelemetry/sdk/metrics/meter_provider.h" + +#include + +#ifdef BAZEL_BUILD +#include "examples/cpp/otel/util.h" +#else +#include "../util.h" +#endif + +ABSL_FLAG(uint16_t, port, 50051, "Server port for the service"); + +int main(int argc, char** argv) { + absl::ParseCommandLine(argc, argv); + // Register a global gRPC OpenTelemetry plugin configured with an ostream + // exporter. + auto ostream_exporter = + opentelemetry::exporter::metrics::OStreamMetricExporterFactory::Create(); + opentelemetry::sdk::metrics::PeriodicExportingMetricReaderOptions + reader_options; + reader_options.export_interval_millis = std::chrono::milliseconds(1000); + reader_options.export_timeout_millis = std::chrono::milliseconds(500); + auto reader = + opentelemetry::sdk::metrics::PeriodicExportingMetricReaderFactory::Create( + std::move(ostream_exporter), reader_options); + auto meter_provider = + std::make_shared(); + // The default histogram boundaries are not granular enough for RPCs. Override + // the "grpc.server.call.duration" view as recommended by + // https://github.com/grpc/proposal/blob/master/A66-otel-stats.md. + AddLatencyView(meter_provider.get(), "grpc.server.call.duration", "s"); + meter_provider->AddMetricReader(std::move(reader)); + auto status = grpc::OpenTelemetryPluginBuilder() + .SetMeterProvider(std::move(meter_provider)) + .BuildAndRegisterGlobal(); + if (!status.ok()) { + std::cerr << "Failed to register gRPC OpenTelemetry Plugin: " + << status.ToString() << std::endl; + return static_cast(status.code()); + } + RunServer(absl::GetFlag(FLAGS_port)); + return 0; +} diff --git a/examples/cpp/otel/util.cc b/examples/cpp/otel/util.cc index 8777481ea00..cba83f736ad 100644 --- a/examples/cpp/otel/util.cc +++ b/examples/cpp/otel/util.cc @@ -16,17 +16,42 @@ // // -#ifdef BAZEL_BUILD -#include "examples/cpp/otel/util.h" -#else -#include "util.h" +// Explicitly define HAVE_ABSEIL to avoid conflict with OTel's Abseil +// version. Refer +// https://github.com/open-telemetry/opentelemetry-cpp/issues/1042. +#ifndef HAVE_ABSEIL +#define HAVE_ABSEIL #endif +#include +#include + #include "opentelemetry/sdk/metrics/view/instrument_selector_factory.h" #include "opentelemetry/sdk/metrics/view/meter_selector_factory.h" #include "opentelemetry/sdk/metrics/view/view_factory.h" +#include #include +#include + +#ifdef BAZEL_BUILD +#include "examples/cpp/otel/util.h" +#include "examples/protos/helloworld.grpc.pb.h" +#else +#include "helloworld.grpc.pb.h" +#include "util.h" +#endif + +using grpc::CallbackServerContext; +using grpc::Channel; +using grpc::ClientContext; +using grpc::Server; +using grpc::ServerBuilder; +using grpc::ServerUnaryReactor; +using grpc::Status; +using helloworld::Greeter; +using helloworld::HelloReply; +using helloworld::HelloRequest; void AddLatencyView(opentelemetry::sdk::metrics::MeterProvider* provider, const std::string& name, const std::string& unit) { @@ -48,3 +73,109 @@ void AddLatencyView(opentelemetry::sdk::metrics::MeterProvider* provider, opentelemetry::sdk::metrics::AggregationType::kHistogram, std::move(histogram_config))); } + +namespace { + +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. + 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. + if (status.ok()) { + return reply.message(); + } else { + std::cout << status.error_code() << ": " << status.error_message() + << std::endl; + return "RPC failed"; + } + } + + private: + std::unique_ptr stub_; +}; + +// 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; + } +}; + +} // namespace + +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; + // 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(); +} + +void RunClient(const std::string& target_str) { + // 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. + grpc::ChannelArguments args; + // Continuously send RPCs every second. + while (true) { + GreeterClient greeter(grpc::CreateCustomChannel( + target_str, grpc::InsecureChannelCredentials(), args)); + std::string user("world"); + std::string reply = greeter.SayHello(user); + std::cout << "Greeter received: " << reply << std::endl; + std::this_thread::sleep_for(std::chrono::seconds(1)); + } +} diff --git a/examples/cpp/otel/util.h b/examples/cpp/otel/util.h index 4fe1681b4fa..4c062a39bc1 100644 --- a/examples/cpp/otel/util.h +++ b/examples/cpp/otel/util.h @@ -28,4 +28,6 @@ void AddLatencyView(opentelemetry::sdk::metrics::MeterProvider* provider, const std::string& name, const std::string& unit); +void RunServer(uint16_t port); +void RunClient(const std::string& target_str); #endif // GRPCPP_EXAMPLES_CPP_OTEL_UTIL_H diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index 6b74801bc8c..90a2f3849fc 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -268,6 +268,7 @@ Pod::Spec.new do |s| 'src/core/channelz/channelz.h', 'src/core/channelz/channelz_registry.h', 'src/core/client_channel/backup_poller.h', + 'src/core/client_channel/client_channel.h', 'src/core/client_channel/client_channel_factory.h', 'src/core/client_channel/client_channel_filter.h', 'src/core/client_channel/client_channel_internal.h', @@ -276,6 +277,7 @@ Pod::Spec.new do |s| 'src/core/client_channel/connector.h', 'src/core/client_channel/dynamic_filters.h', 'src/core/client_channel/global_subchannel_pool.h', + 'src/core/client_channel/load_balanced_call_destination.h', 'src/core/client_channel/local_subchannel_pool.h', 'src/core/client_channel/retry_filter.h', 'src/core/client_channel/retry_filter_legacy_call_data.h', @@ -968,6 +970,7 @@ Pod::Spec.new do |s| 'src/core/lib/gprpp/directory_reader.h', 'src/core/lib/gprpp/down_cast.h', 'src/core/lib/gprpp/dual_ref_counted.h', + 'src/core/lib/gprpp/dump_args.h', 'src/core/lib/gprpp/env.h', 'src/core/lib/gprpp/examine_stack.h', 'src/core/lib/gprpp/fork.h', @@ -1005,10 +1008,6 @@ Pod::Spec.new do |s| 'src/core/lib/gprpp/validation_errors.h', 'src/core/lib/gprpp/work_serializer.h', 'src/core/lib/gprpp/xxhash_inline.h', - 'src/core/lib/http/format_request.h', - 'src/core/lib/http/httpcli.h', - 'src/core/lib/http/httpcli_ssl_credentials.h', - 'src/core/lib/http/parser.h', 'src/core/lib/iomgr/block_annotate.h', 'src/core/lib/iomgr/buffer_list.h', 'src/core/lib/iomgr/call_combiner.h', @@ -1093,6 +1092,7 @@ Pod::Spec.new do |s| 'src/core/lib/promise/latch.h', 'src/core/lib/promise/loop.h', 'src/core/lib/promise/map.h', + 'src/core/lib/promise/observable.h', 'src/core/lib/promise/party.h', 'src/core/lib/promise/pipe.h', 'src/core/lib/promise/poll.h', @@ -1305,6 +1305,10 @@ Pod::Spec.new do |s| 'src/core/tsi/transport_security_grpc.h', 'src/core/tsi/transport_security_interface.h', 'src/core/util/alloc.h', + 'src/core/util/http_client/format_request.h', + 'src/core/util/http_client/httpcli.h', + 'src/core/util/http_client/httpcli_ssl_credentials.h', + 'src/core/util/http_client/parser.h', 'src/core/util/json/json.h', 'src/core/util/json/json_args.h', 'src/core/util/json/json_channel_args.h', @@ -1557,6 +1561,7 @@ Pod::Spec.new do |s| 'src/core/channelz/channelz.h', 'src/core/channelz/channelz_registry.h', 'src/core/client_channel/backup_poller.h', + 'src/core/client_channel/client_channel.h', 'src/core/client_channel/client_channel_factory.h', 'src/core/client_channel/client_channel_filter.h', 'src/core/client_channel/client_channel_internal.h', @@ -1565,6 +1570,7 @@ Pod::Spec.new do |s| 'src/core/client_channel/connector.h', 'src/core/client_channel/dynamic_filters.h', 'src/core/client_channel/global_subchannel_pool.h', + 'src/core/client_channel/load_balanced_call_destination.h', 'src/core/client_channel/local_subchannel_pool.h', 'src/core/client_channel/retry_filter.h', 'src/core/client_channel/retry_filter_legacy_call_data.h', @@ -2239,6 +2245,7 @@ Pod::Spec.new do |s| 'src/core/lib/gprpp/directory_reader.h', 'src/core/lib/gprpp/down_cast.h', 'src/core/lib/gprpp/dual_ref_counted.h', + 'src/core/lib/gprpp/dump_args.h', 'src/core/lib/gprpp/env.h', 'src/core/lib/gprpp/examine_stack.h', 'src/core/lib/gprpp/fork.h', @@ -2276,10 +2283,6 @@ Pod::Spec.new do |s| 'src/core/lib/gprpp/validation_errors.h', 'src/core/lib/gprpp/work_serializer.h', 'src/core/lib/gprpp/xxhash_inline.h', - 'src/core/lib/http/format_request.h', - 'src/core/lib/http/httpcli.h', - 'src/core/lib/http/httpcli_ssl_credentials.h', - 'src/core/lib/http/parser.h', 'src/core/lib/iomgr/block_annotate.h', 'src/core/lib/iomgr/buffer_list.h', 'src/core/lib/iomgr/call_combiner.h', @@ -2364,6 +2367,7 @@ Pod::Spec.new do |s| 'src/core/lib/promise/latch.h', 'src/core/lib/promise/loop.h', 'src/core/lib/promise/map.h', + 'src/core/lib/promise/observable.h', 'src/core/lib/promise/party.h', 'src/core/lib/promise/pipe.h', 'src/core/lib/promise/poll.h', @@ -2576,6 +2580,10 @@ Pod::Spec.new do |s| 'src/core/tsi/transport_security_grpc.h', 'src/core/tsi/transport_security_interface.h', 'src/core/util/alloc.h', + 'src/core/util/http_client/format_request.h', + 'src/core/util/http_client/httpcli.h', + 'src/core/util/http_client/httpcli_ssl_credentials.h', + 'src/core/util/http_client/parser.h', 'src/core/util/json/json.h', 'src/core/util/json/json_args.h', 'src/core/util/json/json_channel_args.h', diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 410e0f9095a..a8cc8fdda1f 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -199,7 +199,7 @@ Pod::Spec.new do |s| ss.libraries = 'z' ss.dependency "#{s.name}/Interface", version ss.dependency "#{s.name}/Privacy", version - ss.dependency 'BoringSSL-GRPC', '0.0.34' + ss.dependency 'BoringSSL-GRPC', '0.0.35' ss.dependency 'abseil/algorithm/container', abseil_version ss.dependency 'abseil/base/base', abseil_version ss.dependency 'abseil/base/config', abseil_version @@ -245,6 +245,8 @@ Pod::Spec.new do |s| 'src/core/channelz/channelz_registry.h', 'src/core/client_channel/backup_poller.cc', 'src/core/client_channel/backup_poller.h', + 'src/core/client_channel/client_channel.cc', + 'src/core/client_channel/client_channel.h', 'src/core/client_channel/client_channel_factory.cc', 'src/core/client_channel/client_channel_factory.h', 'src/core/client_channel/client_channel_filter.cc', @@ -260,6 +262,8 @@ Pod::Spec.new do |s| 'src/core/client_channel/dynamic_filters.h', 'src/core/client_channel/global_subchannel_pool.cc', 'src/core/client_channel/global_subchannel_pool.h', + 'src/core/client_channel/load_balanced_call_destination.cc', + 'src/core/client_channel/load_balanced_call_destination.h', 'src/core/client_channel/local_subchannel_pool.cc', 'src/core/client_channel/local_subchannel_pool.h', 'src/core/client_channel/retry_filter.cc', @@ -1374,6 +1378,8 @@ Pod::Spec.new do |s| 'src/core/lib/gprpp/directory_reader.h', 'src/core/lib/gprpp/down_cast.h', 'src/core/lib/gprpp/dual_ref_counted.h', + 'src/core/lib/gprpp/dump_args.cc', + 'src/core/lib/gprpp/dump_args.h', 'src/core/lib/gprpp/env.h', 'src/core/lib/gprpp/examine_stack.cc', 'src/core/lib/gprpp/examine_stack.h', @@ -1436,14 +1442,6 @@ Pod::Spec.new do |s| 'src/core/lib/gprpp/work_serializer.cc', 'src/core/lib/gprpp/work_serializer.h', 'src/core/lib/gprpp/xxhash_inline.h', - 'src/core/lib/http/format_request.cc', - 'src/core/lib/http/format_request.h', - 'src/core/lib/http/httpcli.cc', - 'src/core/lib/http/httpcli.h', - 'src/core/lib/http/httpcli_security_connector.cc', - 'src/core/lib/http/httpcli_ssl_credentials.h', - 'src/core/lib/http/parser.cc', - 'src/core/lib/http/parser.h', 'src/core/lib/iomgr/block_annotate.h', 'src/core/lib/iomgr/buffer_list.cc', 'src/core/lib/iomgr/buffer_list.h', @@ -1607,6 +1605,7 @@ Pod::Spec.new do |s| 'src/core/lib/promise/latch.h', 'src/core/lib/promise/loop.h', 'src/core/lib/promise/map.h', + 'src/core/lib/promise/observable.h', 'src/core/lib/promise/party.cc', 'src/core/lib/promise/party.h', 'src/core/lib/promise/pipe.h', @@ -2032,6 +2031,14 @@ Pod::Spec.new do |s| 'src/core/util/alloc.h', 'src/core/util/android/log.cc', 'src/core/util/atm.cc', + 'src/core/util/http_client/format_request.cc', + 'src/core/util/http_client/format_request.h', + 'src/core/util/http_client/httpcli.cc', + 'src/core/util/http_client/httpcli.h', + 'src/core/util/http_client/httpcli_security_connector.cc', + 'src/core/util/http_client/httpcli_ssl_credentials.h', + 'src/core/util/http_client/parser.cc', + 'src/core/util/http_client/parser.h', 'src/core/util/iphone/cpu.cc', 'src/core/util/json/json.h', 'src/core/util/json/json_args.h', @@ -2357,6 +2364,7 @@ Pod::Spec.new do |s| 'src/core/channelz/channelz.h', 'src/core/channelz/channelz_registry.h', 'src/core/client_channel/backup_poller.h', + 'src/core/client_channel/client_channel.h', 'src/core/client_channel/client_channel_factory.h', 'src/core/client_channel/client_channel_filter.h', 'src/core/client_channel/client_channel_internal.h', @@ -2365,6 +2373,7 @@ Pod::Spec.new do |s| 'src/core/client_channel/connector.h', 'src/core/client_channel/dynamic_filters.h', 'src/core/client_channel/global_subchannel_pool.h', + 'src/core/client_channel/load_balanced_call_destination.h', 'src/core/client_channel/local_subchannel_pool.h', 'src/core/client_channel/retry_filter.h', 'src/core/client_channel/retry_filter_legacy_call_data.h', @@ -3019,6 +3028,7 @@ Pod::Spec.new do |s| 'src/core/lib/gprpp/directory_reader.h', 'src/core/lib/gprpp/down_cast.h', 'src/core/lib/gprpp/dual_ref_counted.h', + 'src/core/lib/gprpp/dump_args.h', 'src/core/lib/gprpp/env.h', 'src/core/lib/gprpp/examine_stack.h', 'src/core/lib/gprpp/fork.h', @@ -3056,10 +3066,6 @@ Pod::Spec.new do |s| 'src/core/lib/gprpp/validation_errors.h', 'src/core/lib/gprpp/work_serializer.h', 'src/core/lib/gprpp/xxhash_inline.h', - 'src/core/lib/http/format_request.h', - 'src/core/lib/http/httpcli.h', - 'src/core/lib/http/httpcli_ssl_credentials.h', - 'src/core/lib/http/parser.h', 'src/core/lib/iomgr/block_annotate.h', 'src/core/lib/iomgr/buffer_list.h', 'src/core/lib/iomgr/call_combiner.h', @@ -3144,6 +3150,7 @@ Pod::Spec.new do |s| 'src/core/lib/promise/latch.h', 'src/core/lib/promise/loop.h', 'src/core/lib/promise/map.h', + 'src/core/lib/promise/observable.h', 'src/core/lib/promise/party.h', 'src/core/lib/promise/pipe.h', 'src/core/lib/promise/poll.h', @@ -3356,6 +3363,10 @@ Pod::Spec.new do |s| 'src/core/tsi/transport_security_grpc.h', 'src/core/tsi/transport_security_interface.h', 'src/core/util/alloc.h', + 'src/core/util/http_client/format_request.h', + 'src/core/util/http_client/httpcli.h', + 'src/core/util/http_client/httpcli_ssl_credentials.h', + 'src/core/util/http_client/parser.h', 'src/core/util/json/json.h', 'src/core/util/json/json_args.h', 'src/core/util/json/json_channel_args.h', diff --git a/grpc.gemspec b/grpc.gemspec index 26c0f1f1f31..5b919662d11 100644 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -132,6 +132,8 @@ Gem::Specification.new do |s| s.files += %w( src/core/channelz/channelz_registry.h ) s.files += %w( src/core/client_channel/backup_poller.cc ) s.files += %w( src/core/client_channel/backup_poller.h ) + s.files += %w( src/core/client_channel/client_channel.cc ) + s.files += %w( src/core/client_channel/client_channel.h ) s.files += %w( src/core/client_channel/client_channel_factory.cc ) s.files += %w( src/core/client_channel/client_channel_factory.h ) s.files += %w( src/core/client_channel/client_channel_filter.cc ) @@ -147,6 +149,8 @@ Gem::Specification.new do |s| s.files += %w( src/core/client_channel/dynamic_filters.h ) s.files += %w( src/core/client_channel/global_subchannel_pool.cc ) s.files += %w( src/core/client_channel/global_subchannel_pool.h ) + s.files += %w( src/core/client_channel/load_balanced_call_destination.cc ) + s.files += %w( src/core/client_channel/load_balanced_call_destination.h ) s.files += %w( src/core/client_channel/local_subchannel_pool.cc ) s.files += %w( src/core/client_channel/local_subchannel_pool.h ) s.files += %w( src/core/client_channel/retry_filter.cc ) @@ -1261,6 +1265,8 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/gprpp/directory_reader.h ) s.files += %w( src/core/lib/gprpp/down_cast.h ) s.files += %w( src/core/lib/gprpp/dual_ref_counted.h ) + s.files += %w( src/core/lib/gprpp/dump_args.cc ) + s.files += %w( src/core/lib/gprpp/dump_args.h ) s.files += %w( src/core/lib/gprpp/env.h ) s.files += %w( src/core/lib/gprpp/examine_stack.cc ) s.files += %w( src/core/lib/gprpp/examine_stack.h ) @@ -1323,14 +1329,6 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/gprpp/work_serializer.cc ) s.files += %w( src/core/lib/gprpp/work_serializer.h ) s.files += %w( src/core/lib/gprpp/xxhash_inline.h ) - s.files += %w( src/core/lib/http/format_request.cc ) - s.files += %w( src/core/lib/http/format_request.h ) - s.files += %w( src/core/lib/http/httpcli.cc ) - s.files += %w( src/core/lib/http/httpcli.h ) - s.files += %w( src/core/lib/http/httpcli_security_connector.cc ) - s.files += %w( src/core/lib/http/httpcli_ssl_credentials.h ) - s.files += %w( src/core/lib/http/parser.cc ) - s.files += %w( src/core/lib/http/parser.h ) s.files += %w( src/core/lib/iomgr/block_annotate.h ) s.files += %w( src/core/lib/iomgr/buffer_list.cc ) s.files += %w( src/core/lib/iomgr/buffer_list.h ) @@ -1494,6 +1492,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/promise/latch.h ) s.files += %w( src/core/lib/promise/loop.h ) s.files += %w( src/core/lib/promise/map.h ) + s.files += %w( src/core/lib/promise/observable.h ) s.files += %w( src/core/lib/promise/party.cc ) s.files += %w( src/core/lib/promise/party.h ) s.files += %w( src/core/lib/promise/pipe.h ) @@ -1919,6 +1918,14 @@ Gem::Specification.new do |s| s.files += %w( src/core/util/alloc.h ) s.files += %w( src/core/util/android/log.cc ) s.files += %w( src/core/util/atm.cc ) + s.files += %w( src/core/util/http_client/format_request.cc ) + s.files += %w( src/core/util/http_client/format_request.h ) + s.files += %w( src/core/util/http_client/httpcli.cc ) + s.files += %w( src/core/util/http_client/httpcli.h ) + s.files += %w( src/core/util/http_client/httpcli_security_connector.cc ) + s.files += %w( src/core/util/http_client/httpcli_ssl_credentials.h ) + s.files += %w( src/core/util/http_client/parser.cc ) + s.files += %w( src/core/util/http_client/parser.h ) s.files += %w( src/core/util/iphone/cpu.cc ) s.files += %w( src/core/util/json/json.h ) s.files += %w( src/core/util/json/json_args.h ) @@ -2517,7 +2524,6 @@ Gem::Specification.new do |s| s.files += %w( third_party/boringssl-with-bazel/src/crypto/cipher_extra/internal.h ) s.files += %w( third_party/boringssl-with-bazel/src/crypto/cipher_extra/tls_cbc.c ) s.files += %w( third_party/boringssl-with-bazel/src/crypto/conf/conf.c ) - s.files += %w( third_party/boringssl-with-bazel/src/crypto/conf/conf_def.h ) s.files += %w( third_party/boringssl-with-bazel/src/crypto/conf/internal.h ) s.files += %w( third_party/boringssl-with-bazel/src/crypto/cpu_aarch64_apple.c ) s.files += %w( third_party/boringssl-with-bazel/src/crypto/cpu_aarch64_fuchsia.c ) @@ -2540,6 +2546,8 @@ Gem::Specification.new do |s| s.files += %w( third_party/boringssl-with-bazel/src/crypto/dh_extra/dh_asn1.c ) s.files += %w( third_party/boringssl-with-bazel/src/crypto/dh_extra/params.c ) s.files += %w( third_party/boringssl-with-bazel/src/crypto/digest_extra/digest_extra.c ) + s.files += %w( third_party/boringssl-with-bazel/src/crypto/dilithium/dilithium.c ) + s.files += %w( third_party/boringssl-with-bazel/src/crypto/dilithium/internal.h ) s.files += %w( third_party/boringssl-with-bazel/src/crypto/dsa/dsa.c ) s.files += %w( third_party/boringssl-with-bazel/src/crypto/dsa/dsa_asn1.c ) s.files += %w( third_party/boringssl-with-bazel/src/crypto/dsa/internal.h ) @@ -2860,6 +2868,7 @@ Gem::Specification.new do |s| s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/evp.h ) s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/evp_errors.h ) s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/ex_data.h ) + s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/experimental/dilithium.h ) s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/experimental/kyber.h ) s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/experimental/spx.h ) s.files += %w( third_party/boringssl-with-bazel/src/include/openssl/hkdf.h ) diff --git a/grpc.gyp b/grpc.gyp new file mode 100644 index 00000000000..2327e4ad03a --- /dev/null +++ b/grpc.gyp @@ -0,0 +1,2669 @@ +# GRPC GYP build file + +# This file has been automatically generated from a template file. +# Please look at the templates directory instead. +# This file can be regenerated from the template by running +# tools/buildgen/generate_projects.sh + +# 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. + +{ + 'variables': { + # The openssl and zlib dependencies must be passed in as variables + # defined in an included gypi file, usually common.gypi. + 'openssl_gyp_target%': 'Please Define openssl_gyp_target variable', + 'zlib_gyp_target%': 'Please Define zlib_gyp_target variable', + + 'grpc_gcov%': 'false', + 'grpc_alpine%': 'false', + }, + 'target_defaults': { + 'configurations': { + 'Debug': { + 'cflags': [ + '-O0', + ], + 'defines': [ + '_DEBUG', + 'DEBUG', + ], + }, + 'Release': { + 'cflags': [ + '-O2', + '-Wframe-larger-than=16384', + ], + 'defines': [ + 'NDEBUG', + ], + }, + }, + 'cflags': [ + '-g', + '-Wall', + '-Wextra', + '-DOSATOMIC_USE_INLINED=1', + '-Ithird_party/abseil-cpp', + '-Ithird_party/re2', + '-Ithird_party/upb', + '-Isrc/core/ext/upb-gen', + '-Isrc/core/ext/upbdefs-gen', + '-Ithird_party/utf8_range', + '-Ithird_party/xxhash', + ], + 'ldflags': [ + '-g', + ], + 'cflags_c': [ + '-Werror', + '-std=c11', + ], + 'cflags_cc': [ + '-Werror', + '-std=c++14', + ], + 'include_dirs': [ + '.', + '../..', + 'include', + ], + 'defines': [ + 'GRPC_ARES=0', + ], + 'dependencies': [ + '<(openssl_gyp_target)', + '<(zlib_gyp_target)', + ], + 'conditions': [ + ['grpc_gcov=="true"', { + 'cflags': [ + '-O0', + '-fprofile-arcs', + '-ftest-coverage', + '-Wno-return-type', + ], + 'defines': [ + '_DEBUG', + 'DEBUG', + 'GPR_GCOV', + ], + 'ldflags': [ + '-fprofile-arcs', + '-ftest-coverage', + '-rdynamic', + '-lstdc++', + ], + }], + ['grpc_alpine=="true"', { + 'defines': [ + 'GPR_MUSL_LIBC_COMPAT' + ] + }], + ['OS == "win"', { + 'defines': [ + '_WIN32_WINNT=0x0600', + 'WIN32_LEAN_AND_MEAN', + '_HAS_EXCEPTIONS=0', + 'UNICODE', + '_UNICODE', + 'NOMINMAX', + ], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'RuntimeLibrary': 1, # static debug + } + }, + "libraries": [ + "ws2_32" + ] + }], + ['OS == "mac"', { + 'xcode_settings': { + 'OTHER_CFLAGS': [ + '-g', + '-Wall', + '-Wextra', + '-DOSATOMIC_USE_INLINED=1', + '-Ithird_party/abseil-cpp', + '-Ithird_party/re2', + '-Ithird_party/upb', + '-Isrc/core/ext/upb-gen', + '-Isrc/core/ext/upbdefs-gen', + '-Ithird_party/utf8_range', + '-Ithird_party/xxhash', + ], + 'OTHER_CPLUSPLUSFLAGS': [ + '-g', + '-Wall', + '-Wextra', + '-DOSATOMIC_USE_INLINED=1', + '-Ithird_party/abseil-cpp', + '-Ithird_party/re2', + '-Ithird_party/upb', + '-Isrc/core/ext/upb-gen', + '-Isrc/core/ext/upbdefs-gen', + '-Ithird_party/utf8_range', + '-Ithird_party/xxhash', + '-stdlib=libc++', + '-std=c++14', + '-Wno-error=deprecated-declarations', + ], + }, + }] + ] + }, + 'targets': [ + { + 'target_name': 'address_sorting', + 'type': 'static_library', + 'dependencies': [ + ], + 'sources': [ + 'third_party/address_sorting/address_sorting.c', + 'third_party/address_sorting/address_sorting_posix.c', + 'third_party/address_sorting/address_sorting_windows.c', + ], + }, + { + 'target_name': 'gpr', + 'type': 'static_library', + 'dependencies': [ + 'absl/base:base', + 'absl/base:core_headers', + 'absl/flags:flag', + 'absl/flags:marshalling', + 'absl/functional:any_invocable', + 'absl/memory:memory', + 'absl/random:random', + 'absl/status:status', + 'absl/strings:cord', + 'absl/strings:str_format', + 'absl/strings:strings', + 'absl/synchronization:synchronization', + 'absl/time:time', + 'absl/types:optional', + 'absl/types:variant', + ], + 'sources': [ + 'src/core/lib/config/config_vars.cc', + 'src/core/lib/config/config_vars_non_generated.cc', + 'src/core/lib/config/load_config.cc', + 'src/core/lib/event_engine/thread_local.cc', + 'src/core/lib/gpr/alloc.cc', + 'src/core/lib/gpr/android/log.cc', + 'src/core/lib/gpr/atm.cc', + 'src/core/lib/gpr/iphone/cpu.cc', + 'src/core/lib/gpr/linux/cpu.cc', + 'src/core/lib/gpr/linux/log.cc', + 'src/core/lib/gpr/log.cc', + 'src/core/lib/gpr/msys/tmpfile.cc', + 'src/core/lib/gpr/posix/cpu.cc', + 'src/core/lib/gpr/posix/log.cc', + 'src/core/lib/gpr/posix/string.cc', + 'src/core/lib/gpr/posix/sync.cc', + 'src/core/lib/gpr/posix/time.cc', + 'src/core/lib/gpr/posix/tmpfile.cc', + 'src/core/lib/gpr/string.cc', + 'src/core/lib/gpr/sync.cc', + 'src/core/lib/gpr/sync_abseil.cc', + 'src/core/lib/gpr/time.cc', + 'src/core/lib/gpr/time_precise.cc', + 'src/core/lib/gpr/windows/cpu.cc', + 'src/core/lib/gpr/windows/log.cc', + 'src/core/lib/gpr/windows/string.cc', + 'src/core/lib/gpr/windows/string_util.cc', + 'src/core/lib/gpr/windows/sync.cc', + 'src/core/lib/gpr/windows/time.cc', + 'src/core/lib/gpr/windows/tmpfile.cc', + 'src/core/lib/gprpp/crash.cc', + 'src/core/lib/gprpp/examine_stack.cc', + 'src/core/lib/gprpp/fork.cc', + 'src/core/lib/gprpp/host_port.cc', + 'src/core/lib/gprpp/linux/env.cc', + 'src/core/lib/gprpp/mpscq.cc', + 'src/core/lib/gprpp/posix/env.cc', + 'src/core/lib/gprpp/posix/stat.cc', + 'src/core/lib/gprpp/posix/thd.cc', + 'src/core/lib/gprpp/strerror.cc', + 'src/core/lib/gprpp/tchar.cc', + 'src/core/lib/gprpp/time_util.cc', + 'src/core/lib/gprpp/windows/env.cc', + 'src/core/lib/gprpp/windows/stat.cc', + 'src/core/lib/gprpp/windows/thd.cc', + ], + }, + { + 'target_name': 'grpc', + 'type': 'static_library', + 'dependencies': [ + 'upb_json_lib', + 'upb_textformat_lib', + 're2', + 'z', + 'absl/algorithm:container', + 'absl/base:config', + 'absl/base:no_destructor', + 'absl/cleanup:cleanup', + 'absl/container:flat_hash_map', + 'absl/container:flat_hash_set', + 'absl/container:inlined_vector', + 'absl/functional:bind_front', + 'absl/functional:function_ref', + 'absl/hash:hash', + 'absl/meta:type_traits', + 'absl/random:bit_gen_ref', + 'absl/random:distributions', + 'absl/status:statusor', + 'absl/types:span', + 'absl/utility:utility', + 'cares', + 'gpr', + 'address_sorting', + ], + 'sources': [ + 'src/core/client_channel/backup_poller.cc', + 'src/core/client_channel/client_channel.cc', + 'src/core/client_channel/client_channel_channelz.cc', + 'src/core/client_channel/client_channel_factory.cc', + 'src/core/client_channel/client_channel_filter.cc', + 'src/core/client_channel/client_channel_plugin.cc', + 'src/core/client_channel/client_channel_service_config.cc', + 'src/core/client_channel/config_selector.cc', + 'src/core/client_channel/dynamic_filters.cc', + 'src/core/client_channel/global_subchannel_pool.cc', + 'src/core/client_channel/http_proxy_mapper.cc', + 'src/core/client_channel/local_subchannel_pool.cc', + 'src/core/client_channel/retry_filter.cc', + 'src/core/client_channel/retry_filter_legacy_call_data.cc', + 'src/core/client_channel/retry_service_config.cc', + 'src/core/client_channel/retry_throttle.cc', + 'src/core/client_channel/subchannel.cc', + 'src/core/client_channel/subchannel_pool_interface.cc', + 'src/core/client_channel/subchannel_stream_client.cc', + 'src/core/ext/filters/backend_metrics/backend_metric_filter.cc', + '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/deadline/deadline_filter.cc', + 'src/core/ext/filters/fault_injection/fault_injection_filter.cc', + 'src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc', + 'src/core/ext/filters/http/client/http_client_filter.cc', + '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', + 'src/core/ext/filters/rbac/rbac_service_config_parser.cc', + 'src/core/ext/filters/server_config_selector/server_config_selector_filter.cc', + 'src/core/ext/filters/stateful_session/stateful_session_filter.cc', + 'src/core/ext/filters/stateful_session/stateful_session_service_config_parser.cc', + 'src/core/ext/gcp/metadata_query.cc', + 'src/core/ext/transport/chttp2/alpn/alpn.cc', + 'src/core/ext/transport/chttp2/client/chttp2_connector.cc', + 'src/core/ext/transport/chttp2/server/chttp2_server.cc', + 'src/core/ext/transport/chttp2/transport/bin_decoder.cc', + 'src/core/ext/transport/chttp2/transport/bin_encoder.cc', + 'src/core/ext/transport/chttp2/transport/chttp2_transport.cc', + 'src/core/ext/transport/chttp2/transport/decode_huff.cc', + 'src/core/ext/transport/chttp2/transport/flow_control.cc', + 'src/core/ext/transport/chttp2/transport/frame.cc', + 'src/core/ext/transport/chttp2/transport/frame_data.cc', + 'src/core/ext/transport/chttp2/transport/frame_goaway.cc', + 'src/core/ext/transport/chttp2/transport/frame_ping.cc', + 'src/core/ext/transport/chttp2/transport/frame_rst_stream.cc', + 'src/core/ext/transport/chttp2/transport/frame_settings.cc', + 'src/core/ext/transport/chttp2/transport/frame_window_update.cc', + 'src/core/ext/transport/chttp2/transport/hpack_encoder.cc', + 'src/core/ext/transport/chttp2/transport/hpack_encoder_table.cc', + 'src/core/ext/transport/chttp2/transport/hpack_parse_result.cc', + 'src/core/ext/transport/chttp2/transport/hpack_parser.cc', + 'src/core/ext/transport/chttp2/transport/hpack_parser_table.cc', + 'src/core/ext/transport/chttp2/transport/http2_settings.cc', + 'src/core/ext/transport/chttp2/transport/http_trace.cc', + 'src/core/ext/transport/chttp2/transport/huffsyms.cc', + 'src/core/ext/transport/chttp2/transport/max_concurrent_streams_policy.cc', + 'src/core/ext/transport/chttp2/transport/parsing.cc', + 'src/core/ext/transport/chttp2/transport/ping_abuse_policy.cc', + 'src/core/ext/transport/chttp2/transport/ping_callbacks.cc', + 'src/core/ext/transport/chttp2/transport/ping_rate_policy.cc', + 'src/core/ext/transport/chttp2/transport/stream_lists.cc', + 'src/core/ext/transport/chttp2/transport/varint.cc', + 'src/core/ext/transport/chttp2/transport/write_size_policy.cc', + 'src/core/ext/transport/chttp2/transport/writing.cc', + 'src/core/ext/transport/inproc/inproc_plugin.cc', + 'src/core/ext/transport/inproc/inproc_transport.cc', + 'src/core/ext/transport/inproc/legacy_inproc_transport.cc', + 'src/core/ext/upb-gen/envoy/admin/v3/certs.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/admin/v3/clusters.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/admin/v3/config_dump.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/admin/v3/config_dump_shared.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/admin/v3/init_dump.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/admin/v3/listeners.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/admin/v3/memory.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/admin/v3/metrics.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/admin/v3/mutex_stats.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/admin/v3/server_info.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/admin/v3/tap.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/annotations/deprecation.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/annotations/resource.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/accesslog/v3/accesslog.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/bootstrap/v3/bootstrap.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/cluster/v3/circuit_breaker.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/cluster/v3/cluster.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/cluster/v3/filter.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/cluster/v3/outlier_detection.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/common/matcher/v3/matcher.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/core/v3/address.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/core/v3/backoff.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/core/v3/base.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/core/v3/config_source.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/core/v3/event_service_config.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/core/v3/extension.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/core/v3/grpc_method_list.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/core/v3/grpc_service.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/core/v3/health_check.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/core/v3/http_service.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/core/v3/http_uri.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/core/v3/protocol.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/core/v3/proxy_protocol.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/core/v3/resolver.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/core/v3/socket_option.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/core/v3/substitution_format_string.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/core/v3/udp_socket_config.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/endpoint/v3/endpoint.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/endpoint/v3/endpoint_components.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/endpoint/v3/load_report.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/listener/v3/api_listener.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/listener/v3/listener.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/listener/v3/listener_components.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/listener/v3/quic_config.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/listener/v3/udp_listener_config.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/metrics/v3/metrics_service.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/metrics/v3/stats.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/overload/v3/overload.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/rbac/v3/rbac.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/route/v3/route.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/route/v3/route_components.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/route/v3/scoped_route.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/tap/v3/common.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/trace/v3/datadog.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/trace/v3/dynamic_ot.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/trace/v3/http_tracer.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/trace/v3/lightstep.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/trace/v3/opencensus.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/trace/v3/opentelemetry.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/trace/v3/service.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/trace/v3/skywalking.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/trace/v3/trace.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/trace/v3/xray.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/config/trace/v3/zipkin.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/data/accesslog/v3/accesslog.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/extensions/clusters/aggregate/v3/cluster.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/extensions/filters/common/fault/v3/fault.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/extensions/filters/http/fault/v3/fault.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/extensions/filters/http/rbac/v3/rbac.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/extensions/filters/http/router/v3/router.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/extensions/filters/http/stateful_session/v3/stateful_session.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/extensions/http/stateful_session/cookie/v3/cookie.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/extensions/load_balancing_policies/client_side_weighted_round_robin/v3/client_side_weighted_round_robin.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/extensions/load_balancing_policies/common/v3/common.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/extensions/load_balancing_policies/pick_first/v3/pick_first.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/extensions/load_balancing_policies/ring_hash/v3/ring_hash.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/extensions/load_balancing_policies/wrr_locality/v3/wrr_locality.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/extensions/transport_sockets/tls/v3/cert.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/extensions/transport_sockets/tls/v3/common.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/extensions/transport_sockets/tls/v3/secret.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/extensions/transport_sockets/tls/v3/tls.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/extensions/transport_sockets/tls/v3/tls_spiffe_validator_config.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/extensions/upstreams/http/v3/http_protocol_options.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/service/discovery/v3/ads.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/service/discovery/v3/discovery.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/service/load_stats/v3/lrs.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/service/status/v3/csds.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/type/http/v3/cookie.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/type/http/v3/path_transformation.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/type/matcher/v3/filter_state.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/type/matcher/v3/http_inputs.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/type/matcher/v3/metadata.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/type/matcher/v3/node.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/type/matcher/v3/number.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/type/matcher/v3/path.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/type/matcher/v3/regex.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/type/matcher/v3/status_code_input.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/type/matcher/v3/string.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/type/matcher/v3/struct.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/type/matcher/v3/value.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/type/metadata/v3/metadata.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/type/tracing/v3/custom_tag.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/type/v3/hash_policy.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/type/v3/http.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/type/v3/http_status.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/type/v3/percent.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/type/v3/range.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/type/v3/ratelimit_strategy.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/type/v3/ratelimit_unit.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/type/v3/semantic_version.upb_minitable.c', + 'src/core/ext/upb-gen/envoy/type/v3/token_bucket.upb_minitable.c', + 'src/core/ext/upb-gen/google/api/annotations.upb_minitable.c', + 'src/core/ext/upb-gen/google/api/expr/v1alpha1/checked.upb_minitable.c', + 'src/core/ext/upb-gen/google/api/expr/v1alpha1/syntax.upb_minitable.c', + 'src/core/ext/upb-gen/google/api/http.upb_minitable.c', + 'src/core/ext/upb-gen/google/api/httpbody.upb_minitable.c', + 'src/core/ext/upb-gen/google/protobuf/any.upb_minitable.c', + 'src/core/ext/upb-gen/google/protobuf/descriptor.upb_minitable.c', + 'src/core/ext/upb-gen/google/protobuf/duration.upb_minitable.c', + 'src/core/ext/upb-gen/google/protobuf/empty.upb_minitable.c', + 'src/core/ext/upb-gen/google/protobuf/struct.upb_minitable.c', + 'src/core/ext/upb-gen/google/protobuf/timestamp.upb_minitable.c', + 'src/core/ext/upb-gen/google/protobuf/wrappers.upb_minitable.c', + 'src/core/ext/upb-gen/google/rpc/status.upb_minitable.c', + 'src/core/ext/upb-gen/opencensus/proto/trace/v1/trace_config.upb_minitable.c', + 'src/core/ext/upb-gen/src/proto/grpc/gcp/altscontext.upb_minitable.c', + 'src/core/ext/upb-gen/src/proto/grpc/gcp/handshaker.upb_minitable.c', + 'src/core/ext/upb-gen/src/proto/grpc/gcp/transport_security_common.upb_minitable.c', + 'src/core/ext/upb-gen/src/proto/grpc/health/v1/health.upb_minitable.c', + 'src/core/ext/upb-gen/src/proto/grpc/lb/v1/load_balancer.upb_minitable.c', + 'src/core/ext/upb-gen/src/proto/grpc/lookup/v1/rls.upb_minitable.c', + 'src/core/ext/upb-gen/src/proto/grpc/lookup/v1/rls_config.upb_minitable.c', + 'src/core/ext/upb-gen/udpa/annotations/migrate.upb_minitable.c', + 'src/core/ext/upb-gen/udpa/annotations/security.upb_minitable.c', + 'src/core/ext/upb-gen/udpa/annotations/sensitive.upb_minitable.c', + 'src/core/ext/upb-gen/udpa/annotations/status.upb_minitable.c', + 'src/core/ext/upb-gen/udpa/annotations/versioning.upb_minitable.c', + 'src/core/ext/upb-gen/validate/validate.upb_minitable.c', + 'src/core/ext/upb-gen/xds/annotations/v3/migrate.upb_minitable.c', + 'src/core/ext/upb-gen/xds/annotations/v3/security.upb_minitable.c', + 'src/core/ext/upb-gen/xds/annotations/v3/sensitive.upb_minitable.c', + 'src/core/ext/upb-gen/xds/annotations/v3/status.upb_minitable.c', + 'src/core/ext/upb-gen/xds/annotations/v3/versioning.upb_minitable.c', + 'src/core/ext/upb-gen/xds/core/v3/authority.upb_minitable.c', + 'src/core/ext/upb-gen/xds/core/v3/cidr.upb_minitable.c', + 'src/core/ext/upb-gen/xds/core/v3/collection_entry.upb_minitable.c', + 'src/core/ext/upb-gen/xds/core/v3/context_params.upb_minitable.c', + 'src/core/ext/upb-gen/xds/core/v3/extension.upb_minitable.c', + 'src/core/ext/upb-gen/xds/core/v3/resource.upb_minitable.c', + 'src/core/ext/upb-gen/xds/core/v3/resource_locator.upb_minitable.c', + 'src/core/ext/upb-gen/xds/core/v3/resource_name.upb_minitable.c', + 'src/core/ext/upb-gen/xds/data/orca/v3/orca_load_report.upb_minitable.c', + 'src/core/ext/upb-gen/xds/service/orca/v3/orca.upb_minitable.c', + 'src/core/ext/upb-gen/xds/type/matcher/v3/cel.upb_minitable.c', + 'src/core/ext/upb-gen/xds/type/matcher/v3/domain.upb_minitable.c', + 'src/core/ext/upb-gen/xds/type/matcher/v3/http_inputs.upb_minitable.c', + 'src/core/ext/upb-gen/xds/type/matcher/v3/ip.upb_minitable.c', + 'src/core/ext/upb-gen/xds/type/matcher/v3/matcher.upb_minitable.c', + 'src/core/ext/upb-gen/xds/type/matcher/v3/range.upb_minitable.c', + 'src/core/ext/upb-gen/xds/type/matcher/v3/regex.upb_minitable.c', + 'src/core/ext/upb-gen/xds/type/matcher/v3/string.upb_minitable.c', + 'src/core/ext/upb-gen/xds/type/v3/cel.upb_minitable.c', + 'src/core/ext/upb-gen/xds/type/v3/range.upb_minitable.c', + 'src/core/ext/upb-gen/xds/type/v3/typed_struct.upb_minitable.c', + 'src/core/ext/upbdefs-gen/envoy/admin/v3/certs.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/admin/v3/clusters.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/admin/v3/config_dump.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/admin/v3/config_dump_shared.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/admin/v3/init_dump.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/admin/v3/listeners.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/admin/v3/memory.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/admin/v3/metrics.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/admin/v3/mutex_stats.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/admin/v3/server_info.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/admin/v3/tap.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/annotations/deprecation.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/annotations/resource.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/accesslog/v3/accesslog.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/bootstrap/v3/bootstrap.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/cluster/v3/circuit_breaker.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/cluster/v3/cluster.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/cluster/v3/filter.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/cluster/v3/outlier_detection.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/common/matcher/v3/matcher.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/core/v3/address.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/core/v3/backoff.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/core/v3/base.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/core/v3/config_source.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/core/v3/event_service_config.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/core/v3/extension.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/core/v3/grpc_method_list.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/core/v3/grpc_service.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/core/v3/health_check.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/core/v3/http_service.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/core/v3/http_uri.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/core/v3/protocol.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/core/v3/proxy_protocol.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/core/v3/resolver.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/core/v3/socket_option.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/core/v3/substitution_format_string.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/core/v3/udp_socket_config.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/endpoint/v3/endpoint.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/endpoint/v3/endpoint_components.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/endpoint/v3/load_report.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/listener/v3/api_listener.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/listener/v3/listener.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/listener/v3/listener_components.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/listener/v3/quic_config.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/listener/v3/udp_listener_config.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/metrics/v3/metrics_service.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/metrics/v3/stats.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/overload/v3/overload.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/rbac/v3/rbac.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/route/v3/route.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/route/v3/route_components.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/route/v3/scoped_route.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/tap/v3/common.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/trace/v3/datadog.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/trace/v3/dynamic_ot.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/trace/v3/http_tracer.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/trace/v3/lightstep.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/trace/v3/opencensus.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/trace/v3/opentelemetry.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/trace/v3/service.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/trace/v3/skywalking.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/trace/v3/trace.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/trace/v3/xray.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/config/trace/v3/zipkin.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/data/accesslog/v3/accesslog.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/extensions/filters/common/fault/v3/fault.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/extensions/filters/http/fault/v3/fault.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/extensions/filters/http/rbac/v3/rbac.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/extensions/filters/http/router/v3/router.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/extensions/filters/http/stateful_session/v3/stateful_session.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/extensions/http/stateful_session/cookie/v3/cookie.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/extensions/transport_sockets/tls/v3/cert.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/extensions/transport_sockets/tls/v3/common.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/extensions/transport_sockets/tls/v3/secret.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/extensions/transport_sockets/tls/v3/tls.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/extensions/transport_sockets/tls/v3/tls_spiffe_validator_config.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/extensions/upstreams/http/v3/http_protocol_options.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/service/discovery/v3/ads.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/service/discovery/v3/discovery.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/service/load_stats/v3/lrs.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/service/status/v3/csds.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/type/http/v3/cookie.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/type/http/v3/path_transformation.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/type/matcher/v3/filter_state.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/type/matcher/v3/http_inputs.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/type/matcher/v3/metadata.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/type/matcher/v3/node.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/type/matcher/v3/number.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/type/matcher/v3/path.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/type/matcher/v3/regex.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/type/matcher/v3/status_code_input.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/type/matcher/v3/string.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/type/matcher/v3/struct.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/type/matcher/v3/value.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/type/metadata/v3/metadata.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/type/tracing/v3/custom_tag.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/type/v3/hash_policy.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/type/v3/http.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/type/v3/http_status.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/type/v3/percent.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/type/v3/range.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/type/v3/ratelimit_strategy.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/type/v3/ratelimit_unit.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/type/v3/semantic_version.upbdefs.c', + 'src/core/ext/upbdefs-gen/envoy/type/v3/token_bucket.upbdefs.c', + 'src/core/ext/upbdefs-gen/google/api/annotations.upbdefs.c', + 'src/core/ext/upbdefs-gen/google/api/expr/v1alpha1/checked.upbdefs.c', + 'src/core/ext/upbdefs-gen/google/api/expr/v1alpha1/syntax.upbdefs.c', + 'src/core/ext/upbdefs-gen/google/api/http.upbdefs.c', + 'src/core/ext/upbdefs-gen/google/api/httpbody.upbdefs.c', + 'src/core/ext/upbdefs-gen/google/protobuf/any.upbdefs.c', + 'src/core/ext/upbdefs-gen/google/protobuf/descriptor.upbdefs.c', + 'src/core/ext/upbdefs-gen/google/protobuf/duration.upbdefs.c', + 'src/core/ext/upbdefs-gen/google/protobuf/empty.upbdefs.c', + 'src/core/ext/upbdefs-gen/google/protobuf/struct.upbdefs.c', + 'src/core/ext/upbdefs-gen/google/protobuf/timestamp.upbdefs.c', + 'src/core/ext/upbdefs-gen/google/protobuf/wrappers.upbdefs.c', + 'src/core/ext/upbdefs-gen/google/rpc/status.upbdefs.c', + 'src/core/ext/upbdefs-gen/opencensus/proto/trace/v1/trace_config.upbdefs.c', + 'src/core/ext/upbdefs-gen/src/proto/grpc/lookup/v1/rls_config.upbdefs.c', + 'src/core/ext/upbdefs-gen/udpa/annotations/migrate.upbdefs.c', + 'src/core/ext/upbdefs-gen/udpa/annotations/security.upbdefs.c', + 'src/core/ext/upbdefs-gen/udpa/annotations/sensitive.upbdefs.c', + 'src/core/ext/upbdefs-gen/udpa/annotations/status.upbdefs.c', + 'src/core/ext/upbdefs-gen/udpa/annotations/versioning.upbdefs.c', + 'src/core/ext/upbdefs-gen/validate/validate.upbdefs.c', + 'src/core/ext/upbdefs-gen/xds/annotations/v3/migrate.upbdefs.c', + 'src/core/ext/upbdefs-gen/xds/annotations/v3/security.upbdefs.c', + 'src/core/ext/upbdefs-gen/xds/annotations/v3/sensitive.upbdefs.c', + 'src/core/ext/upbdefs-gen/xds/annotations/v3/status.upbdefs.c', + 'src/core/ext/upbdefs-gen/xds/annotations/v3/versioning.upbdefs.c', + 'src/core/ext/upbdefs-gen/xds/core/v3/authority.upbdefs.c', + 'src/core/ext/upbdefs-gen/xds/core/v3/cidr.upbdefs.c', + 'src/core/ext/upbdefs-gen/xds/core/v3/collection_entry.upbdefs.c', + 'src/core/ext/upbdefs-gen/xds/core/v3/context_params.upbdefs.c', + 'src/core/ext/upbdefs-gen/xds/core/v3/extension.upbdefs.c', + 'src/core/ext/upbdefs-gen/xds/core/v3/resource.upbdefs.c', + 'src/core/ext/upbdefs-gen/xds/core/v3/resource_locator.upbdefs.c', + 'src/core/ext/upbdefs-gen/xds/core/v3/resource_name.upbdefs.c', + 'src/core/ext/upbdefs-gen/xds/type/matcher/v3/cel.upbdefs.c', + 'src/core/ext/upbdefs-gen/xds/type/matcher/v3/domain.upbdefs.c', + 'src/core/ext/upbdefs-gen/xds/type/matcher/v3/http_inputs.upbdefs.c', + 'src/core/ext/upbdefs-gen/xds/type/matcher/v3/ip.upbdefs.c', + 'src/core/ext/upbdefs-gen/xds/type/matcher/v3/matcher.upbdefs.c', + 'src/core/ext/upbdefs-gen/xds/type/matcher/v3/range.upbdefs.c', + 'src/core/ext/upbdefs-gen/xds/type/matcher/v3/regex.upbdefs.c', + 'src/core/ext/upbdefs-gen/xds/type/matcher/v3/string.upbdefs.c', + 'src/core/ext/upbdefs-gen/xds/type/v3/cel.upbdefs.c', + 'src/core/ext/upbdefs-gen/xds/type/v3/range.upbdefs.c', + 'src/core/ext/upbdefs-gen/xds/type/v3/typed_struct.upbdefs.c', + 'src/core/ext/xds/certificate_provider_store.cc', + 'src/core/ext/xds/file_watcher_certificate_provider_factory.cc', + 'src/core/ext/xds/xds_api.cc', + 'src/core/ext/xds/xds_audit_logger_registry.cc', + 'src/core/ext/xds/xds_bootstrap.cc', + 'src/core/ext/xds/xds_bootstrap_grpc.cc', + 'src/core/ext/xds/xds_certificate_provider.cc', + 'src/core/ext/xds/xds_channel_stack_modifier.cc', + 'src/core/ext/xds/xds_client.cc', + 'src/core/ext/xds/xds_client_grpc.cc', + 'src/core/ext/xds/xds_client_stats.cc', + 'src/core/ext/xds/xds_cluster.cc', + 'src/core/ext/xds/xds_cluster_specifier_plugin.cc', + 'src/core/ext/xds/xds_common_types.cc', + 'src/core/ext/xds/xds_endpoint.cc', + 'src/core/ext/xds/xds_health_status.cc', + 'src/core/ext/xds/xds_http_fault_filter.cc', + 'src/core/ext/xds/xds_http_filters.cc', + 'src/core/ext/xds/xds_http_rbac_filter.cc', + 'src/core/ext/xds/xds_http_stateful_session_filter.cc', + 'src/core/ext/xds/xds_lb_policy_registry.cc', + 'src/core/ext/xds/xds_listener.cc', + 'src/core/ext/xds/xds_route_config.cc', + 'src/core/ext/xds/xds_routing.cc', + 'src/core/ext/xds/xds_server_config_fetcher.cc', + 'src/core/ext/xds/xds_transport_grpc.cc', + 'src/core/lib/address_utils/parse_address.cc', + 'src/core/lib/address_utils/sockaddr_utils.cc', + 'src/core/lib/backoff/backoff.cc', + 'src/core/lib/backoff/random_early_detection.cc', + 'src/core/lib/channel/call_tracer.cc', + 'src/core/lib/channel/channel_args.cc', + 'src/core/lib/channel/channel_args_preconditioning.cc', + 'src/core/lib/channel/channel_stack.cc', + 'src/core/lib/channel/channel_stack_builder.cc', + 'src/core/lib/channel/channel_stack_builder_impl.cc', + 'src/core/lib/channel/channel_stack_trace.cc', + 'src/core/lib/channel/channel_trace.cc', + 'src/core/lib/channel/channelz.cc', + 'src/core/lib/channel/channelz_registry.cc', + 'src/core/lib/channel/connected_channel.cc', + 'src/core/lib/channel/metrics.cc', + 'src/core/lib/channel/promise_based_filter.cc', + 'src/core/lib/channel/server_call_tracer_filter.cc', + 'src/core/lib/channel/status_util.cc', + 'src/core/lib/compression/compression.cc', + 'src/core/lib/compression/compression_internal.cc', + 'src/core/lib/compression/message_compress.cc', + 'src/core/lib/config/core_configuration.cc', + 'src/core/lib/debug/event_log.cc', + 'src/core/lib/debug/histogram_view.cc', + 'src/core/lib/debug/stats.cc', + 'src/core/lib/debug/stats_data.cc', + 'src/core/lib/debug/trace.cc', + 'src/core/lib/event_engine/ares_resolver.cc', + 'src/core/lib/event_engine/cf_engine/cf_engine.cc', + 'src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc', + 'src/core/lib/event_engine/cf_engine/dns_service_resolver.cc', + 'src/core/lib/event_engine/channel_args_endpoint_config.cc', + 'src/core/lib/event_engine/default_event_engine.cc', + '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/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_posix_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', + 'src/core/lib/event_engine/posix_engine/posix_engine_listener_utils.cc', + 'src/core/lib/event_engine/posix_engine/tcp_socket_utils.cc', + 'src/core/lib/event_engine/posix_engine/timer.cc', + 'src/core/lib/event_engine/posix_engine/timer_heap.cc', + 'src/core/lib/event_engine/posix_engine/timer_manager.cc', + 'src/core/lib/event_engine/posix_engine/traced_buffer_list.cc', + 'src/core/lib/event_engine/posix_engine/wakeup_fd_eventfd.cc', + 'src/core/lib/event_engine/posix_engine/wakeup_fd_pipe.cc', + 'src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.cc', + 'src/core/lib/event_engine/resolved_address.cc', + 'src/core/lib/event_engine/shim.cc', + 'src/core/lib/event_engine/slice.cc', + 'src/core/lib/event_engine/slice_buffer.cc', + 'src/core/lib/event_engine/tcp_socket_utils.cc', + 'src/core/lib/event_engine/thread_pool/thread_count.cc', + 'src/core/lib/event_engine/thread_pool/thread_pool_factory.cc', + 'src/core/lib/event_engine/thread_pool/work_stealing_thread_pool.cc', + 'src/core/lib/event_engine/thready_event_engine/thready_event_engine.cc', + 'src/core/lib/event_engine/time_util.cc', + 'src/core/lib/event_engine/trace.cc', + 'src/core/lib/event_engine/utils.cc', + 'src/core/lib/event_engine/windows/grpc_polled_fd_windows.cc', + 'src/core/lib/event_engine/windows/iocp.cc', + 'src/core/lib/event_engine/windows/native_windows_dns_resolver.cc', + 'src/core/lib/event_engine/windows/win_socket.cc', + 'src/core/lib/event_engine/windows/windows_endpoint.cc', + 'src/core/lib/event_engine/windows/windows_engine.cc', + 'src/core/lib/event_engine/windows/windows_listener.cc', + 'src/core/lib/event_engine/work_queue/basic_work_queue.cc', + 'src/core/lib/experiments/config.cc', + 'src/core/lib/experiments/experiments.cc', + 'src/core/lib/gprpp/load_file.cc', + 'src/core/lib/gprpp/per_cpu.cc', + 'src/core/lib/gprpp/posix/directory_reader.cc', + 'src/core/lib/gprpp/ref_counted_string.cc', + 'src/core/lib/gprpp/status_helper.cc', + 'src/core/lib/gprpp/time.cc', + 'src/core/lib/gprpp/time_averaged_stats.cc', + 'src/core/lib/gprpp/validation_errors.cc', + 'src/core/lib/gprpp/windows/directory_reader.cc', + 'src/core/lib/gprpp/work_serializer.cc', + 'src/core/lib/handshaker/proxy_mapper_registry.cc', + 'src/core/lib/http/format_request.cc', + 'src/core/lib/http/httpcli.cc', + 'src/core/lib/http/httpcli_security_connector.cc', + 'src/core/lib/http/parser.cc', + 'src/core/lib/iomgr/buffer_list.cc', + 'src/core/lib/iomgr/call_combiner.cc', + 'src/core/lib/iomgr/cfstream_handle.cc', + 'src/core/lib/iomgr/closure.cc', + 'src/core/lib/iomgr/combiner.cc', + 'src/core/lib/iomgr/dualstack_socket_posix.cc', + 'src/core/lib/iomgr/endpoint.cc', + 'src/core/lib/iomgr/endpoint_cfstream.cc', + 'src/core/lib/iomgr/endpoint_pair_posix.cc', + 'src/core/lib/iomgr/endpoint_pair_windows.cc', + 'src/core/lib/iomgr/error.cc', + 'src/core/lib/iomgr/error_cfstream.cc', + 'src/core/lib/iomgr/ev_apple.cc', + 'src/core/lib/iomgr/ev_epoll1_linux.cc', + 'src/core/lib/iomgr/ev_poll_posix.cc', + 'src/core/lib/iomgr/ev_posix.cc', + 'src/core/lib/iomgr/ev_windows.cc', + 'src/core/lib/iomgr/event_engine_shims/closure.cc', + 'src/core/lib/iomgr/event_engine_shims/endpoint.cc', + 'src/core/lib/iomgr/event_engine_shims/tcp_client.cc', + 'src/core/lib/iomgr/exec_ctx.cc', + 'src/core/lib/iomgr/executor.cc', + 'src/core/lib/iomgr/fork_posix.cc', + 'src/core/lib/iomgr/fork_windows.cc', + 'src/core/lib/iomgr/gethostname_fallback.cc', + 'src/core/lib/iomgr/gethostname_host_name_max.cc', + 'src/core/lib/iomgr/gethostname_sysconf.cc', + 'src/core/lib/iomgr/grpc_if_nametoindex_posix.cc', + 'src/core/lib/iomgr/grpc_if_nametoindex_unsupported.cc', + 'src/core/lib/iomgr/internal_errqueue.cc', + 'src/core/lib/iomgr/iocp_windows.cc', + 'src/core/lib/iomgr/iomgr.cc', + 'src/core/lib/iomgr/iomgr_internal.cc', + 'src/core/lib/iomgr/iomgr_posix.cc', + 'src/core/lib/iomgr/iomgr_posix_cfstream.cc', + 'src/core/lib/iomgr/iomgr_windows.cc', + 'src/core/lib/iomgr/lockfree_event.cc', + 'src/core/lib/iomgr/polling_entity.cc', + 'src/core/lib/iomgr/pollset.cc', + 'src/core/lib/iomgr/pollset_set.cc', + 'src/core/lib/iomgr/pollset_set_windows.cc', + 'src/core/lib/iomgr/pollset_windows.cc', + 'src/core/lib/iomgr/resolve_address.cc', + 'src/core/lib/iomgr/resolve_address_posix.cc', + 'src/core/lib/iomgr/resolve_address_windows.cc', + 'src/core/lib/iomgr/sockaddr_utils_posix.cc', + 'src/core/lib/iomgr/socket_factory_posix.cc', + 'src/core/lib/iomgr/socket_mutator.cc', + 'src/core/lib/iomgr/socket_utils_common_posix.cc', + 'src/core/lib/iomgr/socket_utils_linux.cc', + 'src/core/lib/iomgr/socket_utils_posix.cc', + 'src/core/lib/iomgr/socket_utils_windows.cc', + 'src/core/lib/iomgr/socket_windows.cc', + 'src/core/lib/iomgr/systemd_utils.cc', + 'src/core/lib/iomgr/tcp_client.cc', + 'src/core/lib/iomgr/tcp_client_cfstream.cc', + 'src/core/lib/iomgr/tcp_client_posix.cc', + 'src/core/lib/iomgr/tcp_client_windows.cc', + 'src/core/lib/iomgr/tcp_posix.cc', + 'src/core/lib/iomgr/tcp_server.cc', + 'src/core/lib/iomgr/tcp_server_posix.cc', + 'src/core/lib/iomgr/tcp_server_utils_posix_common.cc', + 'src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc', + 'src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc', + 'src/core/lib/iomgr/tcp_server_windows.cc', + 'src/core/lib/iomgr/tcp_windows.cc', + 'src/core/lib/iomgr/timer.cc', + 'src/core/lib/iomgr/timer_generic.cc', + 'src/core/lib/iomgr/timer_heap.cc', + 'src/core/lib/iomgr/timer_manager.cc', + 'src/core/lib/iomgr/unix_sockets_posix.cc', + 'src/core/lib/iomgr/unix_sockets_posix_noop.cc', + 'src/core/lib/iomgr/vsock.cc', + 'src/core/lib/iomgr/wakeup_fd_eventfd.cc', + 'src/core/lib/iomgr/wakeup_fd_nospecial.cc', + 'src/core/lib/iomgr/wakeup_fd_pipe.cc', + 'src/core/lib/iomgr/wakeup_fd_posix.cc', + 'src/core/lib/json/json_object_loader.cc', + 'src/core/lib/json/json_reader.cc', + 'src/core/lib/json/json_util.cc', + 'src/core/lib/json/json_writer.cc', + 'src/core/lib/matchers/matchers.cc', + 'src/core/lib/promise/activity.cc', + 'src/core/lib/promise/party.cc', + 'src/core/lib/promise/sleep.cc', + 'src/core/lib/promise/trace.cc', + 'src/core/lib/resource_quota/api.cc', + 'src/core/lib/resource_quota/arena.cc', + 'src/core/lib/resource_quota/memory_quota.cc', + 'src/core/lib/resource_quota/periodic_update.cc', + 'src/core/lib/resource_quota/resource_quota.cc', + 'src/core/lib/resource_quota/thread_quota.cc', + 'src/core/lib/resource_quota/trace.cc', + 'src/core/lib/security/authorization/audit_logging.cc', + 'src/core/lib/security/authorization/authorization_policy_provider_vtable.cc', + 'src/core/lib/security/authorization/evaluate_args.cc', + 'src/core/lib/security/authorization/grpc_authorization_engine.cc', + 'src/core/lib/security/authorization/grpc_server_authz_filter.cc', + 'src/core/lib/security/authorization/matchers.cc', + 'src/core/lib/security/authorization/rbac_policy.cc', + 'src/core/lib/security/authorization/stdout_logger.cc', + 'src/core/lib/security/certificate_provider/certificate_provider_registry.cc', + 'src/core/lib/security/context/security_context.cc', + 'src/core/lib/security/credentials/alts/alts_credentials.cc', + 'src/core/lib/security/credentials/alts/check_gcp_environment.cc', + 'src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc', + 'src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc', + 'src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc', + 'src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc', + 'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc', + 'src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc', + 'src/core/lib/security/credentials/call_creds_util.cc', + 'src/core/lib/security/credentials/channel_creds_registry_init.cc', + 'src/core/lib/security/credentials/composite/composite_credentials.cc', + 'src/core/lib/security/credentials/credentials.cc', + 'src/core/lib/security/credentials/external/aws_external_account_credentials.cc', + 'src/core/lib/security/credentials/external/aws_request_signer.cc', + 'src/core/lib/security/credentials/external/external_account_credentials.cc', + 'src/core/lib/security/credentials/external/file_external_account_credentials.cc', + 'src/core/lib/security/credentials/external/url_external_account_credentials.cc', + 'src/core/lib/security/credentials/fake/fake_credentials.cc', + 'src/core/lib/security/credentials/google_default/credentials_generic.cc', + 'src/core/lib/security/credentials/google_default/google_default_credentials.cc', + 'src/core/lib/security/credentials/iam/iam_credentials.cc', + 'src/core/lib/security/credentials/insecure/insecure_credentials.cc', + 'src/core/lib/security/credentials/jwt/json_token.cc', + 'src/core/lib/security/credentials/jwt/jwt_credentials.cc', + 'src/core/lib/security/credentials/jwt/jwt_verifier.cc', + 'src/core/lib/security/credentials/local/local_credentials.cc', + 'src/core/lib/security/credentials/oauth2/oauth2_credentials.cc', + 'src/core/lib/security/credentials/plugin/plugin_credentials.cc', + 'src/core/lib/security/credentials/ssl/ssl_credentials.cc', + 'src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc', + 'src/core/lib/security/credentials/tls/grpc_tls_certificate_match.cc', + 'src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.cc', + 'src/core/lib/security/credentials/tls/grpc_tls_certificate_verifier.cc', + 'src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc', + 'src/core/lib/security/credentials/tls/grpc_tls_crl_provider.cc', + 'src/core/lib/security/credentials/tls/tls_credentials.cc', + 'src/core/lib/security/credentials/tls/tls_utils.cc', + 'src/core/lib/security/credentials/xds/xds_credentials.cc', + 'src/core/lib/security/security_connector/alts/alts_security_connector.cc', + 'src/core/lib/security/security_connector/fake/fake_security_connector.cc', + 'src/core/lib/security/security_connector/insecure/insecure_security_connector.cc', + 'src/core/lib/security/security_connector/load_system_roots_fallback.cc', + 'src/core/lib/security/security_connector/load_system_roots_supported.cc', + 'src/core/lib/security/security_connector/load_system_roots_windows.cc', + 'src/core/lib/security/security_connector/local/local_security_connector.cc', + 'src/core/lib/security/security_connector/security_connector.cc', + 'src/core/lib/security/security_connector/ssl/ssl_security_connector.cc', + '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', + 'src/core/lib/security/transport/tsi_error.cc', + 'src/core/lib/security/util/json_util.cc', + 'src/core/lib/slice/b64.cc', + 'src/core/lib/slice/percent_encoding.cc', + 'src/core/lib/slice/slice.cc', + 'src/core/lib/slice/slice_buffer.cc', + 'src/core/lib/slice/slice_refcount.cc', + 'src/core/lib/slice/slice_string_helpers.cc', + 'src/core/lib/surface/api_trace.cc', + 'src/core/lib/surface/byte_buffer.cc', + 'src/core/lib/surface/byte_buffer_reader.cc', + 'src/core/lib/surface/call.cc', + 'src/core/lib/surface/call_details.cc', + 'src/core/lib/surface/call_log_batch.cc', + 'src/core/lib/surface/channel.cc', + 'src/core/lib/surface/channel_create.cc', + 'src/core/lib/surface/channel_init.cc', + 'src/core/lib/surface/channel_stack_type.cc', + 'src/core/lib/surface/completion_queue.cc', + 'src/core/lib/surface/completion_queue_factory.cc', + 'src/core/lib/surface/event_string.cc', + 'src/core/lib/surface/init.cc', + 'src/core/lib/surface/init_internally.cc', + 'src/core/lib/surface/lame_client.cc', + 'src/core/lib/surface/legacy_channel.cc', + 'src/core/lib/surface/metadata_array.cc', + 'src/core/lib/surface/server.cc', + 'src/core/lib/surface/validate_metadata.cc', + 'src/core/lib/surface/version.cc', + 'src/core/lib/surface/wait_for_cq_end_op.cc', + 'src/core/lib/transport/batch_builder.cc', + 'src/core/lib/transport/bdp_estimator.cc', + 'src/core/lib/transport/call_filters.cc', + 'src/core/lib/transport/call_final_info.cc', + 'src/core/lib/transport/call_size_estimator.cc', + 'src/core/lib/transport/call_spine.cc', + 'src/core/lib/transport/connectivity_state.cc', + 'src/core/lib/transport/error_utils.cc', + 'src/core/lib/transport/handshaker.cc', + 'src/core/lib/transport/handshaker_registry.cc', + 'src/core/lib/transport/http_connect_handshaker.cc', + 'src/core/lib/transport/message.cc', + 'src/core/lib/transport/metadata.cc', + 'src/core/lib/transport/metadata_batch.cc', + 'src/core/lib/transport/metadata_info.cc', + 'src/core/lib/transport/parsed_metadata.cc', + 'src/core/lib/transport/status_conversion.cc', + 'src/core/lib/transport/tcp_connect_handshaker.cc', + 'src/core/lib/transport/timeout_encoding.cc', + 'src/core/lib/transport/transport.cc', + 'src/core/lib/transport/transport_op_string.cc', + 'src/core/lib/uri/uri_parser.cc', + 'src/core/load_balancing/address_filtering.cc', + 'src/core/load_balancing/backend_metric_parser.cc', + 'src/core/load_balancing/child_policy_handler.cc', + 'src/core/load_balancing/endpoint_list.cc', + 'src/core/load_balancing/grpclb/client_load_reporting_filter.cc', + 'src/core/load_balancing/grpclb/grpclb.cc', + 'src/core/load_balancing/grpclb/grpclb_balancer_addresses.cc', + 'src/core/load_balancing/grpclb/grpclb_client_stats.cc', + 'src/core/load_balancing/grpclb/load_balancer_api.cc', + 'src/core/load_balancing/health_check_client.cc', + 'src/core/load_balancing/lb_policy.cc', + 'src/core/load_balancing/lb_policy_registry.cc', + 'src/core/load_balancing/oob_backend_metric.cc', + 'src/core/load_balancing/outlier_detection/outlier_detection.cc', + 'src/core/load_balancing/pick_first/pick_first.cc', + 'src/core/load_balancing/priority/priority.cc', + 'src/core/load_balancing/ring_hash/ring_hash.cc', + 'src/core/load_balancing/rls/rls.cc', + 'src/core/load_balancing/round_robin/round_robin.cc', + 'src/core/load_balancing/weighted_round_robin/static_stride_scheduler.cc', + 'src/core/load_balancing/weighted_round_robin/weighted_round_robin.cc', + 'src/core/load_balancing/weighted_target/weighted_target.cc', + 'src/core/load_balancing/xds/cds.cc', + 'src/core/load_balancing/xds/xds_cluster_impl.cc', + 'src/core/load_balancing/xds/xds_cluster_manager.cc', + 'src/core/load_balancing/xds/xds_override_host.cc', + 'src/core/load_balancing/xds/xds_wrr_locality.cc', + 'src/core/plugin_registry/grpc_plugin_registry.cc', + 'src/core/plugin_registry/grpc_plugin_registry_extra.cc', + 'src/core/resolver/binder/binder_resolver.cc', + 'src/core/resolver/dns/c_ares/dns_resolver_ares.cc', + 'src/core/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc', + 'src/core/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc', + 'src/core/resolver/dns/c_ares/grpc_ares_wrapper.cc', + 'src/core/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc', + 'src/core/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc', + 'src/core/resolver/dns/dns_resolver_plugin.cc', + 'src/core/resolver/dns/event_engine/event_engine_client_channel_resolver.cc', + 'src/core/resolver/dns/event_engine/service_config_helper.cc', + 'src/core/resolver/dns/native/dns_resolver.cc', + 'src/core/resolver/endpoint_addresses.cc', + 'src/core/resolver/fake/fake_resolver.cc', + 'src/core/resolver/google_c2p/google_c2p_resolver.cc', + 'src/core/resolver/polling_resolver.cc', + 'src/core/resolver/resolver.cc', + 'src/core/resolver/resolver_registry.cc', + 'src/core/resolver/sockaddr/sockaddr_resolver.cc', + 'src/core/resolver/xds/xds_dependency_manager.cc', + 'src/core/resolver/xds/xds_resolver.cc', + 'src/core/resolver/xds/xds_resolver_trace.cc', + 'src/core/service_config/service_config_channel_arg_filter.cc', + 'src/core/service_config/service_config_impl.cc', + 'src/core/service_config/service_config_parser.cc', + 'src/core/tsi/alts/crypt/aes_gcm.cc', + 'src/core/tsi/alts/crypt/gsec.cc', + 'src/core/tsi/alts/frame_protector/alts_counter.cc', + 'src/core/tsi/alts/frame_protector/alts_crypter.cc', + 'src/core/tsi/alts/frame_protector/alts_frame_protector.cc', + 'src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.cc', + 'src/core/tsi/alts/frame_protector/alts_seal_privacy_integrity_crypter.cc', + 'src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc', + 'src/core/tsi/alts/frame_protector/frame_handler.cc', + 'src/core/tsi/alts/handshaker/alts_handshaker_client.cc', + 'src/core/tsi/alts/handshaker/alts_shared_resource.cc', + 'src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc', + 'src/core/tsi/alts/handshaker/alts_tsi_utils.cc', + 'src/core/tsi/alts/handshaker/transport_security_common_api.cc', + 'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc', + 'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc', + 'src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc', + 'src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc', + 'src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc', + 'src/core/tsi/fake_transport_security.cc', + 'src/core/tsi/local_transport_security.cc', + 'src/core/tsi/ssl/key_logging/ssl_key_logging.cc', + 'src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc', + 'src/core/tsi/ssl/session_cache/ssl_session_cache.cc', + 'src/core/tsi/ssl/session_cache/ssl_session_openssl.cc', + 'src/core/tsi/ssl_transport_security.cc', + 'src/core/tsi/ssl_transport_security_utils.cc', + 'src/core/tsi/transport_security.cc', + 'src/core/tsi/transport_security_grpc.cc', + ], + }, + { + 'target_name': 'grpc_test_util', + 'type': 'static_library', + 'dependencies': [ + 'absl/debugging:failure_signal_handler', + 'absl/debugging:stacktrace', + 'absl/debugging:symbolize', + 'grpc', + ], + 'sources': [ + 'test/core/event_engine/test_init.cc', + 'test/core/util/build.cc', + 'test/core/util/port.cc', + 'test/core/util/port_isolated_runtime_environment.cc', + 'test/core/util/port_server_client.cc', + 'test/core/util/reconnect_server.cc', + 'test/core/util/stack_tracer.cc', + 'test/core/util/test_config.cc', + 'test/core/util/test_tcp_server.cc', + 'test/core/util/tls_utils.cc', + ], + }, + { + 'target_name': 'grpc_test_util_unsecure', + 'type': 'static_library', + 'dependencies': [ + 'absl/debugging:failure_signal_handler', + 'absl/debugging:stacktrace', + 'absl/debugging:symbolize', + 'grpc_unsecure', + ], + 'sources': [ + 'test/core/event_engine/test_init.cc', + 'test/core/util/build.cc', + 'test/core/util/port.cc', + 'test/core/util/port_isolated_runtime_environment.cc', + 'test/core/util/port_server_client.cc', + 'test/core/util/reconnect_server.cc', + 'test/core/util/stack_tracer.cc', + 'test/core/util/test_config.cc', + 'test/core/util/test_tcp_server.cc', + ], + }, + { + 'target_name': 'grpc_unsecure', + 'type': 'static_library', + 'dependencies': [ + 'upb_message_lib', + 'utf8_range_lib', + 'z', + 'absl/algorithm:container', + 'absl/base:config', + 'absl/base:no_destructor', + 'absl/cleanup:cleanup', + 'absl/container:flat_hash_map', + 'absl/container:flat_hash_set', + 'absl/container:inlined_vector', + 'absl/functional:bind_front', + 'absl/functional:function_ref', + 'absl/hash:hash', + 'absl/meta:type_traits', + 'absl/random:bit_gen_ref', + 'absl/random:distributions', + 'absl/status:statusor', + 'absl/types:span', + 'absl/utility:utility', + 'cares', + 'gpr', + 'address_sorting', + ], + 'sources': [ + 'src/core/client_channel/backup_poller.cc', + 'src/core/client_channel/client_channel.cc', + 'src/core/client_channel/client_channel_channelz.cc', + 'src/core/client_channel/client_channel_factory.cc', + 'src/core/client_channel/client_channel_filter.cc', + 'src/core/client_channel/client_channel_plugin.cc', + 'src/core/client_channel/client_channel_service_config.cc', + 'src/core/client_channel/config_selector.cc', + 'src/core/client_channel/dynamic_filters.cc', + 'src/core/client_channel/global_subchannel_pool.cc', + 'src/core/client_channel/http_proxy_mapper.cc', + 'src/core/client_channel/local_subchannel_pool.cc', + 'src/core/client_channel/retry_filter.cc', + 'src/core/client_channel/retry_filter_legacy_call_data.cc', + 'src/core/client_channel/retry_service_config.cc', + 'src/core/client_channel/retry_throttle.cc', + 'src/core/client_channel/subchannel.cc', + 'src/core/client_channel/subchannel_pool_interface.cc', + 'src/core/client_channel/subchannel_stream_client.cc', + 'src/core/ext/filters/backend_metrics/backend_metric_filter.cc', + '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/deadline/deadline_filter.cc', + 'src/core/ext/filters/fault_injection/fault_injection_filter.cc', + 'src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc', + 'src/core/ext/filters/http/client/http_client_filter.cc', + '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', + 'src/core/ext/transport/chttp2/server/chttp2_server.cc', + 'src/core/ext/transport/chttp2/transport/bin_decoder.cc', + 'src/core/ext/transport/chttp2/transport/bin_encoder.cc', + 'src/core/ext/transport/chttp2/transport/chttp2_transport.cc', + 'src/core/ext/transport/chttp2/transport/decode_huff.cc', + 'src/core/ext/transport/chttp2/transport/flow_control.cc', + 'src/core/ext/transport/chttp2/transport/frame.cc', + 'src/core/ext/transport/chttp2/transport/frame_data.cc', + 'src/core/ext/transport/chttp2/transport/frame_goaway.cc', + 'src/core/ext/transport/chttp2/transport/frame_ping.cc', + 'src/core/ext/transport/chttp2/transport/frame_rst_stream.cc', + 'src/core/ext/transport/chttp2/transport/frame_settings.cc', + 'src/core/ext/transport/chttp2/transport/frame_window_update.cc', + 'src/core/ext/transport/chttp2/transport/hpack_encoder.cc', + 'src/core/ext/transport/chttp2/transport/hpack_encoder_table.cc', + 'src/core/ext/transport/chttp2/transport/hpack_parse_result.cc', + 'src/core/ext/transport/chttp2/transport/hpack_parser.cc', + 'src/core/ext/transport/chttp2/transport/hpack_parser_table.cc', + 'src/core/ext/transport/chttp2/transport/http2_settings.cc', + 'src/core/ext/transport/chttp2/transport/http_trace.cc', + 'src/core/ext/transport/chttp2/transport/huffsyms.cc', + 'src/core/ext/transport/chttp2/transport/max_concurrent_streams_policy.cc', + 'src/core/ext/transport/chttp2/transport/parsing.cc', + 'src/core/ext/transport/chttp2/transport/ping_abuse_policy.cc', + 'src/core/ext/transport/chttp2/transport/ping_callbacks.cc', + 'src/core/ext/transport/chttp2/transport/ping_rate_policy.cc', + 'src/core/ext/transport/chttp2/transport/stream_lists.cc', + 'src/core/ext/transport/chttp2/transport/varint.cc', + 'src/core/ext/transport/chttp2/transport/write_size_policy.cc', + 'src/core/ext/transport/chttp2/transport/writing.cc', + 'src/core/ext/transport/inproc/inproc_plugin.cc', + 'src/core/ext/transport/inproc/inproc_transport.cc', + 'src/core/ext/transport/inproc/legacy_inproc_transport.cc', + 'src/core/ext/upb-gen/google/api/annotations.upb_minitable.c', + 'src/core/ext/upb-gen/google/api/http.upb_minitable.c', + 'src/core/ext/upb-gen/google/protobuf/any.upb_minitable.c', + 'src/core/ext/upb-gen/google/protobuf/descriptor.upb_minitable.c', + 'src/core/ext/upb-gen/google/protobuf/duration.upb_minitable.c', + 'src/core/ext/upb-gen/google/protobuf/empty.upb_minitable.c', + 'src/core/ext/upb-gen/google/protobuf/struct.upb_minitable.c', + 'src/core/ext/upb-gen/google/protobuf/timestamp.upb_minitable.c', + 'src/core/ext/upb-gen/google/protobuf/wrappers.upb_minitable.c', + 'src/core/ext/upb-gen/google/rpc/status.upb_minitable.c', + 'src/core/ext/upb-gen/src/proto/grpc/gcp/altscontext.upb_minitable.c', + 'src/core/ext/upb-gen/src/proto/grpc/gcp/handshaker.upb_minitable.c', + 'src/core/ext/upb-gen/src/proto/grpc/gcp/transport_security_common.upb_minitable.c', + 'src/core/ext/upb-gen/src/proto/grpc/health/v1/health.upb_minitable.c', + 'src/core/ext/upb-gen/src/proto/grpc/lb/v1/load_balancer.upb_minitable.c', + 'src/core/ext/upb-gen/src/proto/grpc/lookup/v1/rls.upb_minitable.c', + 'src/core/ext/upb-gen/validate/validate.upb_minitable.c', + 'src/core/ext/upb-gen/xds/data/orca/v3/orca_load_report.upb_minitable.c', + 'src/core/ext/upb-gen/xds/service/orca/v3/orca.upb_minitable.c', + 'src/core/lib/address_utils/parse_address.cc', + 'src/core/lib/address_utils/sockaddr_utils.cc', + 'src/core/lib/backoff/backoff.cc', + 'src/core/lib/backoff/random_early_detection.cc', + 'src/core/lib/channel/call_tracer.cc', + 'src/core/lib/channel/channel_args.cc', + 'src/core/lib/channel/channel_args_preconditioning.cc', + 'src/core/lib/channel/channel_stack.cc', + 'src/core/lib/channel/channel_stack_builder.cc', + 'src/core/lib/channel/channel_stack_builder_impl.cc', + 'src/core/lib/channel/channel_stack_trace.cc', + 'src/core/lib/channel/channel_trace.cc', + 'src/core/lib/channel/channelz.cc', + 'src/core/lib/channel/channelz_registry.cc', + 'src/core/lib/channel/connected_channel.cc', + 'src/core/lib/channel/metrics.cc', + 'src/core/lib/channel/promise_based_filter.cc', + 'src/core/lib/channel/server_call_tracer_filter.cc', + 'src/core/lib/channel/status_util.cc', + 'src/core/lib/compression/compression.cc', + 'src/core/lib/compression/compression_internal.cc', + 'src/core/lib/compression/message_compress.cc', + 'src/core/lib/config/core_configuration.cc', + 'src/core/lib/debug/event_log.cc', + 'src/core/lib/debug/histogram_view.cc', + 'src/core/lib/debug/stats.cc', + 'src/core/lib/debug/stats_data.cc', + 'src/core/lib/debug/trace.cc', + 'src/core/lib/event_engine/ares_resolver.cc', + 'src/core/lib/event_engine/cf_engine/cf_engine.cc', + 'src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc', + 'src/core/lib/event_engine/cf_engine/dns_service_resolver.cc', + 'src/core/lib/event_engine/channel_args_endpoint_config.cc', + 'src/core/lib/event_engine/default_event_engine.cc', + '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/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_posix_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', + 'src/core/lib/event_engine/posix_engine/posix_engine_listener_utils.cc', + 'src/core/lib/event_engine/posix_engine/tcp_socket_utils.cc', + 'src/core/lib/event_engine/posix_engine/timer.cc', + 'src/core/lib/event_engine/posix_engine/timer_heap.cc', + 'src/core/lib/event_engine/posix_engine/timer_manager.cc', + 'src/core/lib/event_engine/posix_engine/traced_buffer_list.cc', + 'src/core/lib/event_engine/posix_engine/wakeup_fd_eventfd.cc', + 'src/core/lib/event_engine/posix_engine/wakeup_fd_pipe.cc', + 'src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.cc', + 'src/core/lib/event_engine/resolved_address.cc', + 'src/core/lib/event_engine/shim.cc', + 'src/core/lib/event_engine/slice.cc', + 'src/core/lib/event_engine/slice_buffer.cc', + 'src/core/lib/event_engine/tcp_socket_utils.cc', + 'src/core/lib/event_engine/thread_pool/thread_count.cc', + 'src/core/lib/event_engine/thread_pool/thread_pool_factory.cc', + 'src/core/lib/event_engine/thread_pool/work_stealing_thread_pool.cc', + 'src/core/lib/event_engine/thready_event_engine/thready_event_engine.cc', + 'src/core/lib/event_engine/time_util.cc', + 'src/core/lib/event_engine/trace.cc', + 'src/core/lib/event_engine/utils.cc', + 'src/core/lib/event_engine/windows/grpc_polled_fd_windows.cc', + 'src/core/lib/event_engine/windows/iocp.cc', + 'src/core/lib/event_engine/windows/native_windows_dns_resolver.cc', + 'src/core/lib/event_engine/windows/win_socket.cc', + 'src/core/lib/event_engine/windows/windows_endpoint.cc', + 'src/core/lib/event_engine/windows/windows_engine.cc', + 'src/core/lib/event_engine/windows/windows_listener.cc', + 'src/core/lib/event_engine/work_queue/basic_work_queue.cc', + 'src/core/lib/experiments/config.cc', + 'src/core/lib/experiments/experiments.cc', + 'src/core/lib/gprpp/load_file.cc', + 'src/core/lib/gprpp/per_cpu.cc', + 'src/core/lib/gprpp/ref_counted_string.cc', + 'src/core/lib/gprpp/status_helper.cc', + 'src/core/lib/gprpp/time.cc', + 'src/core/lib/gprpp/time_averaged_stats.cc', + 'src/core/lib/gprpp/validation_errors.cc', + 'src/core/lib/gprpp/work_serializer.cc', + 'src/core/lib/handshaker/proxy_mapper_registry.cc', + 'src/core/lib/http/format_request.cc', + 'src/core/lib/http/httpcli.cc', + 'src/core/lib/http/parser.cc', + 'src/core/lib/iomgr/buffer_list.cc', + 'src/core/lib/iomgr/call_combiner.cc', + 'src/core/lib/iomgr/cfstream_handle.cc', + 'src/core/lib/iomgr/closure.cc', + 'src/core/lib/iomgr/combiner.cc', + 'src/core/lib/iomgr/dualstack_socket_posix.cc', + 'src/core/lib/iomgr/endpoint.cc', + 'src/core/lib/iomgr/endpoint_cfstream.cc', + 'src/core/lib/iomgr/endpoint_pair_posix.cc', + 'src/core/lib/iomgr/endpoint_pair_windows.cc', + 'src/core/lib/iomgr/error.cc', + 'src/core/lib/iomgr/error_cfstream.cc', + 'src/core/lib/iomgr/ev_apple.cc', + 'src/core/lib/iomgr/ev_epoll1_linux.cc', + 'src/core/lib/iomgr/ev_poll_posix.cc', + 'src/core/lib/iomgr/ev_posix.cc', + 'src/core/lib/iomgr/ev_windows.cc', + 'src/core/lib/iomgr/event_engine_shims/closure.cc', + 'src/core/lib/iomgr/event_engine_shims/endpoint.cc', + 'src/core/lib/iomgr/event_engine_shims/tcp_client.cc', + 'src/core/lib/iomgr/exec_ctx.cc', + 'src/core/lib/iomgr/executor.cc', + 'src/core/lib/iomgr/fork_posix.cc', + 'src/core/lib/iomgr/fork_windows.cc', + 'src/core/lib/iomgr/gethostname_fallback.cc', + 'src/core/lib/iomgr/gethostname_host_name_max.cc', + 'src/core/lib/iomgr/gethostname_sysconf.cc', + 'src/core/lib/iomgr/grpc_if_nametoindex_posix.cc', + 'src/core/lib/iomgr/grpc_if_nametoindex_unsupported.cc', + 'src/core/lib/iomgr/internal_errqueue.cc', + 'src/core/lib/iomgr/iocp_windows.cc', + 'src/core/lib/iomgr/iomgr.cc', + 'src/core/lib/iomgr/iomgr_internal.cc', + 'src/core/lib/iomgr/iomgr_posix.cc', + 'src/core/lib/iomgr/iomgr_posix_cfstream.cc', + 'src/core/lib/iomgr/iomgr_windows.cc', + 'src/core/lib/iomgr/lockfree_event.cc', + 'src/core/lib/iomgr/polling_entity.cc', + 'src/core/lib/iomgr/pollset.cc', + 'src/core/lib/iomgr/pollset_set.cc', + 'src/core/lib/iomgr/pollset_set_windows.cc', + 'src/core/lib/iomgr/pollset_windows.cc', + 'src/core/lib/iomgr/resolve_address.cc', + 'src/core/lib/iomgr/resolve_address_posix.cc', + 'src/core/lib/iomgr/resolve_address_windows.cc', + 'src/core/lib/iomgr/sockaddr_utils_posix.cc', + 'src/core/lib/iomgr/socket_factory_posix.cc', + 'src/core/lib/iomgr/socket_mutator.cc', + 'src/core/lib/iomgr/socket_utils_common_posix.cc', + 'src/core/lib/iomgr/socket_utils_linux.cc', + 'src/core/lib/iomgr/socket_utils_posix.cc', + 'src/core/lib/iomgr/socket_utils_windows.cc', + 'src/core/lib/iomgr/socket_windows.cc', + 'src/core/lib/iomgr/systemd_utils.cc', + 'src/core/lib/iomgr/tcp_client.cc', + 'src/core/lib/iomgr/tcp_client_cfstream.cc', + 'src/core/lib/iomgr/tcp_client_posix.cc', + 'src/core/lib/iomgr/tcp_client_windows.cc', + 'src/core/lib/iomgr/tcp_posix.cc', + 'src/core/lib/iomgr/tcp_server.cc', + 'src/core/lib/iomgr/tcp_server_posix.cc', + 'src/core/lib/iomgr/tcp_server_utils_posix_common.cc', + 'src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc', + 'src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc', + 'src/core/lib/iomgr/tcp_server_windows.cc', + 'src/core/lib/iomgr/tcp_windows.cc', + 'src/core/lib/iomgr/timer.cc', + 'src/core/lib/iomgr/timer_generic.cc', + 'src/core/lib/iomgr/timer_heap.cc', + 'src/core/lib/iomgr/timer_manager.cc', + 'src/core/lib/iomgr/unix_sockets_posix.cc', + 'src/core/lib/iomgr/unix_sockets_posix_noop.cc', + 'src/core/lib/iomgr/vsock.cc', + 'src/core/lib/iomgr/wakeup_fd_eventfd.cc', + 'src/core/lib/iomgr/wakeup_fd_nospecial.cc', + 'src/core/lib/iomgr/wakeup_fd_pipe.cc', + 'src/core/lib/iomgr/wakeup_fd_posix.cc', + 'src/core/lib/json/json_object_loader.cc', + 'src/core/lib/json/json_reader.cc', + 'src/core/lib/json/json_writer.cc', + 'src/core/lib/promise/activity.cc', + 'src/core/lib/promise/party.cc', + 'src/core/lib/promise/sleep.cc', + 'src/core/lib/promise/trace.cc', + 'src/core/lib/resource_quota/api.cc', + 'src/core/lib/resource_quota/arena.cc', + 'src/core/lib/resource_quota/memory_quota.cc', + 'src/core/lib/resource_quota/periodic_update.cc', + 'src/core/lib/resource_quota/resource_quota.cc', + 'src/core/lib/resource_quota/thread_quota.cc', + 'src/core/lib/resource_quota/trace.cc', + 'src/core/lib/security/authorization/authorization_policy_provider_vtable.cc', + 'src/core/lib/security/authorization/evaluate_args.cc', + 'src/core/lib/security/authorization/grpc_server_authz_filter.cc', + 'src/core/lib/security/certificate_provider/certificate_provider_registry.cc', + 'src/core/lib/security/context/security_context.cc', + 'src/core/lib/security/credentials/alts/check_gcp_environment.cc', + 'src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc', + 'src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc', + 'src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc', + 'src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc', + 'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc', + 'src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc', + 'src/core/lib/security/credentials/call_creds_util.cc', + 'src/core/lib/security/credentials/composite/composite_credentials.cc', + 'src/core/lib/security/credentials/credentials.cc', + 'src/core/lib/security/credentials/fake/fake_credentials.cc', + 'src/core/lib/security/credentials/insecure/insecure_credentials.cc', + 'src/core/lib/security/credentials/plugin/plugin_credentials.cc', + 'src/core/lib/security/credentials/tls/tls_utils.cc', + 'src/core/lib/security/security_connector/fake/fake_security_connector.cc', + 'src/core/lib/security/security_connector/insecure/insecure_security_connector.cc', + 'src/core/lib/security/security_connector/load_system_roots_fallback.cc', + 'src/core/lib/security/security_connector/load_system_roots_supported.cc', + 'src/core/lib/security/security_connector/load_system_roots_windows.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', + 'src/core/lib/security/transport/tsi_error.cc', + 'src/core/lib/security/util/json_util.cc', + 'src/core/lib/slice/b64.cc', + 'src/core/lib/slice/percent_encoding.cc', + 'src/core/lib/slice/slice.cc', + 'src/core/lib/slice/slice_buffer.cc', + 'src/core/lib/slice/slice_refcount.cc', + 'src/core/lib/slice/slice_string_helpers.cc', + 'src/core/lib/surface/api_trace.cc', + 'src/core/lib/surface/byte_buffer.cc', + 'src/core/lib/surface/byte_buffer_reader.cc', + 'src/core/lib/surface/call.cc', + 'src/core/lib/surface/call_details.cc', + 'src/core/lib/surface/call_log_batch.cc', + 'src/core/lib/surface/channel.cc', + 'src/core/lib/surface/channel_create.cc', + 'src/core/lib/surface/channel_init.cc', + 'src/core/lib/surface/channel_stack_type.cc', + 'src/core/lib/surface/completion_queue.cc', + 'src/core/lib/surface/completion_queue_factory.cc', + 'src/core/lib/surface/event_string.cc', + 'src/core/lib/surface/init.cc', + 'src/core/lib/surface/init_internally.cc', + 'src/core/lib/surface/lame_client.cc', + 'src/core/lib/surface/legacy_channel.cc', + 'src/core/lib/surface/metadata_array.cc', + 'src/core/lib/surface/server.cc', + 'src/core/lib/surface/validate_metadata.cc', + 'src/core/lib/surface/version.cc', + 'src/core/lib/surface/wait_for_cq_end_op.cc', + 'src/core/lib/transport/batch_builder.cc', + 'src/core/lib/transport/bdp_estimator.cc', + 'src/core/lib/transport/call_filters.cc', + 'src/core/lib/transport/call_final_info.cc', + 'src/core/lib/transport/call_size_estimator.cc', + 'src/core/lib/transport/call_spine.cc', + 'src/core/lib/transport/connectivity_state.cc', + 'src/core/lib/transport/error_utils.cc', + 'src/core/lib/transport/handshaker.cc', + 'src/core/lib/transport/handshaker_registry.cc', + 'src/core/lib/transport/http_connect_handshaker.cc', + 'src/core/lib/transport/message.cc', + 'src/core/lib/transport/metadata.cc', + 'src/core/lib/transport/metadata_batch.cc', + 'src/core/lib/transport/metadata_info.cc', + 'src/core/lib/transport/parsed_metadata.cc', + 'src/core/lib/transport/status_conversion.cc', + 'src/core/lib/transport/tcp_connect_handshaker.cc', + 'src/core/lib/transport/timeout_encoding.cc', + 'src/core/lib/transport/transport.cc', + 'src/core/lib/transport/transport_op_string.cc', + 'src/core/lib/uri/uri_parser.cc', + 'src/core/load_balancing/address_filtering.cc', + 'src/core/load_balancing/backend_metric_parser.cc', + 'src/core/load_balancing/child_policy_handler.cc', + 'src/core/load_balancing/endpoint_list.cc', + 'src/core/load_balancing/grpclb/client_load_reporting_filter.cc', + 'src/core/load_balancing/grpclb/grpclb.cc', + 'src/core/load_balancing/grpclb/grpclb_balancer_addresses.cc', + 'src/core/load_balancing/grpclb/grpclb_client_stats.cc', + 'src/core/load_balancing/grpclb/load_balancer_api.cc', + 'src/core/load_balancing/health_check_client.cc', + 'src/core/load_balancing/lb_policy.cc', + 'src/core/load_balancing/lb_policy_registry.cc', + 'src/core/load_balancing/oob_backend_metric.cc', + 'src/core/load_balancing/outlier_detection/outlier_detection.cc', + 'src/core/load_balancing/pick_first/pick_first.cc', + 'src/core/load_balancing/priority/priority.cc', + 'src/core/load_balancing/rls/rls.cc', + 'src/core/load_balancing/round_robin/round_robin.cc', + 'src/core/load_balancing/weighted_round_robin/static_stride_scheduler.cc', + 'src/core/load_balancing/weighted_round_robin/weighted_round_robin.cc', + 'src/core/load_balancing/weighted_target/weighted_target.cc', + 'src/core/plugin_registry/grpc_plugin_registry.cc', + 'src/core/plugin_registry/grpc_plugin_registry_noextra.cc', + 'src/core/resolver/binder/binder_resolver.cc', + 'src/core/resolver/dns/c_ares/dns_resolver_ares.cc', + 'src/core/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc', + 'src/core/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc', + 'src/core/resolver/dns/c_ares/grpc_ares_wrapper.cc', + 'src/core/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc', + 'src/core/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc', + 'src/core/resolver/dns/dns_resolver_plugin.cc', + 'src/core/resolver/dns/event_engine/event_engine_client_channel_resolver.cc', + 'src/core/resolver/dns/event_engine/service_config_helper.cc', + 'src/core/resolver/dns/native/dns_resolver.cc', + 'src/core/resolver/endpoint_addresses.cc', + 'src/core/resolver/fake/fake_resolver.cc', + 'src/core/resolver/polling_resolver.cc', + 'src/core/resolver/resolver.cc', + 'src/core/resolver/resolver_registry.cc', + 'src/core/resolver/sockaddr/sockaddr_resolver.cc', + 'src/core/service_config/service_config_channel_arg_filter.cc', + 'src/core/service_config/service_config_impl.cc', + 'src/core/service_config/service_config_parser.cc', + 'src/core/tsi/alts/handshaker/transport_security_common_api.cc', + 'src/core/tsi/fake_transport_security.cc', + 'src/core/tsi/local_transport_security.cc', + 'src/core/tsi/transport_security.cc', + 'src/core/tsi/transport_security_grpc.cc', + 'third_party/upb/upb/message/accessors.c', + 'third_party/upb/upb/mini_descriptor/build_enum.c', + 'third_party/upb/upb/mini_descriptor/decode.c', + 'third_party/upb/upb/mini_descriptor/internal/base92.c', + 'third_party/upb/upb/mini_descriptor/internal/encode.c', + 'third_party/upb/upb/mini_descriptor/link.c', + 'third_party/upb/upb/wire/decode.c', + 'third_party/upb/upb/wire/decode_fast.c', + 'third_party/upb/upb/wire/encode.c', + 'third_party/upb/upb/wire/eps_copy_input_stream.c', + 'third_party/upb/upb/wire/reader.c', + ], + }, + { + 'target_name': 'gtest', + 'type': 'static_library', + 'dependencies': [ + 're2', + 'absl/container:flat_hash_set', + 'absl/debugging:failure_signal_handler', + 'absl/debugging:stacktrace', + 'absl/debugging:symbolize', + 'absl/flags:flag', + 'absl/flags:parse', + 'absl/flags:reflection', + 'absl/flags:usage', + 'absl/strings:strings', + 'absl/types:any', + 'absl/types:optional', + 'absl/types:variant', + ], + 'sources': [ + 'third_party/googletest/googlemock/src/gmock-cardinalities.cc', + 'third_party/googletest/googlemock/src/gmock-internal-utils.cc', + 'third_party/googletest/googlemock/src/gmock-matchers.cc', + 'third_party/googletest/googlemock/src/gmock-spec-builders.cc', + 'third_party/googletest/googlemock/src/gmock.cc', + 'third_party/googletest/googletest/src/gtest-assertion-result.cc', + 'third_party/googletest/googletest/src/gtest-death-test.cc', + 'third_party/googletest/googletest/src/gtest-filepath.cc', + 'third_party/googletest/googletest/src/gtest-matchers.cc', + 'third_party/googletest/googletest/src/gtest-port.cc', + 'third_party/googletest/googletest/src/gtest-printers.cc', + 'third_party/googletest/googletest/src/gtest-test-part.cc', + 'third_party/googletest/googletest/src/gtest-typed-test.cc', + 'third_party/googletest/googletest/src/gtest.cc', + ], + }, + { + 'target_name': 're2', + 'type': 'static_library', + 'dependencies': [ + ], + 'sources': [ + 'third_party/re2/re2/bitstate.cc', + 'third_party/re2/re2/compile.cc', + 'third_party/re2/re2/dfa.cc', + 'third_party/re2/re2/filtered_re2.cc', + 'third_party/re2/re2/mimics_pcre.cc', + 'third_party/re2/re2/nfa.cc', + 'third_party/re2/re2/onepass.cc', + 'third_party/re2/re2/parse.cc', + 'third_party/re2/re2/perl_groups.cc', + 'third_party/re2/re2/prefilter.cc', + 'third_party/re2/re2/prefilter_tree.cc', + 'third_party/re2/re2/prog.cc', + 'third_party/re2/re2/re2.cc', + 'third_party/re2/re2/regexp.cc', + 'third_party/re2/re2/set.cc', + 'third_party/re2/re2/simplify.cc', + 'third_party/re2/re2/stringpiece.cc', + 'third_party/re2/re2/tostring.cc', + 'third_party/re2/re2/unicode_casefold.cc', + 'third_party/re2/re2/unicode_groups.cc', + 'third_party/re2/util/rune.cc', + 'third_party/re2/util/strutil.cc', + ], + }, + { + 'target_name': 'upb_base_lib', + 'type': 'static_library', + 'dependencies': [ + ], + 'sources': [ + 'third_party/upb/upb/base/status.c', + ], + }, + { + 'target_name': 'upb_json_lib', + 'type': 'static_library', + 'dependencies': [ + 'upb_message_lib', + 'utf8_range_lib', + ], + 'sources': [ + 'src/core/ext/upb-gen/google/protobuf/descriptor.upb_minitable.c', + 'third_party/upb/upb/json/decode.c', + 'third_party/upb/upb/json/encode.c', + 'third_party/upb/upb/lex/atoi.c', + 'third_party/upb/upb/lex/round_trip.c', + 'third_party/upb/upb/lex/strtod.c', + 'third_party/upb/upb/lex/unicode.c', + 'third_party/upb/upb/message/accessors.c', + 'third_party/upb/upb/mini_descriptor/build_enum.c', + 'third_party/upb/upb/mini_descriptor/decode.c', + 'third_party/upb/upb/mini_descriptor/internal/base92.c', + 'third_party/upb/upb/mini_descriptor/internal/encode.c', + 'third_party/upb/upb/mini_descriptor/link.c', + 'third_party/upb/upb/reflection/def_pool.c', + 'third_party/upb/upb/reflection/def_type.c', + 'third_party/upb/upb/reflection/desc_state.c', + 'third_party/upb/upb/reflection/enum_def.c', + 'third_party/upb/upb/reflection/enum_reserved_range.c', + 'third_party/upb/upb/reflection/enum_value_def.c', + 'third_party/upb/upb/reflection/extension_range.c', + 'third_party/upb/upb/reflection/field_def.c', + 'third_party/upb/upb/reflection/file_def.c', + 'third_party/upb/upb/reflection/internal/def_builder.c', + 'third_party/upb/upb/reflection/internal/strdup2.c', + 'third_party/upb/upb/reflection/message.c', + 'third_party/upb/upb/reflection/message_def.c', + 'third_party/upb/upb/reflection/message_reserved_range.c', + 'third_party/upb/upb/reflection/method_def.c', + 'third_party/upb/upb/reflection/oneof_def.c', + 'third_party/upb/upb/reflection/service_def.c', + 'third_party/upb/upb/wire/decode.c', + 'third_party/upb/upb/wire/decode_fast.c', + 'third_party/upb/upb/wire/encode.c', + 'third_party/upb/upb/wire/eps_copy_input_stream.c', + 'third_party/upb/upb/wire/reader.c', + ], + }, + { + 'target_name': 'upb_mem_lib', + 'type': 'static_library', + 'dependencies': [ + ], + 'sources': [ + 'third_party/upb/upb/mem/alloc.c', + 'third_party/upb/upb/mem/arena.c', + ], + }, + { + 'target_name': 'upb_message_lib', + 'type': 'static_library', + 'dependencies': [ + 'upb_base_lib', + 'upb_mem_lib', + ], + 'sources': [ + 'third_party/upb/upb/hash/common.c', + 'third_party/upb/upb/message/array.c', + 'third_party/upb/upb/message/map.c', + 'third_party/upb/upb/message/map_sorter.c', + 'third_party/upb/upb/message/message.c', + 'third_party/upb/upb/mini_table/extension_registry.c', + 'third_party/upb/upb/mini_table/internal/message.c', + 'third_party/upb/upb/mini_table/message.c', + ], + }, + { + 'target_name': 'upb_textformat_lib', + 'type': 'static_library', + 'dependencies': [ + 'upb_message_lib', + 'utf8_range_lib', + ], + 'sources': [ + 'src/core/ext/upb-gen/google/protobuf/descriptor.upb_minitable.c', + 'third_party/upb/upb/lex/atoi.c', + 'third_party/upb/upb/lex/round_trip.c', + 'third_party/upb/upb/lex/strtod.c', + 'third_party/upb/upb/lex/unicode.c', + 'third_party/upb/upb/message/accessors.c', + 'third_party/upb/upb/mini_descriptor/build_enum.c', + 'third_party/upb/upb/mini_descriptor/decode.c', + 'third_party/upb/upb/mini_descriptor/internal/base92.c', + 'third_party/upb/upb/mini_descriptor/internal/encode.c', + 'third_party/upb/upb/mini_descriptor/link.c', + 'third_party/upb/upb/reflection/def_pool.c', + 'third_party/upb/upb/reflection/def_type.c', + 'third_party/upb/upb/reflection/desc_state.c', + 'third_party/upb/upb/reflection/enum_def.c', + 'third_party/upb/upb/reflection/enum_reserved_range.c', + 'third_party/upb/upb/reflection/enum_value_def.c', + 'third_party/upb/upb/reflection/extension_range.c', + 'third_party/upb/upb/reflection/field_def.c', + 'third_party/upb/upb/reflection/file_def.c', + 'third_party/upb/upb/reflection/internal/def_builder.c', + 'third_party/upb/upb/reflection/internal/strdup2.c', + 'third_party/upb/upb/reflection/message.c', + 'third_party/upb/upb/reflection/message_def.c', + 'third_party/upb/upb/reflection/message_reserved_range.c', + 'third_party/upb/upb/reflection/method_def.c', + 'third_party/upb/upb/reflection/oneof_def.c', + 'third_party/upb/upb/reflection/service_def.c', + 'third_party/upb/upb/text/encode.c', + 'third_party/upb/upb/wire/decode.c', + 'third_party/upb/upb/wire/decode_fast.c', + 'third_party/upb/upb/wire/encode.c', + 'third_party/upb/upb/wire/eps_copy_input_stream.c', + 'third_party/upb/upb/wire/reader.c', + ], + }, + { + 'target_name': 'utf8_range_lib', + 'type': 'static_library', + 'dependencies': [ + ], + 'sources': [ + 'third_party/utf8_range/naive.c', + 'third_party/utf8_range/range2-neon.c', + 'third_party/utf8_range/range2-sse.c', + ], + }, + { + 'target_name': 'z', + 'type': 'static_library', + 'dependencies': [ + ], + 'sources': [ + 'third_party/zlib/adler32.c', + 'third_party/zlib/compress.c', + 'third_party/zlib/crc32.c', + 'third_party/zlib/deflate.c', + 'third_party/zlib/infback.c', + 'third_party/zlib/inffast.c', + 'third_party/zlib/inflate.c', + 'third_party/zlib/inftrees.c', + 'third_party/zlib/trees.c', + 'third_party/zlib/uncompr.c', + 'third_party/zlib/zutil.c', + ], + }, + { + 'target_name': 'benchmark_helpers', + 'type': 'static_library', + 'dependencies': [ + 'benchmark', + 'grpc++_unsecure', + 'grpc_test_util_unsecure', + 'grpc++_test_config', + ], + 'sources': [ + 'src/proto/grpc/testing/echo.proto', + 'src/proto/grpc/testing/echo_messages.proto', + 'src/proto/grpc/testing/simple_messages.proto', + 'src/proto/grpc/testing/xds/v3/orca_load_report.proto', + 'test/core/util/cmdline.cc', + 'test/core/util/fuzzer_util.cc', + 'test/core/util/grpc_profiler.cc', + 'test/core/util/histogram.cc', + 'test/core/util/mock_endpoint.cc', + 'test/core/util/parse_hexstring.cc', + 'test/core/util/resolve_localhost_ip46.cc', + 'test/core/util/slice_splitter.cc', + 'test/core/util/tracer_util.cc', + 'test/cpp/microbenchmarks/helpers.cc', + ], + }, + { + 'target_name': 'grpc++', + 'type': 'static_library', + 'dependencies': [ + 'grpc', + 'protobuf', + ], + 'sources': [ + 'src/core/ext/transport/binder/client/binder_connector.cc', + 'src/core/ext/transport/binder/client/channel_create.cc', + 'src/core/ext/transport/binder/client/channel_create_impl.cc', + 'src/core/ext/transport/binder/client/connection_id_generator.cc', + 'src/core/ext/transport/binder/client/endpoint_binder_pool.cc', + 'src/core/ext/transport/binder/client/jni_utils.cc', + 'src/core/ext/transport/binder/client/security_policy_setting.cc', + 'src/core/ext/transport/binder/security_policy/binder_security_policy.cc', + 'src/core/ext/transport/binder/server/binder_server.cc', + 'src/core/ext/transport/binder/server/binder_server_credentials.cc', + 'src/core/ext/transport/binder/transport/binder_transport.cc', + 'src/core/ext/transport/binder/utils/ndk_binder.cc', + 'src/core/ext/transport/binder/utils/transport_stream_receiver_impl.cc', + 'src/core/ext/transport/binder/wire_format/binder_android.cc', + 'src/core/ext/transport/binder/wire_format/binder_constants.cc', + 'src/core/ext/transport/binder/wire_format/transaction.cc', + 'src/core/ext/transport/binder/wire_format/wire_reader_impl.cc', + 'src/core/ext/transport/binder/wire_format/wire_writer.cc', + 'src/cpp/client/channel_cc.cc', + 'src/cpp/client/client_callback.cc', + 'src/cpp/client/client_context.cc', + 'src/cpp/client/client_interceptor.cc', + 'src/cpp/client/client_stats_interceptor.cc', + 'src/cpp/client/create_channel.cc', + 'src/cpp/client/create_channel_internal.cc', + 'src/cpp/client/create_channel_posix.cc', + 'src/cpp/client/insecure_credentials.cc', + 'src/cpp/client/secure_credentials.cc', + 'src/cpp/client/xds_credentials.cc', + 'src/cpp/common/alarm.cc', + 'src/cpp/common/auth_property_iterator.cc', + 'src/cpp/common/channel_arguments.cc', + 'src/cpp/common/completion_queue_cc.cc', + 'src/cpp/common/resource_quota_cc.cc', + 'src/cpp/common/rpc_method.cc', + 'src/cpp/common/secure_auth_context.cc', + 'src/cpp/common/secure_channel_arguments.cc', + 'src/cpp/common/secure_create_auth_context.cc', + 'src/cpp/common/tls_certificate_provider.cc', + 'src/cpp/common/tls_certificate_verifier.cc', + 'src/cpp/common/tls_credentials_options.cc', + 'src/cpp/common/validate_service_config.cc', + 'src/cpp/common/version_cc.cc', + 'src/cpp/server/async_generic_service.cc', + 'src/cpp/server/backend_metric_recorder.cc', + 'src/cpp/server/channel_argument_option.cc', + 'src/cpp/server/create_default_thread_pool.cc', + 'src/cpp/server/external_connection_acceptor_impl.cc', + 'src/cpp/server/health/default_health_check_service.cc', + 'src/cpp/server/health/health_check_service.cc', + 'src/cpp/server/health/health_check_service_server_builder_option.cc', + 'src/cpp/server/insecure_server_credentials.cc', + 'src/cpp/server/secure_server_credentials.cc', + 'src/cpp/server/server_builder.cc', + 'src/cpp/server/server_callback.cc', + 'src/cpp/server/server_cc.cc', + 'src/cpp/server/server_context.cc', + 'src/cpp/server/server_posix.cc', + 'src/cpp/server/xds_server_builder.cc', + 'src/cpp/server/xds_server_credentials.cc', + 'src/cpp/thread_manager/thread_manager.cc', + 'src/cpp/util/byte_buffer_cc.cc', + 'src/cpp/util/status.cc', + 'src/cpp/util/string_ref.cc', + 'src/cpp/util/time_cc.cc', + ], + }, + { + 'target_name': 'grpc++_alts', + 'type': 'static_library', + 'dependencies': [ + 'grpc++', + ], + 'sources': [ + 'src/cpp/common/alts_context.cc', + 'src/cpp/common/alts_util.cc', + ], + }, + { + 'target_name': 'grpc++_error_details', + 'type': 'static_library', + 'dependencies': [ + 'grpc++', + ], + 'sources': [ + 'src/cpp/util/error_details.cc', + ], + }, + { + 'target_name': 'grpc++_reflection', + 'type': 'static_library', + 'dependencies': [ + 'grpc++', + ], + 'sources': [ + 'src/proto/grpc/reflection/v1/reflection.proto', + 'src/proto/grpc/reflection/v1alpha/reflection.proto', + 'src/cpp/ext/proto_server_reflection.cc', + 'src/cpp/ext/proto_server_reflection_plugin.cc', + ], + }, + { + 'target_name': 'grpc++_test', + 'type': 'static_library', + 'dependencies': [ + 'gtest', + 'grpc++', + ], + 'sources': [ + 'src/cpp/client/channel_test_peer.cc', + ], + }, + { + 'target_name': 'grpc++_test_config', + 'type': 'static_library', + 'dependencies': [ + 'absl/flags:parse', + 'gpr', + ], + 'sources': [ + 'test/cpp/util/test_config_cc.cc', + ], + }, + { + 'target_name': 'grpc++_test_util', + 'type': 'static_library', + 'dependencies': [ + 'grpc++', + 'grpc_test_util', + ], + 'sources': [ + 'src/core/lib/gpr/subprocess_posix.cc', + 'src/core/lib/gpr/subprocess_windows.cc', + 'test/core/end2end/data/client_certs.cc', + 'test/core/end2end/data/server1_cert.cc', + 'test/core/end2end/data/server1_key.cc', + 'test/core/end2end/data/test_root_cert.cc', + 'test/core/util/cmdline.cc', + 'test/core/util/fuzzer_util.cc', + 'test/core/util/grpc_profiler.cc', + 'test/core/util/histogram.cc', + 'test/core/util/mock_endpoint.cc', + 'test/core/util/parse_hexstring.cc', + 'test/core/util/resolve_localhost_ip46.cc', + 'test/core/util/slice_splitter.cc', + 'test/core/util/tracer_util.cc', + 'test/cpp/util/byte_buffer_proto_helper.cc', + 'test/cpp/util/create_test_channel.cc', + 'test/cpp/util/string_ref_helper.cc', + 'test/cpp/util/subprocess.cc', + 'test/cpp/util/test_credentials_provider.cc', + ], + }, + { + 'target_name': 'grpc++_unsecure', + 'type': 'static_library', + 'dependencies': [ + 'grpc_unsecure', + 'protobuf', + ], + 'sources': [ + 'src/cpp/client/channel_cc.cc', + 'src/cpp/client/client_callback.cc', + 'src/cpp/client/client_context.cc', + 'src/cpp/client/client_interceptor.cc', + 'src/cpp/client/client_stats_interceptor.cc', + 'src/cpp/client/create_channel.cc', + 'src/cpp/client/create_channel_internal.cc', + 'src/cpp/client/create_channel_posix.cc', + 'src/cpp/client/insecure_credentials.cc', + 'src/cpp/common/alarm.cc', + 'src/cpp/common/channel_arguments.cc', + 'src/cpp/common/completion_queue_cc.cc', + 'src/cpp/common/insecure_create_auth_context.cc', + 'src/cpp/common/resource_quota_cc.cc', + 'src/cpp/common/rpc_method.cc', + 'src/cpp/common/validate_service_config.cc', + 'src/cpp/common/version_cc.cc', + 'src/cpp/server/async_generic_service.cc', + 'src/cpp/server/backend_metric_recorder.cc', + 'src/cpp/server/channel_argument_option.cc', + 'src/cpp/server/create_default_thread_pool.cc', + 'src/cpp/server/external_connection_acceptor_impl.cc', + 'src/cpp/server/health/default_health_check_service.cc', + 'src/cpp/server/health/health_check_service.cc', + 'src/cpp/server/health/health_check_service_server_builder_option.cc', + 'src/cpp/server/insecure_server_credentials.cc', + 'src/cpp/server/server_builder.cc', + 'src/cpp/server/server_callback.cc', + 'src/cpp/server/server_cc.cc', + 'src/cpp/server/server_context.cc', + 'src/cpp/server/server_posix.cc', + 'src/cpp/thread_manager/thread_manager.cc', + 'src/cpp/util/byte_buffer_cc.cc', + 'src/cpp/util/status.cc', + 'src/cpp/util/string_ref.cc', + 'src/cpp/util/time_cc.cc', + ], + }, + { + 'target_name': 'grpc_authorization_provider', + 'type': 'static_library', + 'dependencies': [ + 'upb_message_lib', + 're2', + 'utf8_range_lib', + 'z', + 'absl/base:config', + 'absl/base:no_destructor', + 'absl/cleanup:cleanup', + 'absl/container:flat_hash_map', + 'absl/container:flat_hash_set', + 'absl/container:inlined_vector', + 'absl/functional:function_ref', + 'absl/hash:hash', + 'absl/meta:type_traits', + 'absl/random:bit_gen_ref', + 'absl/random:distributions', + 'absl/status:statusor', + 'absl/types:span', + 'absl/utility:utility', + 'cares', + 'gpr', + 'address_sorting', + ], + 'sources': [ + 'src/core/ext/upb-gen/google/protobuf/any.upb_minitable.c', + 'src/core/ext/upb-gen/google/protobuf/descriptor.upb_minitable.c', + 'src/core/ext/upb-gen/google/rpc/status.upb_minitable.c', + 'src/core/ext/upb-gen/src/proto/grpc/gcp/altscontext.upb_minitable.c', + 'src/core/ext/upb-gen/src/proto/grpc/gcp/handshaker.upb_minitable.c', + 'src/core/ext/upb-gen/src/proto/grpc/gcp/transport_security_common.upb_minitable.c', + 'src/core/lib/address_utils/parse_address.cc', + 'src/core/lib/address_utils/sockaddr_utils.cc', + 'src/core/lib/backoff/backoff.cc', + 'src/core/lib/backoff/random_early_detection.cc', + 'src/core/lib/channel/call_tracer.cc', + 'src/core/lib/channel/channel_args.cc', + 'src/core/lib/channel/channel_args_preconditioning.cc', + 'src/core/lib/channel/channel_stack.cc', + 'src/core/lib/channel/channel_stack_builder.cc', + 'src/core/lib/channel/channel_stack_builder_impl.cc', + 'src/core/lib/channel/channel_stack_trace.cc', + 'src/core/lib/channel/channel_trace.cc', + 'src/core/lib/channel/channelz.cc', + 'src/core/lib/channel/channelz_registry.cc', + 'src/core/lib/channel/connected_channel.cc', + 'src/core/lib/channel/metrics.cc', + 'src/core/lib/channel/promise_based_filter.cc', + 'src/core/lib/channel/status_util.cc', + 'src/core/lib/compression/compression.cc', + 'src/core/lib/compression/compression_internal.cc', + 'src/core/lib/compression/message_compress.cc', + 'src/core/lib/config/core_configuration.cc', + 'src/core/lib/debug/event_log.cc', + 'src/core/lib/debug/histogram_view.cc', + 'src/core/lib/debug/stats.cc', + 'src/core/lib/debug/stats_data.cc', + 'src/core/lib/debug/trace.cc', + 'src/core/lib/event_engine/ares_resolver.cc', + 'src/core/lib/event_engine/cf_engine/cf_engine.cc', + 'src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc', + 'src/core/lib/event_engine/cf_engine/dns_service_resolver.cc', + 'src/core/lib/event_engine/channel_args_endpoint_config.cc', + 'src/core/lib/event_engine/default_event_engine.cc', + '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/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_posix_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', + 'src/core/lib/event_engine/posix_engine/posix_engine_listener_utils.cc', + 'src/core/lib/event_engine/posix_engine/tcp_socket_utils.cc', + 'src/core/lib/event_engine/posix_engine/timer.cc', + 'src/core/lib/event_engine/posix_engine/timer_heap.cc', + 'src/core/lib/event_engine/posix_engine/timer_manager.cc', + 'src/core/lib/event_engine/posix_engine/traced_buffer_list.cc', + 'src/core/lib/event_engine/posix_engine/wakeup_fd_eventfd.cc', + 'src/core/lib/event_engine/posix_engine/wakeup_fd_pipe.cc', + 'src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.cc', + 'src/core/lib/event_engine/resolved_address.cc', + 'src/core/lib/event_engine/shim.cc', + 'src/core/lib/event_engine/slice.cc', + 'src/core/lib/event_engine/slice_buffer.cc', + 'src/core/lib/event_engine/tcp_socket_utils.cc', + 'src/core/lib/event_engine/thread_pool/thread_count.cc', + 'src/core/lib/event_engine/thread_pool/thread_pool_factory.cc', + 'src/core/lib/event_engine/thread_pool/work_stealing_thread_pool.cc', + 'src/core/lib/event_engine/thready_event_engine/thready_event_engine.cc', + 'src/core/lib/event_engine/time_util.cc', + 'src/core/lib/event_engine/trace.cc', + 'src/core/lib/event_engine/utils.cc', + 'src/core/lib/event_engine/windows/grpc_polled_fd_windows.cc', + 'src/core/lib/event_engine/windows/iocp.cc', + 'src/core/lib/event_engine/windows/native_windows_dns_resolver.cc', + 'src/core/lib/event_engine/windows/win_socket.cc', + 'src/core/lib/event_engine/windows/windows_endpoint.cc', + 'src/core/lib/event_engine/windows/windows_engine.cc', + 'src/core/lib/event_engine/windows/windows_listener.cc', + 'src/core/lib/event_engine/work_queue/basic_work_queue.cc', + 'src/core/lib/experiments/config.cc', + 'src/core/lib/experiments/experiments.cc', + 'src/core/lib/gprpp/load_file.cc', + 'src/core/lib/gprpp/per_cpu.cc', + 'src/core/lib/gprpp/ref_counted_string.cc', + 'src/core/lib/gprpp/status_helper.cc', + 'src/core/lib/gprpp/time.cc', + 'src/core/lib/gprpp/time_averaged_stats.cc', + 'src/core/lib/gprpp/validation_errors.cc', + 'src/core/lib/gprpp/work_serializer.cc', + 'src/core/lib/handshaker/proxy_mapper_registry.cc', + 'src/core/lib/iomgr/buffer_list.cc', + 'src/core/lib/iomgr/call_combiner.cc', + 'src/core/lib/iomgr/cfstream_handle.cc', + 'src/core/lib/iomgr/closure.cc', + 'src/core/lib/iomgr/combiner.cc', + 'src/core/lib/iomgr/dualstack_socket_posix.cc', + 'src/core/lib/iomgr/endpoint.cc', + 'src/core/lib/iomgr/endpoint_cfstream.cc', + 'src/core/lib/iomgr/endpoint_pair_posix.cc', + 'src/core/lib/iomgr/endpoint_pair_windows.cc', + 'src/core/lib/iomgr/error.cc', + 'src/core/lib/iomgr/error_cfstream.cc', + 'src/core/lib/iomgr/ev_apple.cc', + 'src/core/lib/iomgr/ev_epoll1_linux.cc', + 'src/core/lib/iomgr/ev_poll_posix.cc', + 'src/core/lib/iomgr/ev_posix.cc', + 'src/core/lib/iomgr/ev_windows.cc', + 'src/core/lib/iomgr/event_engine_shims/closure.cc', + 'src/core/lib/iomgr/event_engine_shims/endpoint.cc', + 'src/core/lib/iomgr/event_engine_shims/tcp_client.cc', + 'src/core/lib/iomgr/exec_ctx.cc', + 'src/core/lib/iomgr/executor.cc', + 'src/core/lib/iomgr/fork_posix.cc', + 'src/core/lib/iomgr/fork_windows.cc', + 'src/core/lib/iomgr/gethostname_fallback.cc', + 'src/core/lib/iomgr/gethostname_host_name_max.cc', + 'src/core/lib/iomgr/gethostname_sysconf.cc', + 'src/core/lib/iomgr/grpc_if_nametoindex_posix.cc', + 'src/core/lib/iomgr/grpc_if_nametoindex_unsupported.cc', + 'src/core/lib/iomgr/internal_errqueue.cc', + 'src/core/lib/iomgr/iocp_windows.cc', + 'src/core/lib/iomgr/iomgr.cc', + 'src/core/lib/iomgr/iomgr_internal.cc', + 'src/core/lib/iomgr/iomgr_posix.cc', + 'src/core/lib/iomgr/iomgr_posix_cfstream.cc', + 'src/core/lib/iomgr/iomgr_windows.cc', + 'src/core/lib/iomgr/lockfree_event.cc', + 'src/core/lib/iomgr/polling_entity.cc', + 'src/core/lib/iomgr/pollset.cc', + 'src/core/lib/iomgr/pollset_set.cc', + 'src/core/lib/iomgr/pollset_set_windows.cc', + 'src/core/lib/iomgr/pollset_windows.cc', + 'src/core/lib/iomgr/resolve_address.cc', + 'src/core/lib/iomgr/resolve_address_posix.cc', + 'src/core/lib/iomgr/resolve_address_windows.cc', + 'src/core/lib/iomgr/sockaddr_utils_posix.cc', + 'src/core/lib/iomgr/socket_factory_posix.cc', + 'src/core/lib/iomgr/socket_mutator.cc', + 'src/core/lib/iomgr/socket_utils_common_posix.cc', + 'src/core/lib/iomgr/socket_utils_linux.cc', + 'src/core/lib/iomgr/socket_utils_posix.cc', + 'src/core/lib/iomgr/socket_utils_windows.cc', + 'src/core/lib/iomgr/socket_windows.cc', + 'src/core/lib/iomgr/systemd_utils.cc', + 'src/core/lib/iomgr/tcp_client.cc', + 'src/core/lib/iomgr/tcp_client_cfstream.cc', + 'src/core/lib/iomgr/tcp_client_posix.cc', + 'src/core/lib/iomgr/tcp_client_windows.cc', + 'src/core/lib/iomgr/tcp_posix.cc', + 'src/core/lib/iomgr/tcp_server.cc', + 'src/core/lib/iomgr/tcp_server_posix.cc', + 'src/core/lib/iomgr/tcp_server_utils_posix_common.cc', + 'src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc', + 'src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc', + 'src/core/lib/iomgr/tcp_server_windows.cc', + 'src/core/lib/iomgr/tcp_windows.cc', + 'src/core/lib/iomgr/timer.cc', + 'src/core/lib/iomgr/timer_generic.cc', + 'src/core/lib/iomgr/timer_heap.cc', + 'src/core/lib/iomgr/timer_manager.cc', + 'src/core/lib/iomgr/unix_sockets_posix.cc', + 'src/core/lib/iomgr/unix_sockets_posix_noop.cc', + 'src/core/lib/iomgr/vsock.cc', + 'src/core/lib/iomgr/wakeup_fd_eventfd.cc', + 'src/core/lib/iomgr/wakeup_fd_nospecial.cc', + 'src/core/lib/iomgr/wakeup_fd_pipe.cc', + 'src/core/lib/iomgr/wakeup_fd_posix.cc', + 'src/core/lib/json/json_reader.cc', + 'src/core/lib/json/json_writer.cc', + 'src/core/lib/matchers/matchers.cc', + 'src/core/lib/promise/activity.cc', + 'src/core/lib/promise/party.cc', + 'src/core/lib/promise/trace.cc', + 'src/core/lib/resource_quota/api.cc', + 'src/core/lib/resource_quota/arena.cc', + 'src/core/lib/resource_quota/memory_quota.cc', + 'src/core/lib/resource_quota/periodic_update.cc', + 'src/core/lib/resource_quota/resource_quota.cc', + 'src/core/lib/resource_quota/thread_quota.cc', + 'src/core/lib/resource_quota/trace.cc', + 'src/core/lib/security/authorization/audit_logging.cc', + 'src/core/lib/security/authorization/authorization_policy_provider_vtable.cc', + 'src/core/lib/security/authorization/evaluate_args.cc', + 'src/core/lib/security/authorization/grpc_authorization_engine.cc', + 'src/core/lib/security/authorization/grpc_authorization_policy_provider.cc', + 'src/core/lib/security/authorization/grpc_server_authz_filter.cc', + 'src/core/lib/security/authorization/matchers.cc', + 'src/core/lib/security/authorization/rbac_policy.cc', + 'src/core/lib/security/authorization/rbac_translator.cc', + 'src/core/lib/security/authorization/stdout_logger.cc', + 'src/core/lib/security/certificate_provider/certificate_provider_registry.cc', + 'src/core/lib/security/context/security_context.cc', + 'src/core/lib/security/credentials/alts/check_gcp_environment.cc', + 'src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc', + 'src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc', + 'src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc', + 'src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc', + 'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc', + 'src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc', + 'src/core/lib/security/credentials/call_creds_util.cc', + 'src/core/lib/security/credentials/composite/composite_credentials.cc', + 'src/core/lib/security/credentials/credentials.cc', + 'src/core/lib/security/credentials/plugin/plugin_credentials.cc', + 'src/core/lib/security/credentials/tls/tls_utils.cc', + 'src/core/lib/security/security_connector/load_system_roots_fallback.cc', + 'src/core/lib/security/security_connector/load_system_roots_supported.cc', + 'src/core/lib/security/security_connector/load_system_roots_windows.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', + 'src/core/lib/security/transport/tsi_error.cc', + 'src/core/lib/security/util/json_util.cc', + 'src/core/lib/slice/b64.cc', + 'src/core/lib/slice/percent_encoding.cc', + 'src/core/lib/slice/slice.cc', + 'src/core/lib/slice/slice_buffer.cc', + 'src/core/lib/slice/slice_refcount.cc', + 'src/core/lib/slice/slice_string_helpers.cc', + 'src/core/lib/surface/api_trace.cc', + 'src/core/lib/surface/byte_buffer.cc', + 'src/core/lib/surface/byte_buffer_reader.cc', + 'src/core/lib/surface/call.cc', + 'src/core/lib/surface/call_details.cc', + 'src/core/lib/surface/call_log_batch.cc', + 'src/core/lib/surface/channel.cc', + 'src/core/lib/surface/channel_init.cc', + 'src/core/lib/surface/channel_stack_type.cc', + 'src/core/lib/surface/completion_queue.cc', + 'src/core/lib/surface/completion_queue_factory.cc', + 'src/core/lib/surface/event_string.cc', + 'src/core/lib/surface/init_internally.cc', + 'src/core/lib/surface/lame_client.cc', + 'src/core/lib/surface/metadata_array.cc', + 'src/core/lib/surface/validate_metadata.cc', + 'src/core/lib/surface/version.cc', + 'src/core/lib/surface/wait_for_cq_end_op.cc', + 'src/core/lib/transport/batch_builder.cc', + 'src/core/lib/transport/call_filters.cc', + 'src/core/lib/transport/call_final_info.cc', + 'src/core/lib/transport/call_size_estimator.cc', + 'src/core/lib/transport/call_spine.cc', + 'src/core/lib/transport/connectivity_state.cc', + 'src/core/lib/transport/error_utils.cc', + 'src/core/lib/transport/handshaker.cc', + 'src/core/lib/transport/handshaker_registry.cc', + 'src/core/lib/transport/message.cc', + 'src/core/lib/transport/metadata.cc', + 'src/core/lib/transport/metadata_batch.cc', + 'src/core/lib/transport/parsed_metadata.cc', + 'src/core/lib/transport/status_conversion.cc', + 'src/core/lib/transport/timeout_encoding.cc', + 'src/core/lib/transport/transport.cc', + 'src/core/lib/transport/transport_op_string.cc', + 'src/core/lib/uri/uri_parser.cc', + 'src/core/load_balancing/lb_policy.cc', + 'src/core/load_balancing/lb_policy_registry.cc', + 'src/core/resolver/endpoint_addresses.cc', + 'src/core/resolver/resolver.cc', + 'src/core/resolver/resolver_registry.cc', + 'src/core/service_config/service_config_parser.cc', + 'src/core/tsi/alts/handshaker/transport_security_common_api.cc', + 'src/core/tsi/transport_security.cc', + 'src/core/tsi/transport_security_grpc.cc', + 'third_party/upb/upb/message/accessors.c', + 'third_party/upb/upb/mini_descriptor/build_enum.c', + 'third_party/upb/upb/mini_descriptor/decode.c', + 'third_party/upb/upb/mini_descriptor/internal/base92.c', + 'third_party/upb/upb/mini_descriptor/internal/encode.c', + 'third_party/upb/upb/mini_descriptor/link.c', + 'third_party/upb/upb/wire/decode.c', + 'third_party/upb/upb/wire/decode_fast.c', + 'third_party/upb/upb/wire/encode.c', + 'third_party/upb/upb/wire/eps_copy_input_stream.c', + 'third_party/upb/upb/wire/reader.c', + ], + }, + { + 'target_name': 'grpc_plugin_support', + 'type': 'static_library', + 'dependencies': [ + 'protobuf', + 'protoc', + ], + 'sources': [ + 'src/compiler/cpp_generator.cc', + 'src/compiler/csharp_generator.cc', + 'src/compiler/node_generator.cc', + 'src/compiler/objective_c_generator.cc', + 'src/compiler/php_generator.cc', + 'src/compiler/proto_parser_helper.cc', + 'src/compiler/python_generator.cc', + 'src/compiler/ruby_generator.cc', + ], + }, + { + 'target_name': 'grpcpp_channelz', + 'type': 'static_library', + 'dependencies': [ + 'grpc++', + ], + 'sources': [ + 'src/proto/grpc/channelz/channelz.proto', + 'src/cpp/server/channelz/channelz_service.cc', + 'src/cpp/server/channelz/channelz_service_plugin.cc', + ], + }, + { + 'target_name': 'boringssl', + 'type': 'static_library', + 'dependencies': [ + ], + 'sources': [ + 'third_party/boringssl-with-bazel/err_data.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/a_bitstr.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/a_bool.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/a_d2i_fp.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/a_dup.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/a_gentm.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/a_i2d_fp.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/a_int.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/a_mbstr.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/a_object.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/a_octet.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/a_strex.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/a_strnid.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/a_time.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/a_type.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/a_utctm.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/asn1_lib.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/asn1_par.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/asn_pack.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/f_int.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/f_string.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/posix_time.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/tasn_dec.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/tasn_enc.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/tasn_fre.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/tasn_new.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/tasn_typ.c', + 'third_party/boringssl-with-bazel/src/crypto/asn1/tasn_utl.c', + 'third_party/boringssl-with-bazel/src/crypto/base64/base64.c', + 'third_party/boringssl-with-bazel/src/crypto/bio/bio.c', + 'third_party/boringssl-with-bazel/src/crypto/bio/bio_mem.c', + 'third_party/boringssl-with-bazel/src/crypto/bio/connect.c', + 'third_party/boringssl-with-bazel/src/crypto/bio/errno.c', + 'third_party/boringssl-with-bazel/src/crypto/bio/fd.c', + 'third_party/boringssl-with-bazel/src/crypto/bio/file.c', + 'third_party/boringssl-with-bazel/src/crypto/bio/hexdump.c', + 'third_party/boringssl-with-bazel/src/crypto/bio/pair.c', + 'third_party/boringssl-with-bazel/src/crypto/bio/printf.c', + 'third_party/boringssl-with-bazel/src/crypto/bio/socket.c', + 'third_party/boringssl-with-bazel/src/crypto/bio/socket_helper.c', + 'third_party/boringssl-with-bazel/src/crypto/blake2/blake2.c', + 'third_party/boringssl-with-bazel/src/crypto/bn_extra/bn_asn1.c', + 'third_party/boringssl-with-bazel/src/crypto/bn_extra/convert.c', + 'third_party/boringssl-with-bazel/src/crypto/buf/buf.c', + 'third_party/boringssl-with-bazel/src/crypto/bytestring/asn1_compat.c', + 'third_party/boringssl-with-bazel/src/crypto/bytestring/ber.c', + 'third_party/boringssl-with-bazel/src/crypto/bytestring/cbb.c', + 'third_party/boringssl-with-bazel/src/crypto/bytestring/cbs.c', + 'third_party/boringssl-with-bazel/src/crypto/bytestring/unicode.c', + 'third_party/boringssl-with-bazel/src/crypto/chacha/chacha.c', + 'third_party/boringssl-with-bazel/src/crypto/cipher_extra/cipher_extra.c', + 'third_party/boringssl-with-bazel/src/crypto/cipher_extra/derive_key.c', + 'third_party/boringssl-with-bazel/src/crypto/cipher_extra/e_aesctrhmac.c', + 'third_party/boringssl-with-bazel/src/crypto/cipher_extra/e_aesgcmsiv.c', + 'third_party/boringssl-with-bazel/src/crypto/cipher_extra/e_chacha20poly1305.c', + 'third_party/boringssl-with-bazel/src/crypto/cipher_extra/e_des.c', + 'third_party/boringssl-with-bazel/src/crypto/cipher_extra/e_null.c', + 'third_party/boringssl-with-bazel/src/crypto/cipher_extra/e_rc2.c', + 'third_party/boringssl-with-bazel/src/crypto/cipher_extra/e_rc4.c', + 'third_party/boringssl-with-bazel/src/crypto/cipher_extra/e_tls.c', + 'third_party/boringssl-with-bazel/src/crypto/cipher_extra/tls_cbc.c', + 'third_party/boringssl-with-bazel/src/crypto/conf/conf.c', + 'third_party/boringssl-with-bazel/src/crypto/cpu_aarch64_apple.c', + 'third_party/boringssl-with-bazel/src/crypto/cpu_aarch64_fuchsia.c', + 'third_party/boringssl-with-bazel/src/crypto/cpu_aarch64_linux.c', + 'third_party/boringssl-with-bazel/src/crypto/cpu_aarch64_openbsd.c', + 'third_party/boringssl-with-bazel/src/crypto/cpu_aarch64_sysreg.c', + 'third_party/boringssl-with-bazel/src/crypto/cpu_aarch64_win.c', + 'third_party/boringssl-with-bazel/src/crypto/cpu_arm_freebsd.c', + 'third_party/boringssl-with-bazel/src/crypto/cpu_arm_linux.c', + 'third_party/boringssl-with-bazel/src/crypto/cpu_intel.c', + 'third_party/boringssl-with-bazel/src/crypto/crypto.c', + 'third_party/boringssl-with-bazel/src/crypto/curve25519/curve25519.c', + 'third_party/boringssl-with-bazel/src/crypto/curve25519/curve25519_64_adx.c', + 'third_party/boringssl-with-bazel/src/crypto/curve25519/spake25519.c', + 'third_party/boringssl-with-bazel/src/crypto/des/des.c', + 'third_party/boringssl-with-bazel/src/crypto/dh_extra/dh_asn1.c', + 'third_party/boringssl-with-bazel/src/crypto/dh_extra/params.c', + 'third_party/boringssl-with-bazel/src/crypto/digest_extra/digest_extra.c', + 'third_party/boringssl-with-bazel/src/crypto/dsa/dsa.c', + 'third_party/boringssl-with-bazel/src/crypto/dsa/dsa_asn1.c', + 'third_party/boringssl-with-bazel/src/crypto/ec_extra/ec_asn1.c', + 'third_party/boringssl-with-bazel/src/crypto/ec_extra/ec_derive.c', + 'third_party/boringssl-with-bazel/src/crypto/ec_extra/hash_to_curve.c', + 'third_party/boringssl-with-bazel/src/crypto/ecdh_extra/ecdh_extra.c', + 'third_party/boringssl-with-bazel/src/crypto/ecdsa_extra/ecdsa_asn1.c', + 'third_party/boringssl-with-bazel/src/crypto/engine/engine.c', + 'third_party/boringssl-with-bazel/src/crypto/err/err.c', + 'third_party/boringssl-with-bazel/src/crypto/evp/evp.c', + 'third_party/boringssl-with-bazel/src/crypto/evp/evp_asn1.c', + 'third_party/boringssl-with-bazel/src/crypto/evp/evp_ctx.c', + 'third_party/boringssl-with-bazel/src/crypto/evp/p_dsa_asn1.c', + 'third_party/boringssl-with-bazel/src/crypto/evp/p_ec.c', + 'third_party/boringssl-with-bazel/src/crypto/evp/p_ec_asn1.c', + 'third_party/boringssl-with-bazel/src/crypto/evp/p_ed25519.c', + 'third_party/boringssl-with-bazel/src/crypto/evp/p_ed25519_asn1.c', + 'third_party/boringssl-with-bazel/src/crypto/evp/p_hkdf.c', + 'third_party/boringssl-with-bazel/src/crypto/evp/p_rsa.c', + 'third_party/boringssl-with-bazel/src/crypto/evp/p_rsa_asn1.c', + 'third_party/boringssl-with-bazel/src/crypto/evp/p_x25519.c', + 'third_party/boringssl-with-bazel/src/crypto/evp/p_x25519_asn1.c', + 'third_party/boringssl-with-bazel/src/crypto/evp/pbkdf.c', + 'third_party/boringssl-with-bazel/src/crypto/evp/print.c', + 'third_party/boringssl-with-bazel/src/crypto/evp/scrypt.c', + 'third_party/boringssl-with-bazel/src/crypto/evp/sign.c', + 'third_party/boringssl-with-bazel/src/crypto/ex_data.c', + 'third_party/boringssl-with-bazel/src/crypto/fipsmodule/bcm.c', + 'third_party/boringssl-with-bazel/src/crypto/fipsmodule/fips_shared_support.c', + 'third_party/boringssl-with-bazel/src/crypto/hpke/hpke.c', + 'third_party/boringssl-with-bazel/src/crypto/hrss/hrss.c', + 'third_party/boringssl-with-bazel/src/crypto/keccak/keccak.c', + 'third_party/boringssl-with-bazel/src/crypto/kyber/kyber.c', + 'third_party/boringssl-with-bazel/src/crypto/lhash/lhash.c', + 'third_party/boringssl-with-bazel/src/crypto/mem.c', + 'third_party/boringssl-with-bazel/src/crypto/obj/obj.c', + 'third_party/boringssl-with-bazel/src/crypto/obj/obj_xref.c', + 'third_party/boringssl-with-bazel/src/crypto/pem/pem_all.c', + 'third_party/boringssl-with-bazel/src/crypto/pem/pem_info.c', + 'third_party/boringssl-with-bazel/src/crypto/pem/pem_lib.c', + 'third_party/boringssl-with-bazel/src/crypto/pem/pem_oth.c', + 'third_party/boringssl-with-bazel/src/crypto/pem/pem_pk8.c', + 'third_party/boringssl-with-bazel/src/crypto/pem/pem_pkey.c', + 'third_party/boringssl-with-bazel/src/crypto/pem/pem_x509.c', + 'third_party/boringssl-with-bazel/src/crypto/pem/pem_xaux.c', + 'third_party/boringssl-with-bazel/src/crypto/pkcs7/pkcs7.c', + 'third_party/boringssl-with-bazel/src/crypto/pkcs7/pkcs7_x509.c', + 'third_party/boringssl-with-bazel/src/crypto/pkcs8/p5_pbev2.c', + 'third_party/boringssl-with-bazel/src/crypto/pkcs8/pkcs8.c', + 'third_party/boringssl-with-bazel/src/crypto/pkcs8/pkcs8_x509.c', + 'third_party/boringssl-with-bazel/src/crypto/poly1305/poly1305.c', + 'third_party/boringssl-with-bazel/src/crypto/poly1305/poly1305_arm.c', + 'third_party/boringssl-with-bazel/src/crypto/poly1305/poly1305_vec.c', + 'third_party/boringssl-with-bazel/src/crypto/pool/pool.c', + 'third_party/boringssl-with-bazel/src/crypto/rand_extra/deterministic.c', + 'third_party/boringssl-with-bazel/src/crypto/rand_extra/forkunsafe.c', + 'third_party/boringssl-with-bazel/src/crypto/rand_extra/getentropy.c', + 'third_party/boringssl-with-bazel/src/crypto/rand_extra/ios.c', + 'third_party/boringssl-with-bazel/src/crypto/rand_extra/passive.c', + 'third_party/boringssl-with-bazel/src/crypto/rand_extra/rand_extra.c', + 'third_party/boringssl-with-bazel/src/crypto/rand_extra/trusty.c', + 'third_party/boringssl-with-bazel/src/crypto/rand_extra/windows.c', + 'third_party/boringssl-with-bazel/src/crypto/rc4/rc4.c', + 'third_party/boringssl-with-bazel/src/crypto/refcount.c', + 'third_party/boringssl-with-bazel/src/crypto/rsa_extra/rsa_asn1.c', + 'third_party/boringssl-with-bazel/src/crypto/rsa_extra/rsa_crypt.c', + 'third_party/boringssl-with-bazel/src/crypto/rsa_extra/rsa_print.c', + 'third_party/boringssl-with-bazel/src/crypto/siphash/siphash.c', + 'third_party/boringssl-with-bazel/src/crypto/spx/address.c', + 'third_party/boringssl-with-bazel/src/crypto/spx/fors.c', + 'third_party/boringssl-with-bazel/src/crypto/spx/merkle.c', + 'third_party/boringssl-with-bazel/src/crypto/spx/spx.c', + 'third_party/boringssl-with-bazel/src/crypto/spx/spx_util.c', + 'third_party/boringssl-with-bazel/src/crypto/spx/thash.c', + 'third_party/boringssl-with-bazel/src/crypto/spx/wots.c', + 'third_party/boringssl-with-bazel/src/crypto/stack/stack.c', + 'third_party/boringssl-with-bazel/src/crypto/thread.c', + 'third_party/boringssl-with-bazel/src/crypto/thread_none.c', + 'third_party/boringssl-with-bazel/src/crypto/thread_pthread.c', + 'third_party/boringssl-with-bazel/src/crypto/thread_win.c', + 'third_party/boringssl-with-bazel/src/crypto/trust_token/pmbtoken.c', + 'third_party/boringssl-with-bazel/src/crypto/trust_token/trust_token.c', + 'third_party/boringssl-with-bazel/src/crypto/trust_token/voprf.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/a_digest.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/a_sign.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/a_verify.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/algorithm.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/asn1_gen.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/by_dir.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/by_file.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/i2d_pr.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/name_print.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/policy.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/rsa_pss.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/t_crl.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/t_req.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/t_x509.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/t_x509a.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/v3_akey.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/v3_akeya.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/v3_alt.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/v3_bcons.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/v3_bitst.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/v3_conf.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/v3_cpols.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/v3_crld.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/v3_enum.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/v3_extku.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/v3_genn.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/v3_ia5.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/v3_info.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/v3_int.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/v3_lib.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/v3_ncons.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/v3_ocsp.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/v3_pcons.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/v3_pmaps.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/v3_prn.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/v3_purp.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/v3_skey.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/v3_utl.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x509.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x509_att.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x509_cmp.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x509_d2.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x509_def.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x509_ext.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x509_lu.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x509_obj.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x509_req.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x509_set.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x509_trs.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x509_txt.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x509_v3.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x509_vfy.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x509_vpm.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x509cset.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x509name.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x509rset.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x509spki.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x_algor.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x_all.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x_attrib.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x_crl.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x_exten.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x_name.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x_pubkey.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x_req.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x_sig.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x_spki.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x_val.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x_x509.c', + 'third_party/boringssl-with-bazel/src/crypto/x509/x_x509a.c', + 'third_party/boringssl-with-bazel/src/ssl/bio_ssl.cc', + 'third_party/boringssl-with-bazel/src/ssl/d1_both.cc', + 'third_party/boringssl-with-bazel/src/ssl/d1_lib.cc', + 'third_party/boringssl-with-bazel/src/ssl/d1_pkt.cc', + 'third_party/boringssl-with-bazel/src/ssl/d1_srtp.cc', + 'third_party/boringssl-with-bazel/src/ssl/dtls_method.cc', + 'third_party/boringssl-with-bazel/src/ssl/dtls_record.cc', + 'third_party/boringssl-with-bazel/src/ssl/encrypted_client_hello.cc', + 'third_party/boringssl-with-bazel/src/ssl/extensions.cc', + 'third_party/boringssl-with-bazel/src/ssl/handoff.cc', + 'third_party/boringssl-with-bazel/src/ssl/handshake.cc', + 'third_party/boringssl-with-bazel/src/ssl/handshake_client.cc', + 'third_party/boringssl-with-bazel/src/ssl/handshake_server.cc', + 'third_party/boringssl-with-bazel/src/ssl/s3_both.cc', + 'third_party/boringssl-with-bazel/src/ssl/s3_lib.cc', + 'third_party/boringssl-with-bazel/src/ssl/s3_pkt.cc', + 'third_party/boringssl-with-bazel/src/ssl/ssl_aead_ctx.cc', + 'third_party/boringssl-with-bazel/src/ssl/ssl_asn1.cc', + 'third_party/boringssl-with-bazel/src/ssl/ssl_buffer.cc', + 'third_party/boringssl-with-bazel/src/ssl/ssl_cert.cc', + 'third_party/boringssl-with-bazel/src/ssl/ssl_cipher.cc', + 'third_party/boringssl-with-bazel/src/ssl/ssl_file.cc', + 'third_party/boringssl-with-bazel/src/ssl/ssl_key_share.cc', + 'third_party/boringssl-with-bazel/src/ssl/ssl_lib.cc', + 'third_party/boringssl-with-bazel/src/ssl/ssl_privkey.cc', + 'third_party/boringssl-with-bazel/src/ssl/ssl_session.cc', + 'third_party/boringssl-with-bazel/src/ssl/ssl_stat.cc', + 'third_party/boringssl-with-bazel/src/ssl/ssl_transcript.cc', + 'third_party/boringssl-with-bazel/src/ssl/ssl_versions.cc', + 'third_party/boringssl-with-bazel/src/ssl/ssl_x509.cc', + 'third_party/boringssl-with-bazel/src/ssl/t1_enc.cc', + 'third_party/boringssl-with-bazel/src/ssl/tls13_both.cc', + 'third_party/boringssl-with-bazel/src/ssl/tls13_client.cc', + 'third_party/boringssl-with-bazel/src/ssl/tls13_enc.cc', + 'third_party/boringssl-with-bazel/src/ssl/tls13_server.cc', + 'third_party/boringssl-with-bazel/src/ssl/tls_method.cc', + 'third_party/boringssl-with-bazel/src/ssl/tls_record.cc', + ], + }, + { + 'target_name': 'boringssl_test_util', + 'type': 'static_library', + 'dependencies': [ + ], + 'sources': [ + 'third_party/boringssl-with-bazel/src/crypto/test/abi_test.cc', + 'third_party/boringssl-with-bazel/src/crypto/test/file_test.cc', + 'third_party/boringssl-with-bazel/src/crypto/test/test_util.cc', + 'third_party/boringssl-with-bazel/src/crypto/test/wycheproof_util.cc', + ], + }, + { + 'target_name': 'benchmark', + 'type': 'static_library', + 'dependencies': [ + ], + 'sources': [ + 'third_party/benchmark/src/benchmark.cc', + 'third_party/benchmark/src/benchmark_api_internal.cc', + 'third_party/benchmark/src/benchmark_main.cc', + 'third_party/benchmark/src/benchmark_name.cc', + 'third_party/benchmark/src/benchmark_register.cc', + 'third_party/benchmark/src/benchmark_runner.cc', + 'third_party/benchmark/src/check.cc', + 'third_party/benchmark/src/colorprint.cc', + 'third_party/benchmark/src/commandlineflags.cc', + 'third_party/benchmark/src/complexity.cc', + 'third_party/benchmark/src/console_reporter.cc', + 'third_party/benchmark/src/counter.cc', + 'third_party/benchmark/src/csv_reporter.cc', + 'third_party/benchmark/src/json_reporter.cc', + 'third_party/benchmark/src/perf_counters.cc', + 'third_party/benchmark/src/reporter.cc', + 'third_party/benchmark/src/statistics.cc', + 'third_party/benchmark/src/string_util.cc', + 'third_party/benchmark/src/sysinfo.cc', + 'third_party/benchmark/src/timers.cc', + ], + }, + ] +} diff --git a/include/grpc/impl/channel_arg_names.h b/include/grpc/impl/channel_arg_names.h index 663e9620a34..efd380b8681 100644 --- a/include/grpc/impl/channel_arg_names.h +++ b/include/grpc/impl/channel_arg_names.h @@ -111,9 +111,11 @@ "grpc.server_max_unrequested_time_in_server" /** Channel arg to override the http2 :scheme header */ #define GRPC_ARG_HTTP2_SCHEME "grpc.http2_scheme" -/** How many pings can the client send before needing to send a - data/header frame? (0 indicates that an infinite number of - pings can be sent without sending a data frame or header frame) */ +/** How many pings can the client send before needing to send a data/header + frame? (0 indicates that an infinite number of pings can be sent without + sending a data frame or header frame). + If experiment "max_pings_wo_data_throttle" is enabled, instead of pings being + completely blocked, they are throttled. */ #define GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA \ "grpc.http2.max_pings_without_data" /** How many misbehaving pings the server can bear before sending goaway and diff --git a/package.xml b/package.xml index eda4309713c..d1778bf0607 100644 --- a/package.xml +++ b/package.xml @@ -114,6 +114,8 @@ + + @@ -129,6 +131,8 @@ + + @@ -1243,6 +1247,8 @@ + + @@ -1305,14 +1311,6 @@ - - - - - - - - @@ -1476,6 +1474,7 @@ + @@ -1901,6 +1900,14 @@ + + + + + + + + @@ -2521,7 +2528,6 @@ - @@ -2544,6 +2550,8 @@ + + @@ -2864,6 +2872,7 @@ + diff --git a/requirements.bazel.txt b/requirements.bazel.txt index 905c092ce4c..c6036839b1f 100644 --- a/requirements.bazel.txt +++ b/requirements.bazel.txt @@ -26,9 +26,12 @@ pyasn1==0.5.0 rsa==4.9 greenlet==1.1.3.post0 zope.interface==6.1 -opentelemetry-sdk==1.21.0 -opentelemetry-api==1.21.0 +opentelemetry-sdk==1.24.0 +opentelemetry-api==1.24.0 importlib-metadata==6.11.0 +opentelemetry-resourcedetector-gcp==1.6.0a0 +opentelemetry-exporter-prometheus==0.45b0 +prometheus_client==0.20.0 Deprecated==1.2.14 opentelemetry-semantic-conventions==0.42b0 typing-extensions==4.9.0 diff --git a/src/boringssl/boringssl_prefix_symbols.h b/src/boringssl/boringssl_prefix_symbols.h index 3255f889966..faa1bc2ad47 100644 --- a/src/boringssl/boringssl_prefix_symbols.h +++ b/src/boringssl/boringssl_prefix_symbols.h @@ -1,4 +1,4 @@ -// generated by generate_boringssl_prefix_header.sh on BoringSSL commit: 5a2bca2124800f2861263959b72bc35cdf18949b +// generated by generate_boringssl_prefix_header.sh on BoringSSL commit: b8a2bffc598f230484ff48a247526a9820facfc2 // Copyright (c) 2018, Google Inc. // @@ -1344,6 +1344,15 @@ #define DH_size BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_size) #define DH_up_ref BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DH_up_ref) #define DHparams_dup BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DHparams_dup) +#define DILITHIUM_generate_key BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DILITHIUM_generate_key) +#define DILITHIUM_generate_key_external_entropy BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DILITHIUM_generate_key_external_entropy) +#define DILITHIUM_marshal_private_key BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DILITHIUM_marshal_private_key) +#define DILITHIUM_marshal_public_key BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DILITHIUM_marshal_public_key) +#define DILITHIUM_parse_private_key BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DILITHIUM_parse_private_key) +#define DILITHIUM_parse_public_key BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DILITHIUM_parse_public_key) +#define DILITHIUM_sign BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DILITHIUM_sign) +#define DILITHIUM_sign_deterministic BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DILITHIUM_sign_deterministic) +#define DILITHIUM_verify BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DILITHIUM_verify) #define DIRECTORYSTRING_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DIRECTORYSTRING_free) #define DIRECTORYSTRING_it BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DIRECTORYSTRING_it) #define DIRECTORYSTRING_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, DIRECTORYSTRING_new) @@ -2697,11 +2706,9 @@ #define X509_STORE_load_locations BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_STORE_load_locations) #define X509_STORE_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_STORE_new) #define X509_STORE_set1_param BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_STORE_set1_param) -#define X509_STORE_set_check_crl BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_STORE_set_check_crl) #define X509_STORE_set_default_paths BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_STORE_set_default_paths) #define X509_STORE_set_depth BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_STORE_set_depth) #define X509_STORE_set_flags BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_STORE_set_flags) -#define X509_STORE_set_get_crl BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_STORE_set_get_crl) #define X509_STORE_set_purpose BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_STORE_set_purpose) #define X509_STORE_set_trust BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_STORE_set_trust) #define X509_STORE_set_verify_cb BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, X509_STORE_set_verify_cb) @@ -2957,19 +2964,22 @@ #define bn_mont_ctx_set_RR_consttime BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_mont_ctx_set_RR_consttime) #define bn_mont_n0 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_mont_n0) #define bn_mul4x_mont BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_mul4x_mont) +#define bn_mul4x_mont_gather5 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_mul4x_mont_gather5) #define bn_mul_add_words BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_mul_add_words) #define bn_mul_comba4 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_mul_comba4) #define bn_mul_comba8 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_mul_comba8) #define bn_mul_consttime BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_mul_consttime) #define bn_mul_mont BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_mul_mont) -#define bn_mul_mont_gather5 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_mul_mont_gather5) +#define bn_mul_mont_gather5_nohw BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_mul_mont_gather5_nohw) #define bn_mul_mont_nohw BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_mul_mont_nohw) #define bn_mul_small BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_mul_small) #define bn_mul_words BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_mul_words) #define bn_mulx4x_mont BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_mulx4x_mont) +#define bn_mulx4x_mont_gather5 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_mulx4x_mont_gather5) #define bn_odd_number_is_obviously_composite BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_odd_number_is_obviously_composite) #define bn_one_to_montgomery BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_one_to_montgomery) -#define bn_power5 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_power5) +#define bn_power5_nohw BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_power5_nohw) +#define bn_powerx5 BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_powerx5) #define bn_rand_range_words BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_rand_range_words) #define bn_rand_secret_range BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_rand_secret_range) #define bn_reduce_once BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, bn_reduce_once) diff --git a/src/core/BUILD b/src/core/BUILD index b1f10e5fdd8..9d23ed2f1a4 100644 --- a/src/core/BUILD +++ b/src/core/BUILD @@ -1236,6 +1236,7 @@ grpc_cc_library( public_hdrs = ["lib/gprpp/dual_ref_counted.h"], deps = [ "down_cast", + "ref_counted", "//:debug_location", "//:gpr", "//:orphanable", @@ -1488,6 +1489,7 @@ grpc_cc_library( "context", "event_engine_memory_allocator", "memory_quota", + "resource_quota", "//:gpr", ], ) @@ -3281,12 +3283,12 @@ grpc_cc_library( language = "c++", deps = [ "arena", + "call_destination", "grpc_service_config", "lb_policy", "unique_type_name", "//:call_tracer", - "//:gpr_public_hdrs", - "//:grpc_base", + "//:gpr", "//:legacy_context", ], ) @@ -4420,10 +4422,10 @@ grpc_cc_library( grpc_cc_library( name = "httpcli_ssl_credentials", srcs = [ - "lib/http/httpcli_security_connector.cc", + "util/http_client/httpcli_security_connector.cc", ], hdrs = [ - "lib/http/httpcli_ssl_credentials.h", + "util/http_client/httpcli_ssl_credentials.h", ], external_deps = [ "absl/log:log", @@ -7509,12 +7511,10 @@ grpc_cc_library( hdrs = [ "lib/transport/call_filters.h", ], - external_deps = [ - "absl/log:check", - "absl/log:log", - ], + external_deps = ["absl/log:check"], deps = [ "call_final_info", + "dump_args", "latch", "map", "message", @@ -7620,20 +7620,19 @@ grpc_cc_library( hdrs = [ "lib/transport/call_spine.h", ], - external_deps = [ - "absl/log:check", - "absl/log:log", - ], + external_deps = ["absl/log:check"], deps = [ "1999", "call_arena_allocator", "call_filters", + "dual_ref_counted", "for_each", "if", "latch", "message", "metadata", "pipe", + "prioritized_race", "promise_status", "status_flag", "try_seq", diff --git a/src/core/client_channel/client_channel.cc b/src/core/client_channel/client_channel.cc new file mode 100644 index 00000000000..5395efce7b9 --- /dev/null +++ b/src/core/client_channel/client_channel.cc @@ -0,0 +1,1387 @@ +// 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 "src/core/client_channel/client_channel.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "absl/cleanup/cleanup.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/cord.h" +#include "absl/strings/numbers.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_join.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "absl/types/variant.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "src/core/client_channel/backup_poller.h" +#include "src/core/client_channel/client_channel_internal.h" +#include "src/core/client_channel/client_channel_service_config.h" +#include "src/core/client_channel/config_selector.h" +#include "src/core/client_channel/dynamic_filters.h" +#include "src/core/client_channel/global_subchannel_pool.h" +#include "src/core/client_channel/local_subchannel_pool.h" +#include "src/core/client_channel/retry_filter.h" +#include "src/core/client_channel/subchannel.h" +#include "src/core/client_channel/subchannel_interface_internal.h" +#include "src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h" +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/channel/channel_stack.h" +#include "src/core/lib/channel/promise_based_filter.h" +#include "src/core/lib/channel/status_util.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/crash.h" +#include "src/core/lib/gprpp/debug_location.h" +#include "src/core/lib/gprpp/manual_constructor.h" +#include "src/core/lib/gprpp/status_helper.h" +#include "src/core/lib/gprpp/sync.h" +#include "src/core/lib/gprpp/unique_type_name.h" +#include "src/core/lib/gprpp/work_serializer.h" +#include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/iomgr/resolved_address.h" +#include "src/core/lib/promise/cancel_callback.h" +#include "src/core/lib/promise/context.h" +#include "src/core/lib/promise/exec_ctx_wakeup_scheduler.h" +#include "src/core/lib/promise/latch.h" +#include "src/core/lib/promise/loop.h" +#include "src/core/lib/promise/map.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/sleep.h" +#include "src/core/lib/promise/status_flag.h" +#include "src/core/lib/promise/try_seq.h" +#include "src/core/lib/resource_quota/resource_quota.h" +#include "src/core/lib/security/credentials/credentials.h" +#include "src/core/lib/slice/slice.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/surface/call.h" +#include "src/core/lib/surface/channel.h" +#include "src/core/lib/surface/completion_queue.h" +#include "src/core/lib/transport/call_spine.h" +#include "src/core/lib/transport/connectivity_state.h" +#include "src/core/lib/transport/error_utils.h" +#include "src/core/lib/transport/metadata_batch.h" +#include "src/core/load_balancing/backend_metric_parser.h" +#include "src/core/load_balancing/child_policy_handler.h" +#include "src/core/load_balancing/lb_policy.h" +#include "src/core/load_balancing/lb_policy_registry.h" +#include "src/core/load_balancing/subchannel_interface.h" +#include "src/core/resolver/endpoint_addresses.h" +#include "src/core/resolver/resolver_registry.h" +#include "src/core/service_config/service_config_call_data.h" +#include "src/core/service_config/service_config_impl.h" +#include "src/core/telemetry/metrics.h" +#include "src/core/util/json/json.h" +#include "src/core/util/useful.h" + +namespace grpc_core { + +using grpc_event_engine::experimental::EventEngine; + +using internal::ClientChannelMethodParsedConfig; + +// Defined in legacy client channel filter. +// TODO(roth): Move these here when we remove the legacy filter. +extern TraceFlag grpc_client_channel_trace; +extern TraceFlag grpc_client_channel_call_trace; +extern TraceFlag grpc_client_channel_lb_call_trace; + +// +// ClientChannel::ResolverResultHandler +// + +class ClientChannel::ResolverResultHandler : public Resolver::ResultHandler { + public: + explicit ResolverResultHandler(RefCountedPtr client_channel) + : client_channel_(std::move(client_channel)) {} + + ~ResolverResultHandler() override { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, "client_channel=%p: resolver shutdown complete", + client_channel_.get()); + } + } + + void ReportResult(Resolver::Result result) override + ABSL_EXCLUSIVE_LOCKS_REQUIRED(*client_channel_->work_serializer_) { + client_channel_->OnResolverResultChangedLocked(std::move(result)); + } + + private: + RefCountedPtr client_channel_; +}; + +// +// ClientChannel::SubchannelWrapper +// + +// This class is a wrapper for Subchannel that hides details of the +// channel's implementation (such as the connected subchannel) from the +// LB policy API. +// +// Note that no synchronization is needed here, because even if the +// underlying subchannel is shared between channels, this wrapper will only +// be used within one channel, so it will always be synchronized by the +// control plane work_serializer. +class ClientChannel::SubchannelWrapper + : public SubchannelInterfaceWithCallDestination { + public: + SubchannelWrapper(RefCountedPtr client_channel, + RefCountedPtr subchannel); + ~SubchannelWrapper() override; + + void Orphaned() override; + void WatchConnectivityState( + std::unique_ptr watcher) override + ABSL_EXCLUSIVE_LOCKS_REQUIRED(*client_channel_->work_serializer_); + void CancelConnectivityStateWatch( + ConnectivityStateWatcherInterface* watcher) override + ABSL_EXCLUSIVE_LOCKS_REQUIRED(*client_channel_->work_serializer_); + + RefCountedPtr call_destination() override { + return subchannel_->call_destination(); + } + + void RequestConnection() override { subchannel_->RequestConnection(); } + + void ResetBackoff() override { subchannel_->ResetBackoff(); } + + void AddDataWatcher(std::unique_ptr watcher) override + ABSL_EXCLUSIVE_LOCKS_REQUIRED(*client_channel_->work_serializer_); + void CancelDataWatcher(DataWatcherInterface* watcher) override + ABSL_EXCLUSIVE_LOCKS_REQUIRED(*client_channel_->work_serializer_); + void ThrottleKeepaliveTime(int new_keepalive_time); + + private: + class WatcherWrapper; + + // A heterogenous lookup comparator for data watchers that allows + // unique_ptr keys to be looked up as raw pointers. + struct DataWatcherLessThan { + using is_transparent = void; + bool operator()(const std::unique_ptr& p1, + const std::unique_ptr& p2) const { + return p1 < p2; + } + bool operator()(const std::unique_ptr& p1, + const DataWatcherInterface* p2) const { + return p1.get() < p2; + } + bool operator()(const DataWatcherInterface* p1, + const std::unique_ptr& p2) const { + return p1 < p2.get(); + } + }; + + RefCountedPtr client_channel_; + RefCountedPtr subchannel_; + // Maps from the address of the watcher passed to us by the LB policy + // to the address of the WrapperWatcher that we passed to the underlying + // subchannel. This is needed so that when the LB policy calls + // CancelConnectivityStateWatch() with its watcher, we know the + // corresponding WrapperWatcher to cancel on the underlying subchannel. + std::map watcher_map_ + ABSL_GUARDED_BY(*client_channel_->work_serializer_); + std::set, DataWatcherLessThan> + data_watchers_ ABSL_GUARDED_BY(*client_channel_->work_serializer_); +}; + +// This wrapper provides a bridge between the internal Subchannel API +// and the SubchannelInterface API that we expose to LB policies. +// It implements Subchannel::ConnectivityStateWatcherInterface and wraps +// the instance of SubchannelInterface::ConnectivityStateWatcherInterface +// that was passed in by the LB policy. We pass an instance of this +// class to the underlying Subchannel, and when we get updates from +// the subchannel, we pass those on to the wrapped watcher to return +// the update to the LB policy. +// +// This class handles things like hopping into the WorkSerializer +// before passing notifications to the LB policy and propagating +// keepalive information betwen subchannels. +class ClientChannel::SubchannelWrapper::WatcherWrapper + : public Subchannel::ConnectivityStateWatcherInterface { + public: + WatcherWrapper( + std::unique_ptr + watcher, + RefCountedPtr subchannel_wrapper) + : watcher_(std::move(watcher)), + subchannel_wrapper_(std::move(subchannel_wrapper)) {} + + ~WatcherWrapper() override { + subchannel_wrapper_.reset(DEBUG_LOCATION, "WatcherWrapper"); + } + + void OnConnectivityStateChange( + RefCountedPtr self, + grpc_connectivity_state state, const absl::Status& status) override { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, + "client_channel=%p: connectivity change for subchannel " + "wrapper %p subchannel %p; hopping into work_serializer", + subchannel_wrapper_->client_channel_.get(), + subchannel_wrapper_.get(), + subchannel_wrapper_->subchannel_.get()); + } + self.release(); // Held by callback. + subchannel_wrapper_->client_channel_->work_serializer_->Run( + [this, state, status]() ABSL_EXCLUSIVE_LOCKS_REQUIRED( + *subchannel_wrapper_->client_channel_->work_serializer_) { + ApplyUpdateInControlPlaneWorkSerializer(state, status); + Unref(); + }, + DEBUG_LOCATION); + } + + grpc_pollset_set* interested_parties() override { return nullptr; } + + private: + void ApplyUpdateInControlPlaneWorkSerializer(grpc_connectivity_state state, + const absl::Status& status) + ABSL_EXCLUSIVE_LOCKS_REQUIRED( + *subchannel_wrapper_->client_channel_->work_serializer_) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, + "client_channel=%p: processing connectivity change in work " + "serializer for subchannel wrapper %p subchannel %p watcher=%p " + "state=%s status=%s", + subchannel_wrapper_->client_channel_.get(), + subchannel_wrapper_.get(), subchannel_wrapper_->subchannel_.get(), + watcher_.get(), ConnectivityStateName(state), + status.ToString().c_str()); + } + absl::optional keepalive_throttling = + status.GetPayload(kKeepaliveThrottlingKey); + if (keepalive_throttling.has_value()) { + int new_keepalive_time = -1; + if (absl::SimpleAtoi(std::string(keepalive_throttling.value()), + &new_keepalive_time)) { + if (new_keepalive_time > + subchannel_wrapper_->client_channel_->keepalive_time_) { + subchannel_wrapper_->client_channel_->keepalive_time_ = + new_keepalive_time; + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, + "client_channel=%p: throttling keepalive time to %d", + subchannel_wrapper_->client_channel_.get(), + subchannel_wrapper_->client_channel_->keepalive_time_); + } + // Propagate the new keepalive time to all subchannels. This is so + // that new transports created by any subchannel (and not just the + // subchannel that received the GOAWAY), use the new keepalive time. + for (auto* subchannel_wrapper : + subchannel_wrapper_->client_channel_->subchannel_wrappers_) { + subchannel_wrapper->ThrottleKeepaliveTime(new_keepalive_time); + } + } + } else { + gpr_log(GPR_ERROR, + "client_channel=%p: Illegal keepalive throttling value %s", + subchannel_wrapper_->client_channel_.get(), + std::string(keepalive_throttling.value()).c_str()); + } + } + // Propagate status only in state TF. + // We specifically want to avoid propagating the status for + // state IDLE that the real subchannel gave us only for the + // purpose of keepalive propagation. + watcher_->OnConnectivityStateChange( + state, + state == GRPC_CHANNEL_TRANSIENT_FAILURE ? status : absl::OkStatus()); + } + + std::unique_ptr + watcher_; + RefCountedPtr subchannel_wrapper_; +}; + +ClientChannel::SubchannelWrapper::SubchannelWrapper( + RefCountedPtr client_channel, + RefCountedPtr subchannel) + : SubchannelInterfaceWithCallDestination( + GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace) + ? "SubchannelWrapper" + : nullptr), + client_channel_(std::move(client_channel)), + subchannel_(std::move(subchannel)) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log( + GPR_INFO, + "client_channel=%p: creating subchannel wrapper %p for subchannel %p", + client_channel_.get(), this, subchannel_.get()); + } +#ifndef NDEBUG + DCHECK(client_channel_->work_serializer_->RunningInWorkSerializer()); +#endif + if (client_channel_->channelz_node_ != nullptr) { + auto* subchannel_node = subchannel_->channelz_node(); + if (subchannel_node != nullptr) { + auto it = + client_channel_->subchannel_refcount_map_.find(subchannel_.get()); + if (it == client_channel_->subchannel_refcount_map_.end()) { + client_channel_->channelz_node_->AddChildSubchannel( + subchannel_node->uuid()); + it = client_channel_->subchannel_refcount_map_ + .emplace(subchannel_.get(), 0) + .first; + } + ++it->second; + } + } + client_channel_->subchannel_wrappers_.insert(this); +} + +ClientChannel::SubchannelWrapper::~SubchannelWrapper() { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, + "client_channel=%p: destroying subchannel wrapper %p " + "for subchannel %p", + client_channel_.get(), this, subchannel_.get()); + } +} + +void ClientChannel::SubchannelWrapper::Orphaned() { + // Make sure we clean up the channel's subchannel maps inside the + // WorkSerializer. + auto self = WeakRefAsSubclass(DEBUG_LOCATION, + "subchannel map cleanup"); + client_channel_->work_serializer_->Run( + [self]() ABSL_EXCLUSIVE_LOCKS_REQUIRED( + *self->client_channel_->work_serializer_) { + self->client_channel_->subchannel_wrappers_.erase(self.get()); + if (self->client_channel_->channelz_node_ != nullptr) { + auto* subchannel_node = self->subchannel_->channelz_node(); + if (subchannel_node != nullptr) { + auto it = self->client_channel_->subchannel_refcount_map_.find( + self->subchannel_.get()); + CHECK(it != self->client_channel_->subchannel_refcount_map_.end()); + --it->second; + if (it->second == 0) { + self->client_channel_->channelz_node_->RemoveChildSubchannel( + subchannel_node->uuid()); + self->client_channel_->subchannel_refcount_map_.erase(it); + } + } + } + }, + DEBUG_LOCATION); +} + +void ClientChannel::SubchannelWrapper::WatchConnectivityState( + std::unique_ptr watcher) { + auto& watcher_wrapper = watcher_map_[watcher.get()]; + CHECK(watcher_wrapper == nullptr); + watcher_wrapper = new WatcherWrapper( + std::move(watcher), + RefAsSubclass(DEBUG_LOCATION, "WatcherWrapper")); + subchannel_->WatchConnectivityState( + RefCountedPtr( + watcher_wrapper)); +} + +void ClientChannel::SubchannelWrapper::CancelConnectivityStateWatch( + ConnectivityStateWatcherInterface* watcher) { + auto it = watcher_map_.find(watcher); + CHECK(it != watcher_map_.end()); + subchannel_->CancelConnectivityStateWatch(it->second); + watcher_map_.erase(it); +} + +void ClientChannel::SubchannelWrapper::AddDataWatcher( + std::unique_ptr watcher) { + static_cast(watcher.get()) + ->SetSubchannel(subchannel_.get()); + CHECK(data_watchers_.insert(std::move(watcher)).second); +} + +void ClientChannel::SubchannelWrapper::CancelDataWatcher( + DataWatcherInterface* watcher) { + auto it = data_watchers_.find(watcher); + if (it != data_watchers_.end()) data_watchers_.erase(it); +} + +void ClientChannel::SubchannelWrapper::ThrottleKeepaliveTime( + int new_keepalive_time) { + subchannel_->ThrottleKeepaliveTime(new_keepalive_time); +} + +// +// ClientChannel::ClientChannelControlHelper +// + +class ClientChannel::ClientChannelControlHelper + : public LoadBalancingPolicy::ChannelControlHelper { + public: + explicit ClientChannelControlHelper( + RefCountedPtr client_channel) + : client_channel_(std::move(client_channel)) {} + + ~ClientChannelControlHelper() override { + client_channel_.reset(DEBUG_LOCATION, "ClientChannelControlHelper"); + } + + RefCountedPtr CreateSubchannel( + const grpc_resolved_address& address, const ChannelArgs& per_address_args, + const ChannelArgs& args) override + ABSL_EXCLUSIVE_LOCKS_REQUIRED(*client_channel_->work_serializer_) { + // If shutting down, do nothing. + if (client_channel_->resolver_ == nullptr) return nullptr; + ChannelArgs subchannel_args = Subchannel::MakeSubchannelArgs( + args, per_address_args, client_channel_->subchannel_pool_, + client_channel_->default_authority_); + // Create subchannel. + RefCountedPtr subchannel = + client_channel_->client_channel_factory_->CreateSubchannel( + address, subchannel_args); + if (subchannel == nullptr) return nullptr; + // Make sure the subchannel has updated keepalive time. + subchannel->ThrottleKeepaliveTime(client_channel_->keepalive_time_); + // Create and return wrapper for the subchannel. + return MakeRefCounted(client_channel_, + std::move(subchannel)); + } + + void UpdateState( + grpc_connectivity_state state, const absl::Status& status, + RefCountedPtr picker) override + ABSL_EXCLUSIVE_LOCKS_REQUIRED(*client_channel_->work_serializer_) { + if (client_channel_->resolver_ == nullptr) return; // Shutting down. + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + const char* extra = client_channel_->disconnect_error_.ok() + ? "" + : " (ignoring -- channel shutting down)"; + gpr_log(GPR_INFO, + "client_channel=%p: update: state=%s status=(%s) picker=%p%s", + client_channel_.get(), ConnectivityStateName(state), + status.ToString().c_str(), picker.get(), extra); + } + // Do update only if not shutting down. + if (client_channel_->disconnect_error_.ok()) { + client_channel_->UpdateStateAndPickerLocked(state, status, "helper", + std::move(picker)); + } + } + + void RequestReresolution() override + ABSL_EXCLUSIVE_LOCKS_REQUIRED(*client_channel_->work_serializer_) { + if (client_channel_->resolver_ == nullptr) return; // Shutting down. + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, "client_channel=%p: started name re-resolving", + client_channel_.get()); + } + client_channel_->resolver_->RequestReresolutionLocked(); + } + + absl::string_view GetTarget() override { return client_channel_->target(); } + + absl::string_view GetAuthority() override { + return client_channel_->default_authority_; + } + + RefCountedPtr GetChannelCredentials() override { + return client_channel_->channel_args_.GetObject() + ->duplicate_without_call_credentials(); + } + + RefCountedPtr GetUnsafeChannelCredentials() + override { + return client_channel_->channel_args_.GetObject() + ->Ref(); + } + + EventEngine* GetEventEngine() override { + return client_channel_->event_engine(); + } + + GlobalStatsPluginRegistry::StatsPluginGroup& GetStatsPluginGroup() override { + return client_channel_->stats_plugin_group_; + } + + void AddTraceEvent(TraceSeverity severity, absl::string_view message) override + ABSL_EXCLUSIVE_LOCKS_REQUIRED(*client_channel_->work_serializer_) { + if (client_channel_->resolver_ == nullptr) return; // Shutting down. + if (client_channel_->channelz_node_ != nullptr) { + client_channel_->channelz_node_->AddTraceEvent( + ConvertSeverityEnum(severity), + grpc_slice_from_copied_buffer(message.data(), message.size())); + } + } + + private: + static channelz::ChannelTrace::Severity ConvertSeverityEnum( + TraceSeverity severity) { + if (severity == TRACE_INFO) return channelz::ChannelTrace::Info; + if (severity == TRACE_WARNING) return channelz::ChannelTrace::Warning; + return channelz::ChannelTrace::Error; + } + + RefCountedPtr client_channel_; +}; + +// +// ClientChannel implementation +// + +namespace { + +RefCountedPtr GetSubchannelPool( + const ChannelArgs& args) { + if (args.GetBool(GRPC_ARG_USE_LOCAL_SUBCHANNEL_POOL).value_or(false)) { + return MakeRefCounted(); + } + return GlobalSubchannelPool::instance(); +} + +} // namespace + +absl::StatusOr> ClientChannel::Create( + std::string target, ChannelArgs channel_args) { + gpr_log(GPR_ERROR, "ARGS: %s", channel_args.ToString().c_str()); + // Get URI to resolve, using proxy mapper if needed. + if (target.empty()) { + return absl::InternalError("target URI is empty in client channel"); + } + std::string uri_to_resolve = CoreConfiguration::Get() + .proxy_mapper_registry() + .MapName(target, &channel_args) + .value_or(target); + // Make sure the URI to resolve is valid, so that we know that + // resolver creation will succeed later. + if (!CoreConfiguration::Get().resolver_registry().IsValidTarget( + uri_to_resolve)) { + return absl::InvalidArgumentError( + absl::StrCat("invalid target URI: ", uri_to_resolve)); + } + // Get default service config. If none is specified via the client API, + // we use an empty config. + absl::optional service_config_json = + channel_args.GetString(GRPC_ARG_SERVICE_CONFIG); + if (!service_config_json.has_value()) service_config_json = "{}"; + auto default_service_config = + ServiceConfigImpl::Create(channel_args, *service_config_json); + if (!default_service_config.ok()) return default_service_config.status(); + // Strip out service config channel arg, so that it doesn't affect + // subchannel uniqueness when the args flow down to that layer. + channel_args = channel_args.Remove(GRPC_ARG_SERVICE_CONFIG); + // Check client channel factory. + auto* client_channel_factory = channel_args.GetObject(); + if (client_channel_factory == nullptr) { + return absl::InternalError( + "Missing client channel factory in args for client channel"); + } + auto* call_destination_factory = + channel_args.GetObject(); + if (call_destination_factory == nullptr) { + return absl::InternalError( + "Missing call destination factory in args for client channel"); + } + if (channel_args.GetObject() == nullptr) { + return absl::InternalError( + "Missing event engine in args for client channel"); + } + // Success. Construct channel. + return MakeOrphanable( + std::move(target), std::move(channel_args), std::move(uri_to_resolve), + std::move(*default_service_config), client_channel_factory, + call_destination_factory); +} + +namespace { +std::string GetDefaultAuthorityFromChannelArgs(const ChannelArgs& channel_args, + absl::string_view target) { + absl::optional default_authority = + channel_args.GetOwnedString(GRPC_ARG_DEFAULT_AUTHORITY); + if (!default_authority.has_value()) { + return CoreConfiguration::Get().resolver_registry().GetDefaultAuthority( + target); + } else { + return std::move(*default_authority); + } +} +} // namespace + +ClientChannel::ClientChannel( + std::string target, ChannelArgs channel_args, std::string uri_to_resolve, + RefCountedPtr default_service_config, + ClientChannelFactory* client_channel_factory, + CallDestinationFactory* call_destination_factory) + : Channel(std::move(target), channel_args), + channel_args_(std::move(channel_args)), + event_engine_(channel_args_.GetObjectRef()), + uri_to_resolve_(std::move(uri_to_resolve)), + service_config_parser_index_( + internal::ClientChannelServiceConfigParser::ParserIndex()), + default_service_config_(std::move(default_service_config)), + client_channel_factory_(client_channel_factory), + default_authority_( + GetDefaultAuthorityFromChannelArgs(channel_args_, this->target())), + channelz_node_(channel_args_.GetObject()), + idle_timeout_(GetClientIdleTimeout(channel_args_)), + resolver_data_for_calls_(ResolverDataForCalls{}), + picker_(nullptr), + call_destination_( + call_destination_factory->CreateCallDestination(picker_)), + work_serializer_(std::make_shared(event_engine_)), + state_tracker_("client_channel", GRPC_CHANNEL_IDLE), + subchannel_pool_(GetSubchannelPool(channel_args_)) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, "client_channel=%p: creating client_channel", this); + } + // Set initial keepalive time. + auto keepalive_arg = channel_args_.GetInt(GRPC_ARG_KEEPALIVE_TIME_MS); + if (keepalive_arg.has_value()) { + keepalive_time_ = Clamp(*keepalive_arg, 1, INT_MAX); + } else { + keepalive_time_ = -1; // unset + } + // Get stats plugins for channel. + experimental::StatsPluginChannelScope scope(this->target(), + default_authority_); + stats_plugin_group_ = + GlobalStatsPluginRegistry::GetStatsPluginsForChannel(scope); +} + +ClientChannel::~ClientChannel() { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, "client_channel=%p: destroying", this); + } +} + +void ClientChannel::Orphan() { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, "client_channel=%p: shutting down", this); + } + auto self = RefAsSubclass(); + work_serializer_->Run( + [self]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*self->work_serializer_) { + self->DestroyResolverAndLbPolicyLocked(); + }, + DEBUG_LOCATION); + // IncreaseCallCount() introduces a phony call and prevents the idle + // timer from being reset by other threads. + idle_state_.IncreaseCallCount(); + idle_activity_.Reset(); + Unref(); +} + +grpc_connectivity_state ClientChannel::CheckConnectivityState( + bool try_to_connect) { + // state_tracker_ is guarded by work_serializer_, which we're not + // holding here. But the one method of state_tracker_ that *is* + // thread-safe to call without external synchronization is the state() + // method, so we can disable thread-safety analysis for this one read. + grpc_connectivity_state state = + ABSL_TS_UNCHECKED_READ(state_tracker_).state(); + if (state == GRPC_CHANNEL_IDLE && try_to_connect) { + auto self = RefAsSubclass(); // Held by callback. + work_serializer_->Run( + [self]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*self->work_serializer_) { + self->TryToConnectLocked(); + }, + DEBUG_LOCATION); + } + return state; +} + +void ClientChannel::WatchConnectivityState(grpc_connectivity_state, Timestamp, + grpc_completion_queue*, void*) { + // TODO(ctiller): implement + Crash("not implemented"); +} + +void ClientChannel::AddConnectivityWatcher( + grpc_connectivity_state, + OrphanablePtr) { + Crash("not implemented"); + // TODO(ctiller): to make this work, need to change WorkSerializer to use + // absl::AnyInvocable<> instead of std::function<> + // work_serializer_->Run( + // [self = RefAsSubclass(), initial_state, + // watcher = std::move(watcher)]() + // ABSL_EXCLUSIVE_LOCKS_REQUIRED(*work_serializer_) { + // self->state_tracker_.AddWatcher(initial_state, std::move(watcher)); + // }, + // DEBUG_LOCATION); +} + +void ClientChannel::RemoveConnectivityWatcher( + AsyncConnectivityStateWatcherInterface* watcher) { + auto self = RefAsSubclass(); // Held by callback. + work_serializer_->Run( + [self, watcher]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*self->work_serializer_) { + self->state_tracker_.RemoveWatcher(watcher); + }, + DEBUG_LOCATION); +} + +void ClientChannel::GetInfo(const grpc_channel_info* info) { + MutexLock lock(&info_mu_); + if (info->lb_policy_name != nullptr) { + *info->lb_policy_name = gpr_strdup(info_lb_policy_name_.c_str()); + } + if (info->service_config_json != nullptr) { + *info->service_config_json = gpr_strdup(info_service_config_json_.c_str()); + } +} + +void ClientChannel::ResetConnectionBackoff() { + auto self = RefAsSubclass(); + work_serializer_->Run( + [self]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*self->work_serializer_) { + if (self->lb_policy_ != nullptr) self->lb_policy_->ResetBackoffLocked(); + }, + DEBUG_LOCATION); +} + +namespace { + +// A class to handle CQ completion for a ping. +class PingRequest { + public: + PingRequest(grpc_completion_queue* cq, void* tag) : cq_(cq), tag_(tag) { + grpc_cq_begin_op(cq, tag); + } + + // Triggers CQ completion and eventually deletes the PingRequest object. + void Complete(grpc_error_handle error) { + grpc_cq_end_op(cq_, tag_, error, Destroy, this, &completion_storage_); + } + + private: + static void Destroy(void* arg, grpc_cq_completion* /*storage*/) { + delete static_cast(arg); + } + + grpc_completion_queue* cq_; + void* tag_; + grpc_cq_completion completion_storage_; +}; + +} // namespace + +void ClientChannel::Ping(grpc_completion_queue*, void*) { + // TODO(ctiller): implement + Crash("not implemented"); +} + +grpc_call* ClientChannel::CreateCall(grpc_call*, uint32_t, + grpc_completion_queue*, grpc_pollset_set*, + Slice, absl::optional, Timestamp, + bool) { + // TODO(ctiller): code to convert from C-core batch API to v3 call, then + // invoke CreateCall(client_initial_metadata, arena) + // TODO(ctiller): make sure call holds a ref to ClientChannel for its entire + // lifetime + Crash("not implemented"); + return nullptr; +} + +CallInitiator ClientChannel::CreateCall( + ClientMetadataHandle client_initial_metadata) { + // Increment call count. + if (idle_timeout_ != Duration::Zero()) idle_state_.IncreaseCallCount(); + // Exit IDLE if needed. + CheckConnectivityState(/*try_to_connect=*/true); + // Create an initiator/unstarted-handler pair. + auto call = + MakeCallPair(std::move(client_initial_metadata), event_engine_.get(), + call_arena_allocator()->MakeArena(), nullptr); + // Spawn a promise to wait for the resolver result. + // This will eventually start the call. + call.initiator.SpawnGuardedUntilCallCompletes( + "wait-for-name-resolution", + [self = RefAsSubclass(), + unstarted_handler = std::move(call.handler)]() mutable { + const bool wait_for_ready = + unstarted_handler.UnprocessedClientInitialMetadata() + .GetOrCreatePointer(WaitForReady()) + ->value; + return Map( + // Wait for the resolver result. + CheckDelayed(self->resolver_data_for_calls_.NextWhen( + [wait_for_ready]( + const absl::StatusOr result) { + bool got_result = false; + // If the resolver reports an error but the call is + // wait_for_ready, keep waiting for the next result + // instead of failing the call. + if (!result.ok()) { + got_result = !wait_for_ready; + } else { + // Not an error. Make sure we actually have a result. + got_result = result->config_selector != nullptr; + } + return got_result; + })), + // Handle resolver result. + [self, unstarted_handler]( + std::tuple, bool> + result_and_delayed) mutable { + auto& resolver_data = std::get<0>(result_and_delayed); + const bool was_queued = std::get<1>(result_and_delayed); + if (!resolver_data.ok()) return resolver_data.status(); + // Apply service config to call. + absl::Status status = self->ApplyServiceConfigToCall( + *resolver_data->config_selector, + unstarted_handler.UnprocessedClientInitialMetadata()); + if (!status.ok()) return status; + // If the call was queued, add trace annotation. + if (was_queued) { + auto* call_tracer = + MaybeGetContext(); + if (call_tracer != nullptr) { + call_tracer->RecordAnnotation( + "Delayed name resolution complete."); + } + } + // Start the call on the destination provided by the + // resolver. + resolver_data->call_destination->StartCall( + std::move(unstarted_handler)); + return absl::OkStatus(); + }); + }); + // Return the initiator. + return std::move(call.initiator); +} + +void ClientChannel::CreateResolverLocked() { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, "client_channel=%p: starting name resolution for %s", + this, uri_to_resolve_.c_str()); + } + resolver_ = CoreConfiguration::Get().resolver_registry().CreateResolver( + uri_to_resolve_, channel_args_, nullptr, work_serializer_, + std::make_unique(RefAsSubclass())); + // Since the validity of the args was checked when the channel was created, + // CreateResolver() must return a non-null result. + CHECK(resolver_ != nullptr); + UpdateStateLocked(GRPC_CHANNEL_CONNECTING, absl::Status(), + "started resolving"); + resolver_->StartLocked(); + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, "client_channel=%p: created resolver=%p", this, + resolver_.get()); + } +} + +void ClientChannel::DestroyResolverAndLbPolicyLocked() { + if (resolver_ != nullptr) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, "client_channel=%p: shutting down resolver=%p", this, + resolver_.get()); + } + resolver_.reset(); + saved_service_config_.reset(); + saved_config_selector_.reset(); + resolver_data_for_calls_.Set(ResolverDataForCalls{nullptr, nullptr}); + // Clear LB policy if set. + if (lb_policy_ != nullptr) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, "client_channel=%p: shutting down lb_policy=%p", this, + lb_policy_.get()); + } + lb_policy_.reset(); + picker_.Set(nullptr); + } + } +} + +void ClientChannel::TryToConnectLocked() { + if (disconnect_error_.ok()) { + if (lb_policy_ != nullptr) { + lb_policy_->ExitIdleLocked(); + } else if (resolver_ == nullptr) { + CreateResolverLocked(); + } + } +} + +namespace { + +RefCountedPtr ChooseLbPolicy( + const Resolver::Result& resolver_result, + const internal::ClientChannelGlobalParsedConfig* parsed_service_config) { + // Prefer the LB policy config found in the service config. + if (parsed_service_config->parsed_lb_config() != nullptr) { + return parsed_service_config->parsed_lb_config(); + } + // Try the deprecated LB policy name from the service config. + // If not, try the setting from channel args. + absl::optional policy_name; + if (!parsed_service_config->parsed_deprecated_lb_policy().empty()) { + policy_name = parsed_service_config->parsed_deprecated_lb_policy(); + } else { + policy_name = resolver_result.args.GetString(GRPC_ARG_LB_POLICY_NAME); + bool requires_config = false; + if (policy_name.has_value() && + (!CoreConfiguration::Get() + .lb_policy_registry() + .LoadBalancingPolicyExists(*policy_name, &requires_config) || + requires_config)) { + if (requires_config) { + gpr_log(GPR_ERROR, + "LB policy: %s passed through channel_args must not " + "require a config. Using pick_first instead.", + std::string(*policy_name).c_str()); + } else { + gpr_log(GPR_ERROR, + "LB policy: %s passed through channel_args does not exist. " + "Using pick_first instead.", + std::string(*policy_name).c_str()); + } + policy_name = "pick_first"; + } + } + // Use pick_first if nothing was specified and we didn't select grpclb + // above. + if (!policy_name.has_value()) policy_name = "pick_first"; + // Now that we have the policy name, construct an empty config for it. + Json config_json = Json::FromArray({Json::FromObject({ + {std::string(*policy_name), Json::FromObject({})}, + })}); + auto lb_policy_config = + CoreConfiguration::Get().lb_policy_registry().ParseLoadBalancingConfig( + config_json); + // The policy name came from one of three places: + // - The deprecated loadBalancingPolicy field in the service config, + // in which case the code in ClientChannelServiceConfigParser + // already verified that the policy does not require a config. + // - One of the hard-coded values here, all of which are known to not + // require a config. + // - A channel arg, in which case we check that the specified policy exists + // and accepts an empty config. If not, we revert to using pick_first + // lb_policy + CHECK_OK(lb_policy_config); + return std::move(*lb_policy_config); +} + +} // namespace + +void ClientChannel::OnResolverResultChangedLocked(Resolver::Result result) { + // Handle race conditions. + if (resolver_ == nullptr) return; + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, "client_channel=%p: got resolver result", this); + } + // Grab resolver result health callback. + auto resolver_callback = std::move(result.result_health_callback); + absl::Status resolver_result_status; + // We only want to trace the address resolution in the follow cases: + // (a) Address resolution resulted in service config change. + // (b) Address resolution that causes number of backends to go from + // zero to non-zero. + // (c) Address resolution that causes number of backends to go from + // non-zero to zero. + // (d) Address resolution that causes a new LB policy to be created. + // + // We track a list of strings to eventually be concatenated and traced. + std::vector trace_strings; + const bool resolution_contains_addresses = + result.addresses.ok() && !result.addresses->empty(); + if (!resolution_contains_addresses && + previous_resolution_contained_addresses_) { + trace_strings.push_back("Address list became empty"); + } else if (resolution_contains_addresses && + !previous_resolution_contained_addresses_) { + trace_strings.push_back("Address list became non-empty"); + } + previous_resolution_contained_addresses_ = resolution_contains_addresses; + std::string service_config_error_string_storage; + if (!result.service_config.ok()) { + service_config_error_string_storage = + result.service_config.status().ToString(); + trace_strings.push_back(service_config_error_string_storage.c_str()); + } + // Choose the service config. + RefCountedPtr service_config; + RefCountedPtr config_selector; + if (!result.service_config.ok()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, + "client_channel=%p: resolver returned service config error: %s", + this, result.service_config.status().ToString().c_str()); + } + // If the service config was invalid, then fallback to the + // previously returned service config, if any. + if (saved_service_config_ != nullptr) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, + "client_channel=%p: resolver returned invalid service config; " + "continuing to use previous service config", + this); + } + service_config = saved_service_config_; + config_selector = saved_config_selector_; + } else { + // We received a service config error and we don't have a + // previous service config to fall back to. Put the channel into + // TRANSIENT_FAILURE. + OnResolverErrorLocked(result.service_config.status()); + trace_strings.push_back("no valid service config"); + resolver_result_status = + absl::UnavailableError("no valid service config"); + } + } else if (*result.service_config == nullptr) { + // Resolver did not return any service config. + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, + "client_channel=%p: resolver returned no service config; " + "using default service config for channel", + this); + } + service_config = default_service_config_; + } else { + // Use ServiceConfig and ConfigSelector returned by resolver. + service_config = std::move(*result.service_config); + config_selector = result.args.GetObjectRef(); + } + // Note: The only case in which service_config is null here is if the + // resolver returned a service config error and we don't have a previous + // service config to fall back to. + if (service_config != nullptr) { + // Extract global config for client channel. + const internal::ClientChannelGlobalParsedConfig* parsed_service_config = + static_cast( + service_config->GetGlobalParsedConfig( + service_config_parser_index_)); + // Choose LB policy config. + RefCountedPtr lb_policy_config = + ChooseLbPolicy(result, parsed_service_config); + // Check if the ServiceConfig has changed. + const bool service_config_changed = + saved_service_config_ == nullptr || + service_config->json_string() != saved_service_config_->json_string(); + // Check if the ConfigSelector has changed. + const bool config_selector_changed = !ConfigSelector::Equals( + saved_config_selector_.get(), config_selector.get()); + // If either has changed, apply the global parameters now. + if (service_config_changed || config_selector_changed) { + // Update service config in control plane. + UpdateServiceConfigInControlPlaneLocked( + std::move(service_config), std::move(config_selector), + std::string(lb_policy_config->name())); + // TODO(ncteisen): might be worth somehow including a snippet of the + // config in the trace, at the risk of bloating the trace logs. + trace_strings.push_back("Service config changed"); + } else if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, "client_channel=%p: service config not changed", this); + } + // Create or update LB policy, as needed. + resolver_result_status = CreateOrUpdateLbPolicyLocked( + std::move(lb_policy_config), + parsed_service_config->health_check_service_name(), std::move(result)); + // Start using new service config for calls. + // This needs to happen after the LB policy has been updated, since + // the ConfigSelector may need the LB policy to know about new + // destinations before it can send RPCs to those destinations. + if (service_config_changed || config_selector_changed) { + UpdateServiceConfigInDataPlaneLocked(); + } + } + // Invoke resolver callback if needed. + if (resolver_callback != nullptr) { + resolver_callback(std::move(resolver_result_status)); + } + // Add channel trace event. + if (!trace_strings.empty()) { + std::string message = + absl::StrCat("Resolution event: ", absl::StrJoin(trace_strings, ", ")); + if (channelz_node_ != nullptr) { + channelz_node_->AddTraceEvent(channelz::ChannelTrace::Severity::Info, + grpc_slice_from_cpp_string(message)); + } + } +} + +void ClientChannel::OnResolverErrorLocked(absl::Status status) { + if (resolver_ == nullptr) return; + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, "client_channel=%p: resolver transient failure: %s", this, + status.ToString().c_str()); + } + // If we already have an LB policy from a previous resolution + // result, then we continue to let it set the connectivity state. + // Otherwise, we go into TRANSIENT_FAILURE. + if (lb_policy_ == nullptr) { + // Update connectivity state. + UpdateStateLocked(GRPC_CHANNEL_TRANSIENT_FAILURE, status, + "resolver failure"); + // Send updated resolver result. + resolver_data_for_calls_.Set( + MaybeRewriteIllegalStatusCode(status, "resolver")); + } +} + +absl::Status ClientChannel::CreateOrUpdateLbPolicyLocked( + RefCountedPtr lb_policy_config, + const absl::optional& health_check_service_name, + Resolver::Result result) { + // Construct update. + LoadBalancingPolicy::UpdateArgs update_args; + 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 + // unnecessary refs that cause it to be destroyed somewhere other than in the + // WorkSerializer. + update_args.args = result.args.Remove(GRPC_ARG_CONFIG_SELECTOR); + // Add health check service name to channel args. + if (health_check_service_name.has_value()) { + update_args.args = update_args.args.Set(GRPC_ARG_HEALTH_CHECK_SERVICE_NAME, + *health_check_service_name); + } + // Create policy if needed. + if (lb_policy_ == nullptr) { + lb_policy_ = CreateLbPolicyLocked(update_args.args); + } + // Update the policy. + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, "client_channel=%p: Updating child policy %p", this, + lb_policy_.get()); + } + return lb_policy_->UpdateLocked(std::move(update_args)); +} + +// Creates a new LB policy. +OrphanablePtr ClientChannel::CreateLbPolicyLocked( + const ChannelArgs& args) { + // The LB policy will start in state CONNECTING but will not + // necessarily send us an update synchronously, so set state to + // CONNECTING (in case the resolver had previously failed and put the + // channel into TRANSIENT_FAILURE) and make sure we have a queueing picker. + UpdateStateAndPickerLocked( + GRPC_CHANNEL_CONNECTING, absl::Status(), "started resolving", + MakeRefCounted(nullptr)); + // Now create the LB policy. + LoadBalancingPolicy::Args lb_policy_args; + lb_policy_args.work_serializer = work_serializer_; + lb_policy_args.channel_control_helper = + std::make_unique( + RefAsSubclass()); + lb_policy_args.args = args; + OrphanablePtr lb_policy = + MakeOrphanable(std::move(lb_policy_args), + &grpc_client_channel_trace); + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, "client_channel=%p: created new LB policy %p", this, + lb_policy.get()); + } + return lb_policy; +} + +void ClientChannel::UpdateServiceConfigInControlPlaneLocked( + RefCountedPtr service_config, + RefCountedPtr config_selector, std::string lb_policy_name) { + std::string service_config_json(service_config->json_string()); + // Update service config. + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, "client_channel=%p: using service config: \"%s\"", this, + service_config_json.c_str()); + } + saved_service_config_ = std::move(service_config); + // Update config selector. + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, "client_channel=%p: using ConfigSelector %p", this, + config_selector.get()); + } + saved_config_selector_ = std::move(config_selector); + // Update the data used by GetChannelInfo(). + { + MutexLock lock(&info_mu_); + info_lb_policy_name_ = std::move(lb_policy_name); + info_service_config_json_ = std::move(service_config_json); + } +} + +void ClientChannel::UpdateServiceConfigInDataPlaneLocked() { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, "client_channel=%p: switching to ConfigSelector %p", this, + saved_config_selector_.get()); + } + // Use default config selector if resolver didn't supply one. + RefCountedPtr config_selector = saved_config_selector_; + if (config_selector == nullptr) { + config_selector = + MakeRefCounted(saved_service_config_); + } + // Construct filter stack. + InterceptionChainBuilder builder(channel_args_.SetObject(this)); + if (idle_timeout_ != Duration::Zero()) { + builder.AddOnServerTrailingMetadata([this](ServerMetadata&) { + if (idle_state_.DecreaseCallCount()) StartIdleTimer(); + }); + } + CoreConfiguration::Get().channel_init().AddToInterceptionChainBuilder( + GRPC_CLIENT_CHANNEL, builder); + // TODO(roth): add filters returned by config selector + // Create call destination. + const bool enable_retries = + !channel_args_.WantMinimalStack() && + channel_args_.GetBool(GRPC_ARG_ENABLE_RETRIES).value_or(true); + if (enable_retries) { + Crash("call v3 stack does not yet support retries"); + } + auto top_of_stack_call_destination = builder.Build(call_destination_); + // Send result to data plane. + if (!top_of_stack_call_destination.ok()) { + resolver_data_for_calls_.Set(MaybeRewriteIllegalStatusCode( + top_of_stack_call_destination.status(), "channel construction")); + } else { + resolver_data_for_calls_.Set(ResolverDataForCalls{ + std::move(config_selector), std::move(*top_of_stack_call_destination)}); + } +} + +void ClientChannel::UpdateStateLocked(grpc_connectivity_state state, + const absl::Status& status, + const char* reason) { + if (state != GRPC_CHANNEL_SHUTDOWN && + state_tracker_.state() == GRPC_CHANNEL_SHUTDOWN) { + Crash("Illegal transition SHUTDOWN -> anything"); + } + state_tracker_.SetState(state, status, reason); + if (channelz_node_ != nullptr) { + channelz_node_->SetConnectivityState(state); + channelz_node_->AddTraceEvent( + channelz::ChannelTrace::Severity::Info, + grpc_slice_from_static_string( + channelz::ChannelNode::GetChannelConnectivityStateChangeString( + state))); + } +} + +void ClientChannel::UpdateStateAndPickerLocked( + grpc_connectivity_state state, const absl::Status& status, + const char* reason, + RefCountedPtr picker) { + UpdateStateLocked(state, status, reason); + picker_.Set(std::move(picker)); +} + +void ClientChannel::StartIdleTimer() { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { + gpr_log(GPR_INFO, "client_channel=%p: idle timer started", this); + } + auto self = RefAsSubclass(); + auto promise = Loop([self]() { + return TrySeq(Sleep(Timestamp::Now() + self->idle_timeout_), + [self]() -> Poll> { + if (self->idle_state_.CheckTimer()) { + return Continue{}; + } else { + return absl::OkStatus(); + } + }); + }); + idle_activity_.Set(MakeActivity( + std::move(promise), ExecCtxWakeupScheduler{}, + [self = std::move(self)](absl::Status status) mutable { + if (status.ok()) { + self->work_serializer_->Run( + [self]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*self->work_serializer_) { + self->DestroyResolverAndLbPolicyLocked(); + self->UpdateStateAndPickerLocked( + GRPC_CHANNEL_IDLE, absl::OkStatus(), + "channel entering IDLE", nullptr); + // TODO(roth): In case there's a race condition, we + // might need to check for any calls that are queued + // waiting for a resolver result or an LB pick. + }, + DEBUG_LOCATION); + } + }, + GetContext())); +} + +absl::Status ClientChannel::ApplyServiceConfigToCall( + ConfigSelector& config_selector, + ClientMetadata& client_initial_metadata) const { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { + gpr_log(GPR_INFO, "client_channel=%p: %sapplying service config to call", + this, GetContext()->DebugTag().c_str()); + } + // Create a ClientChannelServiceConfigCallData for the call. This stores + // a ref to the ServiceConfig and caches the right set of parsed configs + // to use for the call. The ClientChannelServiceConfigCallData will store + // itself in the call context, so that it can be accessed by filters + // below us in the stack, and it will be cleaned up when the call ends. + auto* service_config_call_data = + GetContext()->New( + GetContext(), GetContext()); + // Use the ConfigSelector to determine the config for the call. + absl::Status call_config_status = config_selector.GetCallConfig( + {&client_initial_metadata, GetContext(), + service_config_call_data}); + if (!call_config_status.ok()) { + return MaybeRewriteIllegalStatusCode(call_config_status, "ConfigSelector"); + } + // Apply our own method params to the call. + auto* method_params = static_cast( + service_config_call_data->GetMethodParsedConfig( + service_config_parser_index_)); + if (method_params != nullptr) { + // If the service config specifies a deadline, update the call's + // deadline timer. + if (method_params->timeout() != Duration::Zero()) { + Call* call = GetContext(); + const Timestamp per_method_deadline = + Timestamp::FromCycleCounterRoundUp(call->start_time()) + + method_params->timeout(); + call->UpdateDeadline(per_method_deadline); + } + // If the service config set wait_for_ready and the application + // did not explicitly set it, use the value from the service config. + auto* wait_for_ready = + client_initial_metadata.GetOrCreatePointer(WaitForReady()); + if (method_params->wait_for_ready().has_value() && + !wait_for_ready->explicitly_set) { + wait_for_ready->value = method_params->wait_for_ready().value(); + } + } + return absl::OkStatus(); +} + +} // namespace grpc_core diff --git a/src/core/client_channel/client_channel.h b/src/core/client_channel/client_channel.h new file mode 100644 index 00000000000..abe53bbf689 --- /dev/null +++ b/src/core/client_channel/client_channel.h @@ -0,0 +1,243 @@ +// +// 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. +// + +#ifndef GRPC_SRC_CORE_CLIENT_CHANNEL_CLIENT_CHANNEL_H +#define GRPC_SRC_CORE_CLIENT_CHANNEL_CLIENT_CHANNEL_H + +#include + +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/string_view.h" + +#include "src/core/client_channel/client_channel_factory.h" +#include "src/core/client_channel/config_selector.h" +#include "src/core/client_channel/subchannel.h" +#include "src/core/ext/filters/channel_idle/idle_filter_state.h" +#include "src/core/lib/gprpp/single_set_ptr.h" +#include "src/core/lib/promise/observable.h" +#include "src/core/lib/surface/channel.h" +#include "src/core/lib/transport/metadata.h" +#include "src/core/load_balancing/lb_policy.h" +#include "src/core/resolver/resolver.h" +#include "src/core/service_config/service_config.h" + +namespace grpc_core { + +class ClientChannel : public Channel { + public: + using PickerObservable = + Observable>; + + class CallDestinationFactory { + public: + struct RawPointerChannelArgTag {}; + + static absl::string_view ChannelArgName() { + return "grpc.internal.client_channel_call_destination"; + } + + virtual RefCountedPtr CreateCallDestination( + PickerObservable) = 0; + + protected: + ~CallDestinationFactory() = default; + }; + + static absl::StatusOr> Create( + std::string target, ChannelArgs channel_args); + + // Do not instantiate directly -- use Create() instead. + ClientChannel(std::string target_uri, ChannelArgs args, + std::string uri_to_resolve, + RefCountedPtr default_service_config, + ClientChannelFactory* client_channel_factory, + CallDestinationFactory* call_destination_factory); + + ~ClientChannel() override; + + void Orphan() override; + + grpc_call* CreateCall(grpc_call* parent_call, uint32_t propagation_mask, + grpc_completion_queue* cq, + grpc_pollset_set* /*pollset_set_alternative*/, + Slice path, absl::optional authority, + Timestamp deadline, bool registered_method) override; + + CallInitiator CreateCall(ClientMetadataHandle client_initial_metadata); + + grpc_event_engine::experimental::EventEngine* event_engine() const override { + return event_engine_.get(); + } + + // TODO(ctiller): lame channels + bool IsLame() const override { return false; } + + bool SupportsConnectivityWatcher() const override { return true; } + + // Returns the current connectivity state. If try_to_connect is true, + // triggers a connection attempt if not already connected. + grpc_connectivity_state CheckConnectivityState(bool try_to_connect) override; + + void WatchConnectivityState(grpc_connectivity_state last_observed_state, + Timestamp deadline, grpc_completion_queue* cq, + void* tag) override; + + // Starts and stops a connectivity watch. The watcher will be initially + // notified as soon as the state changes from initial_state and then on + // every subsequent state change until either the watch is stopped or + // it is notified that the state has changed to SHUTDOWN. + // + // This is intended to be used when starting watches from code inside of + // C-core (e.g., for a nested control plane channel for things like xds). + void AddConnectivityWatcher( + grpc_connectivity_state initial_state, + OrphanablePtr watcher) override; + void RemoveConnectivityWatcher( + AsyncConnectivityStateWatcherInterface* watcher) override; + + void GetInfo(const grpc_channel_info* channel_info) override; + + void ResetConnectionBackoff() override; + + void Ping(grpc_completion_queue* cq, void* tag) override; + + // Flag that this object gets stored in channel args as a raw pointer. + struct RawPointerChannelArgTag {}; + static absl::string_view ChannelArgName() { + return "grpc.internal.client_channel"; + } + + private: + class ClientChannelControlHelper; + class ResolverResultHandler; + class SubchannelWrapper; + + void CreateResolverLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*work_serializer_); + void DestroyResolverAndLbPolicyLocked() + ABSL_EXCLUSIVE_LOCKS_REQUIRED(*work_serializer_); + + void TryToConnectLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*work_serializer_); + + void OnResolverResultChangedLocked(Resolver::Result result) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(*work_serializer_); + void OnResolverErrorLocked(absl::Status status) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(*work_serializer_); + + absl::Status CreateOrUpdateLbPolicyLocked( + RefCountedPtr lb_policy_config, + const absl::optional& health_check_service_name, + Resolver::Result result) ABSL_EXCLUSIVE_LOCKS_REQUIRED(*work_serializer_); + OrphanablePtr CreateLbPolicyLocked( + const ChannelArgs& args) ABSL_EXCLUSIVE_LOCKS_REQUIRED(*work_serializer_); + + void UpdateServiceConfigInControlPlaneLocked( + RefCountedPtr service_config, + RefCountedPtr config_selector, std::string lb_policy_name) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(*work_serializer_); + + void UpdateServiceConfigInDataPlaneLocked() + ABSL_EXCLUSIVE_LOCKS_REQUIRED(*work_serializer_); + + void UpdateStateLocked(grpc_connectivity_state state, + const absl::Status& status, const char* reason) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(*work_serializer_); + + void UpdateStateAndPickerLocked( + grpc_connectivity_state state, const absl::Status& status, + const char* reason, + RefCountedPtr picker) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(*work_serializer_); + + void StartIdleTimer(); + + // Applies service config settings from config_selector to the call. + // May modify call context and client_initial_metadata. + absl::Status ApplyServiceConfigToCall( + ConfigSelector& config_selector, + ClientMetadata& client_initial_metadata) const; + + const ChannelArgs channel_args_; + const std::shared_ptr + event_engine_; + const std::string uri_to_resolve_; + const size_t service_config_parser_index_; + const RefCountedPtr default_service_config_; + ClientChannelFactory* const client_channel_factory_; + const std::string default_authority_; + channelz::ChannelNode* const channelz_node_; + GlobalStatsPluginRegistry::StatsPluginGroup stats_plugin_group_; + + // + // Idleness state. + // + const Duration idle_timeout_; + IdleFilterState idle_state_{false}; + SingleSetPtr idle_activity_; + + // + // Fields related to name resolution. + // + struct ResolverDataForCalls { + RefCountedPtr config_selector; + RefCountedPtr call_destination; + }; + Observable> resolver_data_for_calls_; + + // + // Fields related to LB picks. + // + PickerObservable picker_; + const RefCountedPtr call_destination_; + + // + // Fields used in the control plane. Guarded by work_serializer. + // + std::shared_ptr work_serializer_; + ConnectivityStateTracker state_tracker_ ABSL_GUARDED_BY(*work_serializer_); + OrphanablePtr resolver_ ABSL_GUARDED_BY(*work_serializer_); + bool previous_resolution_contained_addresses_ + ABSL_GUARDED_BY(*work_serializer_) = false; + RefCountedPtr saved_service_config_ + ABSL_GUARDED_BY(*work_serializer_); + RefCountedPtr saved_config_selector_ + ABSL_GUARDED_BY(*work_serializer_); + OrphanablePtr lb_policy_ + ABSL_GUARDED_BY(*work_serializer_); + RefCountedPtr subchannel_pool_ + ABSL_GUARDED_BY(*work_serializer_); + // The number of SubchannelWrapper instances referencing a given Subchannel. + std::map subchannel_refcount_map_ + ABSL_GUARDED_BY(*work_serializer_); + // The set of SubchannelWrappers that currently exist. + // No need to hold a ref, since the set is updated in the control-plane + // work_serializer when the SubchannelWrappers are created and destroyed. + absl::flat_hash_set subchannel_wrappers_ + ABSL_GUARDED_BY(*work_serializer_); + int keepalive_time_ ABSL_GUARDED_BY(*work_serializer_) = -1; + absl::Status disconnect_error_ ABSL_GUARDED_BY(*work_serializer_); + + // + // Fields accessed via GetChannelInfo(). + // + Mutex info_mu_; + std::string info_lb_policy_name_ ABSL_GUARDED_BY(info_mu_); + std::string info_service_config_json_ ABSL_GUARDED_BY(info_mu_); +}; + +} // namespace grpc_core + +#endif // GRPC_SRC_CORE_CLIENT_CHANNEL_CLIENT_CHANNEL_H diff --git a/src/core/client_channel/client_channel_filter.cc b/src/core/client_channel/client_channel_filter.cc index 3cb76ff8409..f0c58c1580f 100644 --- a/src/core/client_channel/client_channel_filter.cc +++ b/src/core/client_channel/client_channel_filter.cc @@ -1109,7 +1109,7 @@ class ClientChannelFilter::ClientChannelControlHelper final const ChannelArgs& args) override ABSL_EXCLUSIVE_LOCKS_REQUIRED(*chand_->work_serializer_) { if (chand_->resolver_ == nullptr) return nullptr; // Shutting down. - ChannelArgs subchannel_args = ClientChannelFilter::MakeSubchannelArgs( + ChannelArgs subchannel_args = Subchannel::MakeSubchannelArgs( args, per_address_args, chand_->subchannel_pool_, chand_->default_authority_); // Create subchannel. @@ -1359,31 +1359,6 @@ ClientChannelFilter::CreateLoadBalancedCallPromise( return call_ptr->MakeCallPromise(std::move(call_args), std::move(lb_call)); } -ChannelArgs ClientChannelFilter::MakeSubchannelArgs( - const ChannelArgs& channel_args, const ChannelArgs& address_args, - const RefCountedPtr& subchannel_pool, - const std::string& channel_default_authority) { - // Note that we start with the channel-level args and then apply the - // per-address args, so that if a value is present in both, the one - // in the channel-level args is used. This is particularly important - // for the GRPC_ARG_DEFAULT_AUTHORITY arg, which we want to allow - // resolvers to set on a per-address basis only if the application - // did not explicitly set it at the channel level. - return channel_args.UnionWith(address_args) - .SetObject(subchannel_pool) - // If we haven't already set the default authority arg (i.e., it - // was not explicitly set by the application nor overridden by - // the resolver), add it from the channel's default. - .SetIfUnset(GRPC_ARG_DEFAULT_AUTHORITY, channel_default_authority) - // Remove channel args that should not affect subchannel - // uniqueness. - .Remove(GRPC_ARG_HEALTH_CHECK_SERVICE_NAME) - .Remove(GRPC_ARG_INHIBIT_HEALTH_CHECKING) - .Remove(GRPC_ARG_CHANNELZ_CHANNEL_NODE) - // Remove all keys with the no-subchannel prefix. - .RemoveAllKeysWithPrefix(GRPC_ARG_NO_SUBCHANNEL_PREFIX); -} - void ClientChannelFilter::ReprocessQueuedResolverCalls() { for (CallData* calld : resolver_queued_calls_) { calld->RemoveCallFromResolverQueuedCallsLocked(); diff --git a/src/core/client_channel/client_channel_filter.h b/src/core/client_channel/client_channel_filter.h index 5bbafc68d68..9233c846c6f 100644 --- a/src/core/client_channel/client_channel_filter.h +++ b/src/core/client_channel/client_channel_filter.h @@ -86,9 +86,6 @@ // Channel arg key for server URI string. #define GRPC_ARG_SERVER_URI "grpc.server_uri" -// Channel arg containing a pointer to the ClientChannelFilter object. -#define GRPC_ARG_CLIENT_CHANNEL "grpc.internal.client_channel_filter" - // Max number of batches that can be pending on a call at any given // time. This includes one batch for each of the following ops: // recv_initial_metadata @@ -112,7 +109,9 @@ class ClientChannelFilter final { // Flag that this object gets stored in channel args as a raw pointer. struct RawPointerChannelArgTag {}; - static absl::string_view ChannelArgName() { return GRPC_ARG_CLIENT_CHANNEL; } + static absl::string_view ChannelArgName() { + return "grpc.internal.client_channel_filter"; + } static ArenaPromise MakeCallPromise( grpc_channel_element* elem, CallArgs call_args, @@ -166,12 +165,6 @@ class ClientChannelFilter final { CallArgs call_args, absl::AnyInvocable on_commit, bool is_transparent_retry); - // Exposed for testing only. - static ChannelArgs MakeSubchannelArgs( - const ChannelArgs& channel_args, const ChannelArgs& address_args, - const RefCountedPtr& subchannel_pool, - const std::string& channel_default_authority); - private: class CallData; class FilterBasedCallData; diff --git a/src/core/client_channel/client_channel_internal.h b/src/core/client_channel/client_channel_internal.h index a2c759ec7d6..b4d204834ab 100644 --- a/src/core/client_channel/client_channel_internal.h +++ b/src/core/client_channel/client_channel_internal.h @@ -29,6 +29,7 @@ #include "src/core/lib/channel/context.h" #include "src/core/lib/gprpp/unique_type_name.h" #include "src/core/lib/resource_quota/arena.h" +#include "src/core/lib/transport/call_destination.h" #include "src/core/load_balancing/lb_policy.h" #include "src/core/service_config/service_config_call_data.h" #include "src/core/telemetry/call_tracer.h" @@ -75,6 +76,13 @@ class ClientChannelServiceConfigCallData final : public ServiceConfigCallData { absl::AnyInvocable on_commit_; }; +class SubchannelInterfaceWithCallDestination : public SubchannelInterface { + public: + using SubchannelInterface::SubchannelInterface; + // Obtain the call destination for this subchannel. + virtual RefCountedPtr call_destination() = 0; +}; + } // namespace grpc_core #endif // GRPC_SRC_CORE_CLIENT_CHANNEL_CLIENT_CHANNEL_INTERNAL_H diff --git a/src/core/client_channel/load_balanced_call_destination.cc b/src/core/client_channel/load_balanced_call_destination.cc new file mode 100644 index 00000000000..4d702a5858c --- /dev/null +++ b/src/core/client_channel/load_balanced_call_destination.cc @@ -0,0 +1,335 @@ +// Copyright 2024 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "src/core/client_channel/load_balanced_call_destination.h" + +#include "src/core/client_channel/client_channel.h" +#include "src/core/client_channel/client_channel_internal.h" +#include "src/core/client_channel/subchannel.h" +#include "src/core/lib/channel/status_util.h" +#include "src/core/lib/promise/loop.h" +#include "src/core/telemetry/call_tracer.h" + +namespace grpc_core { + +// Defined in legacy client channel filter. +// TODO(roth): Move these here when we remove the legacy filter. +extern TraceFlag grpc_client_channel_trace; +extern TraceFlag grpc_client_channel_call_trace; +extern TraceFlag grpc_client_channel_lb_call_trace; + +namespace { + +class LbMetadata : public LoadBalancingPolicy::MetadataInterface { + public: + explicit LbMetadata(grpc_metadata_batch* batch) : batch_(batch) {} + + void Add(absl::string_view key, absl::string_view value) override { + if (batch_ == nullptr) return; + // Gross, egregious hack to support legacy grpclb behavior. + // TODO(ctiller): Use a promise context for this once that plumbing is done. + if (key == GrpcLbClientStatsMetadata::key()) { + batch_->Set( + GrpcLbClientStatsMetadata(), + const_cast( + reinterpret_cast(value.data()))); + return; + } + batch_->Append(key, Slice::FromStaticString(value), + [key](absl::string_view error, const Slice& value) { + gpr_log(GPR_ERROR, "%s", + absl::StrCat(error, " key:", key, + " value:", value.as_string_view()) + .c_str()); + }); + } + + std::vector> TestOnlyCopyToVector() + override { + if (batch_ == nullptr) return {}; + Encoder encoder; + batch_->Encode(&encoder); + return encoder.Take(); + } + + absl::optional Lookup(absl::string_view key, + std::string* buffer) const override { + if (batch_ == nullptr) return absl::nullopt; + return batch_->GetStringValue(key, buffer); + } + + private: + class Encoder { + public: + void Encode(const Slice& key, const Slice& value) { + out_.emplace_back(std::string(key.as_string_view()), + std::string(value.as_string_view())); + } + + template + void Encode(Which, const typename Which::ValueType& value) { + auto value_slice = Which::Encode(value); + out_.emplace_back(std::string(Which::key()), + std::string(value_slice.as_string_view())); + } + + void Encode(GrpcTimeoutMetadata, + const typename GrpcTimeoutMetadata::ValueType&) {} + void Encode(HttpPathMetadata, const Slice&) {} + void Encode(HttpMethodMetadata, + const typename HttpMethodMetadata::ValueType&) {} + + std::vector> Take() { + return std::move(out_); + } + + private: + std::vector> out_; + }; + + grpc_metadata_batch* batch_; +}; + +void MaybeCreateCallAttemptTracer(bool is_transparent_retry) { + auto* call_tracer = MaybeGetContext(); + if (call_tracer == nullptr) return; + auto* tracer = call_tracer->StartNewAttempt(is_transparent_retry); + SetContext(tracer); +} + +class LbCallState : public ClientChannelLbCallState { + public: + void* Alloc(size_t size) override { return GetContext()->Alloc(size); } + + // Internal API to allow first-party LB policies to access per-call + // attributes set by the ConfigSelector. + ServiceConfigCallData::CallAttributeInterface* GetCallAttribute( + UniqueTypeName type) const override { + auto* service_config_call_data = GetContext(); + return service_config_call_data->GetCallAttribute(type); + } + + ClientCallTracer::CallAttemptTracer* GetCallAttemptTracer() const override { + auto* legacy_context = GetContext(); + return static_cast( + legacy_context[GRPC_CONTEXT_CALL_TRACER].value); + } +}; + +// TODO(roth): Remove this in favor of the gprpp Match() function once +// we can do that without breaking lock annotations. +template +T HandlePickResult( + LoadBalancingPolicy::PickResult* result, + std::function complete_func, + std::function queue_func, + std::function fail_func, + std::function drop_func) { + auto* complete_pick = + absl::get_if(&result->result); + if (complete_pick != nullptr) { + return complete_func(complete_pick); + } + auto* queue_pick = + absl::get_if(&result->result); + if (queue_pick != nullptr) { + return queue_func(queue_pick); + } + auto* fail_pick = + absl::get_if(&result->result); + if (fail_pick != nullptr) { + return fail_func(fail_pick); + } + auto* drop_pick = + absl::get_if(&result->result); + CHECK(drop_pick != nullptr); + return drop_func(drop_pick); +} + +// Does an LB pick for a call. Returns one of the following things: +// - Continue{}, meaning to queue the pick +// - a non-OK status, meaning to fail the call +// - a call destination, meaning that the pick is complete +// When the pick is complete, pushes client_initial_metadata onto +// call_initiator. Also adds the subchannel call tracker (if any) to +// context. +LoopCtl>> PickSubchannel( + LoadBalancingPolicy::SubchannelPicker& picker, + UnstartedCallHandler& unstarted_handler) { + // Perform LB pick. + auto& client_initial_metadata = + unstarted_handler.UnprocessedClientInitialMetadata(); + LoadBalancingPolicy::PickArgs pick_args; + Slice* path = client_initial_metadata.get_pointer(HttpPathMetadata()); + CHECK(path != nullptr); + pick_args.path = path->as_string_view(); + LbCallState lb_call_state; + pick_args.call_state = &lb_call_state; + LbMetadata initial_metadata(&client_initial_metadata); + pick_args.initial_metadata = &initial_metadata; + auto result = picker.Pick(pick_args); + // Handle result. + return HandlePickResult< + LoopCtl>>>( + &result, + // CompletePick + [&](LoadBalancingPolicy::PickResult::Complete* complete_pick) + -> LoopCtl>> { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_lb_call_trace)) { + gpr_log(GPR_INFO, + "client_channel: %sLB pick succeeded: subchannel=%p", + GetContext()->DebugTag().c_str(), + complete_pick->subchannel.get()); + } + CHECK(complete_pick->subchannel != nullptr); + // Grab a ref to the call destination while we're still + // holding the data plane mutex. + auto call_destination = + DownCast( + complete_pick->subchannel.get()) + ->call_destination(); + // If the subchannel has no call destination (e.g., if the + // subchannel has moved out of state READY but the LB policy hasn't + // yet seen that change and given us a new picker), then just + // queue the pick. We'll try again as soon as we get a new picker. + if (call_destination == nullptr) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_lb_call_trace)) { + gpr_log(GPR_INFO, + "client_channel: %ssubchannel returned by LB picker " + "has no connected subchannel; queueing pick", + GetContext()->DebugTag().c_str()); + } + return Continue{}; + } + // If the LB policy returned a call tracker, inform it that the + // call is starting and add it to context, so that we can notify + // it when the call finishes. + if (complete_pick->subchannel_call_tracker != nullptr) { + complete_pick->subchannel_call_tracker->Start(); + SetContext(complete_pick->subchannel_call_tracker.release()); + } + // Return the connected subchannel. + return call_destination; + }, + // QueuePick + [&](LoadBalancingPolicy::PickResult::Queue* /*queue_pick*/) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_lb_call_trace)) { + gpr_log(GPR_INFO, "client_channel: %sLB pick queued", + GetContext()->DebugTag().c_str()); + } + return Continue{}; + }, + // FailPick + [&](LoadBalancingPolicy::PickResult::Fail* fail_pick) + -> LoopCtl>> { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_lb_call_trace)) { + gpr_log(GPR_INFO, "client_channel: %sLB pick failed: %s", + GetContext()->DebugTag().c_str(), + fail_pick->status.ToString().c_str()); + } + // If wait_for_ready is false, then the error indicates the RPC + // attempt's final status. + if (!unstarted_handler.UnprocessedClientInitialMetadata() + .GetOrCreatePointer(WaitForReady()) + ->value) { + return MaybeRewriteIllegalStatusCode(std::move(fail_pick->status), + "LB pick"); + } + // If wait_for_ready is true, then queue to retry when we get a new + // picker. + return Continue{}; + }, + // DropPick + [&](LoadBalancingPolicy::PickResult::Drop* drop_pick) + -> LoopCtl>> { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_lb_call_trace)) { + gpr_log(GPR_INFO, "client_channel: %sLB pick dropped: %s", + GetContext()->DebugTag().c_str(), + drop_pick->status.ToString().c_str()); + } + return grpc_error_set_int(MaybeRewriteIllegalStatusCode( + std::move(drop_pick->status), "LB drop"), + StatusIntProperty::kLbPolicyDrop, 1); + }); +} + +} // namespace + +void LoadBalancedCallDestination::StartCall( + UnstartedCallHandler unstarted_handler) { + // If there is a call tracer, create a call attempt tracer. + bool* is_transparent_retry_metadata = + unstarted_handler.UnprocessedClientInitialMetadata().get_pointer( + IsTransparentRetry()); + bool is_transparent_retry = is_transparent_retry_metadata != nullptr + ? *is_transparent_retry_metadata + : false; + MaybeCreateCallAttemptTracer(is_transparent_retry); + // Spawn a promise to do the LB pick. + // This will eventually start the call. + unstarted_handler.SpawnGuardedUntilCallCompletes( + "lb_pick", [unstarted_handler, picker = picker_]() mutable { + return Map( + // Wait for the LB picker. + CheckDelayed(Loop( + [last_picker = + RefCountedPtr(), + unstarted_handler, picker]() mutable { + return Map( + picker.Next(last_picker), + [unstarted_handler, &last_picker]( + RefCountedPtr + picker) mutable { + last_picker = std::move(picker); + // Returns 3 possible things: + // - Continue to queue the pick + // - non-OK status to fail the pick + // - a connected subchannel to complete the pick + return PickSubchannel(*last_picker, unstarted_handler); + }); + })), + // Create call stack on the connected subchannel. + [unstarted_handler]( + std::tuple< + absl::StatusOr>, + bool> + pick_result) { + auto& call_destination = std::get<0>(pick_result); + const bool was_queued = std::get<1>(pick_result); + if (!call_destination.ok()) { + return call_destination.status(); + } + // LB pick is done, so indicate that we've committed. + auto* on_commit = MaybeGetContext(); + if (on_commit != nullptr && *on_commit != nullptr) { + (*on_commit)(); + } + // If it was queued, add a trace annotation. + if (was_queued) { + auto* tracer = + MaybeGetContext(); + if (tracer != nullptr) { + tracer->RecordAnnotation("Delayed LB pick complete."); + } + } + // Delegate to connected subchannel. + // TODO(ctiller): need to insert LbCallTracingFilter at the top of + // the stack + (*call_destination)->StartCall(unstarted_handler); + return absl::OkStatus(); + }); + }); +} + +} // namespace grpc_core \ No newline at end of file diff --git a/src/core/client_channel/load_balanced_call_destination.h b/src/core/client_channel/load_balanced_call_destination.h new file mode 100644 index 00000000000..2adbdbe3dc3 --- /dev/null +++ b/src/core/client_channel/load_balanced_call_destination.h @@ -0,0 +1,49 @@ +// Copyright 2024 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_CLIENT_CHANNEL_LOAD_BALANCED_CALL_DESTINATION_H +#define GRPC_SRC_CORE_CLIENT_CHANNEL_LOAD_BALANCED_CALL_DESTINATION_H + +#include "absl/functional/any_invocable.h" + +#include "src/core/client_channel/client_channel.h" +#include "src/core/lib/promise/context.h" +#include "src/core/lib/transport/call_destination.h" +#include "src/core/load_balancing/lb_policy.h" + +namespace grpc_core { + +// Context type for LB on_commit callback. +// TODO(ctiller): make this a struct, so we don't accidentally alias context +// types +using LbOnCommit = absl::AnyInvocable; +template <> +struct ContextType {}; + +class LoadBalancedCallDestination final : public UnstartedCallDestination { + public: + explicit LoadBalancedCallDestination(ClientChannel::PickerObservable picker) + : picker_(std::move(picker)) {} + + void Orphaned() override {} + + void StartCall(UnstartedCallHandler unstarted_handler) override; + + private: + ClientChannel::PickerObservable picker_; +}; + +} // namespace grpc_core + +#endif // GRPC_SRC_CORE_CLIENT_CHANNEL_LOAD_BALANCED_CALL_DESTINATION_H diff --git a/src/core/client_channel/subchannel.cc b/src/core/client_channel/subchannel.cc index 9ebb91b276e..d12f24b592a 100644 --- a/src/core/client_channel/subchannel.cc +++ b/src/core/client_channel/subchannel.cc @@ -41,6 +41,7 @@ #include "src/core/channelz/channel_trace.h" #include "src/core/channelz/channelz.h" +#include "src/core/client_channel/client_channel_internal.h" #include "src/core/client_channel/subchannel_pool_interface.h" #include "src/core/handshaker/proxy_mapper_registry.h" #include "src/core/lib/address_utils/sockaddr_utils.h" @@ -50,7 +51,10 @@ #include "src/core/lib/channel/channel_stack_builder_impl.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/orphanable.h" +#include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/gprpp/status_helper.h" #include "src/core/lib/gprpp/sync.h" @@ -64,6 +68,7 @@ #include "src/core/lib/surface/init_internally.h" #include "src/core/lib/transport/connectivity_state.h" #include "src/core/lib/transport/error_utils.h" +#include "src/core/lib/transport/interception_chain.h" #include "src/core/lib/transport/transport.h" #include "src/core/telemetry/stats.h" #include "src/core/telemetry/stats_data.h" @@ -97,75 +102,168 @@ DebugOnlyTraceFlag grpc_trace_subchannel_refcount(false, "subchannel_refcount"); // ConnectedSubchannel::ConnectedSubchannel( - grpc_channel_stack* channel_stack, const ChannelArgs& args, + const ChannelArgs& args, RefCountedPtr channelz_subchannel) : RefCounted( GRPC_TRACE_FLAG_ENABLED(grpc_trace_subchannel_refcount) ? "ConnectedSubchannel" : nullptr), - channel_stack_(channel_stack), args_(args), channelz_subchannel_(std::move(channelz_subchannel)) {} -ConnectedSubchannel::~ConnectedSubchannel() { - GRPC_CHANNEL_STACK_UNREF(channel_stack_, "connected_subchannel_dtor"); -} - -void ConnectedSubchannel::StartWatch( - grpc_pollset_set* interested_parties, - OrphanablePtr watcher) { - grpc_transport_op* op = grpc_make_transport_op(nullptr); - op->start_connectivity_watch = std::move(watcher); - op->start_connectivity_watch_state = GRPC_CHANNEL_READY; - op->bind_pollset_set = interested_parties; - grpc_channel_element* elem = grpc_channel_stack_element(channel_stack_, 0); - elem->filter->start_transport_op(elem, op); -} - -void ConnectedSubchannel::Ping(grpc_closure* on_initiate, - grpc_closure* on_ack) { - grpc_transport_op* op = grpc_make_transport_op(nullptr); - grpc_channel_element* elem; - op->send_ping.on_initiate = on_initiate; - op->send_ping.on_ack = on_ack; - elem = grpc_channel_stack_element(channel_stack_, 0); - elem->filter->start_transport_op(elem, op); -} - -size_t ConnectedSubchannel::GetInitialCallSizeEstimate() const { - return GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(SubchannelCall)) + - channel_stack_->call_stack_size; -} - -ArenaPromise ConnectedSubchannel::MakeCallPromise( - CallArgs call_args) { - // If not using channelz, we just need to call the channel stack. - if (channelz_subchannel() == nullptr) { - return channel_stack_->MakeClientCallPromise(std::move(call_args)); - } - // Otherwise, we need to wrap the channel stack promise with code that - // handles the channelz updates. - return OnCancel( - Seq(channel_stack_->MakeClientCallPromise(std::move(call_args)), - [self = Ref()](ServerMetadataHandle metadata) { - channelz::SubchannelNode* channelz_subchannel = - self->channelz_subchannel(); - CHECK_NE(channelz_subchannel, nullptr); - if (metadata->get(GrpcStatusMetadata()) - .value_or(GRPC_STATUS_UNKNOWN) != GRPC_STATUS_OK) { - channelz_subchannel->RecordCallFailed(); - } else { - channelz_subchannel->RecordCallSucceeded(); - } - return metadata; - }), - [self = Ref()]() { - channelz::SubchannelNode* channelz_subchannel = - self->channelz_subchannel(); - CHECK_NE(channelz_subchannel, nullptr); - channelz_subchannel->RecordCallFailed(); - }); -} +// +// LegacyConnectedSubchannel +// + +class LegacyConnectedSubchannel : public ConnectedSubchannel { + public: + LegacyConnectedSubchannel( + RefCountedPtr channel_stack, const ChannelArgs& args, + RefCountedPtr channelz_subchannel) + : ConnectedSubchannel(args, std::move(channelz_subchannel)), + channel_stack_(std::move(channel_stack)) {} + + ~LegacyConnectedSubchannel() override { + channel_stack_.reset(DEBUG_LOCATION, "ConnectedSubchannel"); + } + + void StartWatch( + grpc_pollset_set* interested_parties, + OrphanablePtr watcher) override { + grpc_transport_op* op = grpc_make_transport_op(nullptr); + op->start_connectivity_watch = std::move(watcher); + op->start_connectivity_watch_state = GRPC_CHANNEL_READY; + op->bind_pollset_set = interested_parties; + grpc_channel_element* elem = + grpc_channel_stack_element(channel_stack_.get(), 0); + elem->filter->start_transport_op(elem, op); + } + + void Ping(absl::AnyInvocable) override { + Crash("call v3 ping method called in legacy impl"); + } + + RefCountedPtr unstarted_call_destination() + const override { + Crash("call v3 unstarted_call_destination method called in legacy impl"); + } + + grpc_channel_stack* channel_stack() const override { + return channel_stack_.get(); + } + + size_t GetInitialCallSizeEstimate() const override { + return GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(SubchannelCall)) + + channel_stack_->call_stack_size; + } + + ArenaPromise MakeCallPromise( + CallArgs call_args) override { + // If not using channelz, we just need to call the channel stack. + if (channelz_subchannel() == nullptr) { + return channel_stack_->MakeClientCallPromise(std::move(call_args)); + } + // Otherwise, we need to wrap the channel stack promise with code that + // handles the channelz updates. + return OnCancel( + Seq(channel_stack_->MakeClientCallPromise(std::move(call_args)), + [self = Ref()](ServerMetadataHandle metadata) { + channelz::SubchannelNode* channelz_subchannel = + self->channelz_subchannel(); + CHECK(channelz_subchannel != nullptr); + if (metadata->get(GrpcStatusMetadata()) + .value_or(GRPC_STATUS_UNKNOWN) != GRPC_STATUS_OK) { + channelz_subchannel->RecordCallFailed(); + } else { + channelz_subchannel->RecordCallSucceeded(); + } + return metadata; + }), + [self = Ref()]() { + channelz::SubchannelNode* channelz_subchannel = + self->channelz_subchannel(); + CHECK(channelz_subchannel != nullptr); + channelz_subchannel->RecordCallFailed(); + }); + } + + void Ping(grpc_closure* on_initiate, grpc_closure* on_ack) override { + grpc_transport_op* op = grpc_make_transport_op(nullptr); + op->send_ping.on_initiate = on_initiate; + op->send_ping.on_ack = on_ack; + grpc_channel_element* elem = + grpc_channel_stack_element(channel_stack_.get(), 0); + elem->filter->start_transport_op(elem, op); + } + + private: + RefCountedPtr channel_stack_; +}; + +// +// NewConnectedSubchannel +// + +class NewConnectedSubchannel : public ConnectedSubchannel { + public: + class TransportCallDestination final : public CallDestination { + public: + explicit TransportCallDestination(OrphanablePtr transport) + : transport_(std::move(transport)) {} + + ClientTransport* transport() { return transport_.get(); } + + void HandleCall(CallHandler handler) override { + transport_->StartCall(std::move(handler)); + } + + void Orphaned() override { transport_.reset(); } + + private: + OrphanablePtr transport_; + }; + + NewConnectedSubchannel( + RefCountedPtr call_destination, + RefCountedPtr transport, + const ChannelArgs& args, + RefCountedPtr channelz_subchannel) + : ConnectedSubchannel(args, std::move(channelz_subchannel)), + call_destination_(std::move(call_destination)), + transport_(std::move(transport)) {} + + void StartWatch( + grpc_pollset_set*, + OrphanablePtr watcher) override { + transport_->transport()->StartConnectivityWatch(std::move(watcher)); + } + + void Ping(absl::AnyInvocable) override { + // TODO(ctiller): add new transport API for this in v3 stack + Crash("not implemented"); + } + + RefCountedPtr unstarted_call_destination() + const override { + return call_destination_; + } + + grpc_channel_stack* channel_stack() const override { return nullptr; } + + size_t GetInitialCallSizeEstimate() const override { return 0; } + + ArenaPromise MakeCallPromise(CallArgs) override { + Crash("legacy MakeCallPromise() method called in call v3 impl"); + } + + void Ping(grpc_closure*, grpc_closure*) override { + Crash("legacy ping method called in call v3 impl"); + } + + private: + RefCountedPtr call_destination_; + RefCountedPtr transport_; +}; // // SubchannelCall @@ -255,8 +353,8 @@ void SubchannelCall::Destroy(void* arg, grpc_error_handle /*error*/) { // Destroy the subchannel call. self->~SubchannelCall(); // Destroy the call stack. This should be after destroying the subchannel - // call, because call->after_call_stack_destroy(), if not null, will free the - // call arena. + // call, because call->after_call_stack_destroy(), if not null, will free + // the call arena. grpc_call_stack_destroy(SUBCHANNEL_CALL_TO_CALL_STACK(self), nullptr, after_call_stack_destroy); // Automatically reset connected_subchannel. This should be after destroying @@ -474,8 +572,8 @@ Subchannel::Subchannel(SubchannelKey key, // result the subchannel destruction happens asynchronously to channel // destruction. If the last channel destruction triggers a grpc_shutdown // before the last subchannel destruction, then there maybe race conditions - // triggering segmentation faults. To prevent this issue, we call a grpc_init - // here and a grpc_shutdown in the subchannel destructor. + // triggering segmentation faults. To prevent this issue, we call a + // grpc_init here and a grpc_shutdown in the subchannel destructor. InitInternally(); global_stats().IncrementClientSubchannelsCreated(); GRPC_CLOSURE_INIT(&on_connecting_finished_, OnConnectingFinished, this, @@ -587,7 +685,8 @@ void Subchannel::CancelConnectivityStateWatch( watcher_list_.RemoveWatcherLocked(watcher); } // Drain any connectivity state notifications after releasing the mutex. - // (Shouldn't actually be necessary in this case, but better safe than sorry.) + // (Shouldn't actually be necessary in this case, but better safe than + // sorry.) work_serializer_.DrainQueue(); } @@ -758,11 +857,11 @@ void Subchannel::OnConnectingFinishedLocked(grpc_error_handle error) { ExecCtx exec_ctx; self->OnRetryTimer(); // Subchannel deletion might require an active ExecCtx. So if - // self.reset() is not called here, the WeakRefCountedPtr destructor - // may run after the ExecCtx declared in the callback is destroyed. - // Since subchannel may get destroyed when the WeakRefCountedPtr - // destructor runs, it may not have an active ExecCtx - thus leading - // to crashes. + // self.reset() is not called here, the WeakRefCountedPtr + // destructor may run after the ExecCtx declared in the callback + // is destroyed. Since subchannel may get destroyed when the + // WeakRefCountedPtr destructor runs, it may not have an active + // ExecCtx - thus leading to crashes. self.reset(); } }); @@ -770,37 +869,60 @@ void Subchannel::OnConnectingFinishedLocked(grpc_error_handle error) { } bool Subchannel::PublishTransportLocked() { - // Construct channel stack. - // Builder takes ownership of transport. - ChannelStackBuilderImpl builder( - "subchannel", GRPC_CLIENT_SUBCHANNEL, - connecting_result_.channel_args.SetObject( - std::exchange(connecting_result_.transport, nullptr))); - if (!CoreConfiguration::Get().channel_init().CreateStack(&builder)) { - return false; - } - absl::StatusOr> stk = builder.Build(); - if (!stk.ok()) { - auto error = absl_status_to_grpc_error(stk.status()); - connecting_result_.Reset(); - gpr_log(GPR_ERROR, - "subchannel %p %s: error initializing subchannel stack: %s", this, - key_.ToString().c_str(), StatusToString(error).c_str()); - return false; + auto socket_node = std::move(connecting_result_.socket_node); + if (connecting_result_.transport->filter_stack_transport() != nullptr || + IsChaoticGoodEnabled()) { + // Construct channel stack. + // Builder takes ownership of transport. + ChannelStackBuilderImpl builder( + "subchannel", GRPC_CLIENT_SUBCHANNEL, + connecting_result_.channel_args.SetObject( + std::exchange(connecting_result_.transport, nullptr))); + if (!CoreConfiguration::Get().channel_init().CreateStack(&builder)) { + return false; + } + absl::StatusOr> stack = builder.Build(); + if (!stack.ok()) { + connecting_result_.Reset(); + gpr_log(GPR_ERROR, + "subchannel %p %s: error initializing subchannel stack: %s", this, + key_.ToString().c_str(), stack.status().ToString().c_str()); + return false; + } + connected_subchannel_ = MakeRefCounted( + std::move(*stack), args_, channelz_node_); + } else { + OrphanablePtr transport( + std::exchange(connecting_result_.transport, nullptr) + ->client_transport()); + InterceptionChainBuilder builder( + connecting_result_.channel_args.SetObject(transport.get())); + CoreConfiguration::Get().channel_init().AddToInterceptionChainBuilder( + GRPC_CLIENT_SUBCHANNEL, builder); + auto transport_destination = + MakeRefCounted( + std::move(transport)); + auto call_destination = builder.Build(transport_destination); + if (!call_destination.ok()) { + connecting_result_.Reset(); + gpr_log(GPR_ERROR, + "subchannel %p %s: error initializing subchannel stack: %s", this, + key_.ToString().c_str(), + call_destination.status().ToString().c_str()); + return false; + } + connected_subchannel_ = MakeRefCounted( + std::move(*call_destination), std::move(transport_destination), args_, + channelz_node_); } - RefCountedPtr socket = - std::move(connecting_result_.socket_node); connecting_result_.Reset(); - if (shutdown_) return false; // Publish. - connected_subchannel_.reset( - new ConnectedSubchannel(stk->release(), args_, channelz_node_)); if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_subchannel)) { gpr_log(GPR_INFO, "subchannel %p %s: new connected subchannel at %p", this, key_.ToString().c_str(), connected_subchannel_.get()); } if (channelz_node_ != nullptr) { - channelz_node_->SetChildSocket(std::move(socket)); + channelz_node_->SetChildSocket(std::move(socket_node)); } // Start watching connected subchannel. connected_subchannel_->StartWatch( @@ -811,4 +933,29 @@ bool Subchannel::PublishTransportLocked() { return true; } +ChannelArgs Subchannel::MakeSubchannelArgs( + const ChannelArgs& channel_args, const ChannelArgs& address_args, + const RefCountedPtr& subchannel_pool, + const std::string& channel_default_authority) { + // Note that we start with the channel-level args and then apply the + // per-address args, so that if a value is present in both, the one + // in the channel-level args is used. This is particularly important + // for the GRPC_ARG_DEFAULT_AUTHORITY arg, which we want to allow + // resolvers to set on a per-address basis only if the application + // did not explicitly set it at the channel level. + return channel_args.UnionWith(address_args) + .SetObject(subchannel_pool) + // If we haven't already set the default authority arg (i.e., it + // was not explicitly set by the application nor overridden by + // the resolver), add it from the channel's default. + .SetIfUnset(GRPC_ARG_DEFAULT_AUTHORITY, channel_default_authority) + // Remove channel args that should not affect subchannel + // uniqueness. + .Remove(GRPC_ARG_HEALTH_CHECK_SERVICE_NAME) + .Remove(GRPC_ARG_INHIBIT_HEALTH_CHECKING) + .Remove(GRPC_ARG_CHANNELZ_CHANNEL_NODE) + // Remove all keys with the no-subchannel prefix. + .RemoveAllKeysWithPrefix(GRPC_ARG_NO_SUBCHANNEL_PREFIX); +} + } // namespace grpc_core diff --git a/src/core/client_channel/subchannel.h b/src/core/client_channel/subchannel.h index f59a3810208..fc2c05ed873 100644 --- a/src/core/client_channel/subchannel.h +++ b/src/core/client_channel/subchannel.h @@ -64,30 +64,35 @@ namespace grpc_core { class SubchannelCall; -class ConnectedSubchannel final : public RefCounted { +class ConnectedSubchannel : public RefCounted { public: - ConnectedSubchannel( - grpc_channel_stack* channel_stack, const ChannelArgs& args, - RefCountedPtr channelz_subchannel); - ~ConnectedSubchannel() override; - - void StartWatch(grpc_pollset_set* interested_parties, - OrphanablePtr watcher); - - void Ping(grpc_closure* on_initiate, grpc_closure* on_ack); - - grpc_channel_stack* channel_stack() const { return channel_stack_; } const ChannelArgs& args() const { return args_; } channelz::SubchannelNode* channelz_subchannel() const { return channelz_subchannel_.get(); } - size_t GetInitialCallSizeEstimate() const; + virtual void StartWatch( + grpc_pollset_set* interested_parties, + OrphanablePtr watcher) = 0; + + // Methods for v3 stack. + virtual void Ping(absl::AnyInvocable on_ack) = 0; + virtual RefCountedPtr unstarted_call_destination() + const = 0; - ArenaPromise MakeCallPromise(CallArgs call_args); + // Methods for legacy stack. + virtual grpc_channel_stack* channel_stack() const = 0; + virtual size_t GetInitialCallSizeEstimate() const = 0; + virtual ArenaPromise MakeCallPromise( + CallArgs call_args) = 0; + virtual void Ping(grpc_closure* on_initiate, grpc_closure* on_ack) = 0; + + protected: + ConnectedSubchannel( + const ChannelArgs& args, + RefCountedPtr channelz_subchannel); private: - grpc_channel_stack* channel_stack_; ChannelArgs args_; // ref counted pointer to the channelz node in this connected subchannel's // owning subchannel. @@ -243,6 +248,12 @@ class Subchannel final : public DualRefCounted { return connected_subchannel_; } + RefCountedPtr call_destination() { + MutexLock lock(&mu_); + if (connected_subchannel_ == nullptr) return nullptr; + return connected_subchannel_->unstarted_call_destination(); + } + // Attempt to connect to the backend. Has no effect if already connected. void RequestConnection() ABSL_LOCKS_EXCLUDED(mu_); @@ -272,6 +283,12 @@ class Subchannel final : public DualRefCounted { return event_engine_; } + // Exposed for testing purposes only. + static ChannelArgs MakeSubchannelArgs( + const ChannelArgs& channel_args, const ChannelArgs& address_args, + const RefCountedPtr& subchannel_pool, + const std::string& channel_default_authority); + private: // Tears down any existing connection, and arranges for destruction void Orphaned() override ABSL_LOCKS_EXCLUDED(mu_); diff --git a/src/core/client_channel/subchannel_stream_client.cc b/src/core/client_channel/subchannel_stream_client.cc index 2ee082ef1fa..ab3118d4442 100644 --- a/src/core/client_channel/subchannel_stream_client.cc +++ b/src/core/client_channel/subchannel_stream_client.cc @@ -59,12 +59,13 @@ SubchannelStreamClient::SubchannelStreamClient( connected_subchannel_(std::move(connected_subchannel)), interested_parties_(interested_parties), tracer_(tracer), - call_allocator_( + call_allocator_(MakeRefCounted( connected_subchannel_->args() .GetObject() ->memory_quota() ->CreateMemoryAllocator( - (tracer != nullptr) ? tracer : "SubchannelStreamClient")), + (tracer != nullptr) ? tracer : "SubchannelStreamClient"), + 1024)), event_handler_(std::move(event_handler)), retry_backoff_( BackOff::Options() @@ -171,9 +172,7 @@ SubchannelStreamClient::CallState::CallState( grpc_pollset_set* interested_parties) : subchannel_stream_client_(std::move(health_check_client)), pollent_(grpc_polling_entity_create_from_pollset_set(interested_parties)), - arena_(Arena::Create(subchannel_stream_client_->connected_subchannel_ - ->GetInitialCallSizeEstimate(), - &subchannel_stream_client_->call_allocator_)), + arena_(subchannel_stream_client_->call_allocator_->MakeArena()), payload_(context_) {} SubchannelStreamClient::CallState::~CallState() { diff --git a/src/core/client_channel/subchannel_stream_client.h b/src/core/client_channel/subchannel_stream_client.h index 38d25c755d3..d84f4b3cc1f 100644 --- a/src/core/client_channel/subchannel_stream_client.h +++ b/src/core/client_channel/subchannel_stream_client.h @@ -146,7 +146,7 @@ class SubchannelStreamClient final RefCountedPtr subchannel_stream_client_; grpc_polling_entity pollent_; - ScopedArenaPtr arena_; + RefCountedPtr arena_; CallCombiner call_combiner_; grpc_call_context_element context_[GRPC_CONTEXT_COUNT] = {}; @@ -201,7 +201,7 @@ class SubchannelStreamClient final RefCountedPtr connected_subchannel_; grpc_pollset_set* interested_parties_; // Do not own. const char* tracer_; - MemoryAllocator call_allocator_; + RefCountedPtr call_allocator_; Mutex mu_; std::unique_ptr event_handler_ ABSL_GUARDED_BY(mu_); 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 index fd48d034d38..63a886bc991 100644 --- a/src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc +++ b/src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc @@ -78,15 +78,11 @@ TraceFlag grpc_trace_client_idle_filter(false, "client_idle_filter"); } \ } while (0) -namespace { - Duration GetClientIdleTimeout(const ChannelArgs& args) { return args.GetDurationFromIntMillis(GRPC_ARG_CLIENT_IDLE_TIMEOUT_MS) .value_or(kDefaultIdleTimeout); } -} // namespace - struct LegacyMaxAgeFilter::Config { Duration max_connection_age; Duration max_connection_idle; 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 index 8e6215cebba..001282276f1 100644 --- a/src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h +++ b/src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h @@ -40,6 +40,8 @@ namespace grpc_core { +Duration GetClientIdleTimeout(const ChannelArgs& args); + class LegacyChannelIdleFilter : public ChannelFilter { public: LegacyChannelIdleFilter(grpc_channel_stack* channel_stack, diff --git a/src/core/ext/gcp/metadata_query.h b/src/core/ext/gcp/metadata_query.h index 9e3f6931da5..395c1e6d995 100644 --- a/src/core/ext/gcp/metadata_query.h +++ b/src/core/ext/gcp/metadata_query.h @@ -26,11 +26,11 @@ #include "src/core/lib/gprpp/orphanable.h" #include "src/core/lib/gprpp/time.h" -#include "src/core/lib/http/httpcli.h" -#include "src/core/lib/http/parser.h" #include "src/core/lib/iomgr/closure.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/polling_entity.h" +#include "src/core/util/http_client/httpcli.h" +#include "src/core/util/http_client/parser.h" namespace grpc_core { diff --git a/src/core/ext/transport/chaotic_good/client/chaotic_good_connector.cc b/src/core/ext/transport/chaotic_good/client/chaotic_good_connector.cc index d22d3bbb02c..a5cf2893951 100644 --- a/src/core/ext/transport/chaotic_good/client/chaotic_good_connector.cc +++ b/src/core/ext/transport/chaotic_good/client/chaotic_good_connector.cc @@ -333,7 +333,7 @@ void ChaoticGoodConnector::OnHandshakeDone(void* arg, grpc_error_handle error) { status); } }, - self->arena_.get(), self->event_engine_.get()); + self->arena_, self->event_engine_.get()); MutexLock lock(&self->mu_); if (!self->is_shutdown_) { self->connect_activity_ = std::move(activity); diff --git a/src/core/ext/transport/chaotic_good/client/chaotic_good_connector.h b/src/core/ext/transport/chaotic_good/client/chaotic_good_connector.h index 90b4abff267..b8db7a52502 100644 --- a/src/core/ext/transport/chaotic_good/client/chaotic_good_connector.h +++ b/src/core/ext/transport/chaotic_good/client/chaotic_good_connector.h @@ -79,10 +79,7 @@ class ChaoticGoodConnector : public SubchannelConnector { RefCountedPtr self); static void OnHandshakeDone(void* arg, grpc_error_handle error); - grpc_event_engine::experimental::MemoryAllocator memory_allocator_ = - ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator( - "connect_activity"); - ScopedArenaPtr arena_ = MakeScopedArena(1024, &memory_allocator_); + RefCountedPtr arena_ = SimpleArenaAllocator()->MakeArena(); Mutex mu_; Args args_; Result* result_ ABSL_GUARDED_BY(mu_); diff --git a/src/core/ext/transport/chaotic_good/client_transport.cc b/src/core/ext/transport/chaotic_good/client_transport.cc index cc1fd8b9a18..511d04f6ed1 100644 --- a/src/core/ext/transport/chaotic_good/client_transport.cc +++ b/src/core/ext/transport/chaotic_good/client_transport.cc @@ -146,10 +146,9 @@ auto ChaoticGoodClientTransport::TransportReadLoop( frame_limits); } else { // Stream not found, skip the frame. - auto arena = MakeScopedArena(1024, &allocator_); - deserialize_status = - transport->DeserializeFrame(frame_header, std::move(buffers), - arena.get(), frame, frame_limits); + deserialize_status = transport->DeserializeFrame( + frame_header, std::move(buffers), + SimpleArenaAllocator()->MakeArena().get(), frame, frame_limits); } return If( deserialize_status.ok() && call_handler.has_value(), diff --git a/src/core/ext/transport/chaotic_good/server/chaotic_good_server.cc b/src/core/ext/transport/chaotic_good/server/chaotic_good_server.cc index 8af652a292c..524d9e68349 100644 --- a/src/core/ext/transport/chaotic_good/server/chaotic_good_server.cc +++ b/src/core/ext/transport/chaotic_good/server/chaotic_good_server.cc @@ -149,8 +149,7 @@ absl::Status ChaoticGoodServerListener::StartListening() { ChaoticGoodServerListener::ActiveConnection::ActiveConnection( RefCountedPtr listener, std::unique_ptr endpoint) - : memory_allocator_(listener->memory_allocator_), - listener_(std::move(listener)) { + : listener_(std::move(listener)) { handshaking_state_ = MakeRefCounted(Ref()); handshaking_state_->Start(std::move(endpoint)); } @@ -208,8 +207,7 @@ void ChaoticGoodServerListener::ActiveConnection::Done( ChaoticGoodServerListener::ActiveConnection::HandshakingState::HandshakingState( RefCountedPtr connection) - : memory_allocator_(connection->memory_allocator_), - connection_(std::move(connection)), + : connection_(std::move(connection)), handshake_mgr_(MakeRefCounted()) {} void ChaoticGoodServerListener::ActiveConnection::HandshakingState::Start( diff --git a/src/core/ext/transport/chaotic_good/server/chaotic_good_server.h b/src/core/ext/transport/chaotic_good/server/chaotic_good_server.h index 0479016c15b..8511790c03b 100644 --- a/src/core/ext/transport/chaotic_good/server/chaotic_good_server.h +++ b/src/core/ext/transport/chaotic_good/server/chaotic_good_server.h @@ -106,8 +106,6 @@ class ChaoticGoodServerListener final : public Server::ListenerInterface { static void OnHandshakeDone(void* arg, grpc_error_handle error); Timestamp GetConnectionDeadline(); - const std::shared_ptr - memory_allocator_; const RefCountedPtr connection_; const RefCountedPtr handshake_mgr_; }; @@ -115,9 +113,7 @@ class ChaoticGoodServerListener final : public Server::ListenerInterface { private: void Done(absl::optional error = absl::nullopt); void NewConnectionID(); - const std::shared_ptr - memory_allocator_; - ScopedArenaPtr arena_ = MakeScopedArena(1024, memory_allocator_.get()); + RefCountedPtr arena_ = SimpleArenaAllocator()->MakeArena(); const RefCountedPtr listener_; RefCountedPtr handshaking_state_; Mutex mu_; @@ -161,11 +157,6 @@ class ChaoticGoodServerListener final : public Server::ListenerInterface { absl::AnyInvocable connection_id_generator_ ABSL_GUARDED_BY(mu_); grpc_closure* on_destroy_done_ ABSL_GUARDED_BY(mu_) = nullptr; - std::shared_ptr - memory_allocator_ = - std::make_shared( - ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator( - "server_connection")); }; } // namespace chaotic_good diff --git a/src/core/ext/transport/chaotic_good/server_transport.cc b/src/core/ext/transport/chaotic_good/server_transport.cc index 98fbf4e915e..bc4fbed3334 100644 --- a/src/core/ext/transport/chaotic_good/server_transport.cc +++ b/src/core/ext/transport/chaotic_good/server_transport.cc @@ -235,15 +235,14 @@ auto ChaoticGoodServerTransport::DeserializeAndPushFragmentToNewCall( FrameHeader frame_header, BufferPair buffers, ChaoticGoodTransport& transport) { ClientFragmentFrame fragment_frame; - ScopedArenaPtr arena(call_arena_allocator_->MakeArena()); + RefCountedPtr arena(call_arena_allocator_->MakeArena()); absl::Status status = transport.DeserializeFrame( frame_header, std::move(buffers), arena.get(), fragment_frame, FrameLimits{1024 * 1024 * 1024, aligned_bytes_ - 1}); absl::optional call_initiator; if (status.ok()) { - auto call = - MakeCallPair(std::move(fragment_frame.headers), event_engine_.get(), - arena.release(), call_arena_allocator_, nullptr); + auto call = MakeCallPair(std::move(fragment_frame.headers), + event_engine_.get(), std::move(arena), nullptr); call_initiator.emplace(std::move(call.initiator)); auto add_result = NewStream(frame_header.stream_id, *call_initiator); if (add_result.ok()) { diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.cc b/src/core/ext/transport/chttp2/server/chttp2_server.cc index 3388e234fd9..77645c06871 100644 --- a/src/core/ext/transport/chttp2/server/chttp2_server.cc +++ b/src/core/ext/transport/chttp2/server/chttp2_server.cc @@ -474,23 +474,18 @@ void Chttp2ServerListener::ActiveConnection::HandshakingState::OnHandshakeDone( // handshaker may have handed off the connection to some external // code, so we can just clean up here without creating a transport. if (args->endpoint != nullptr) { - Transport* transport = - grpc_create_chttp2_transport(args->args, args->endpoint, false); + RefCountedPtr transport = + grpc_create_chttp2_transport(args->args, args->endpoint, false) + ->Ref(); grpc_error_handle channel_init_err = self->connection_->listener_->server_->SetupTransport( - transport, self->accepting_pollset_, args->args, - grpc_chttp2_transport_get_socket_node(transport)); + transport.get(), self->accepting_pollset_, args->args, + grpc_chttp2_transport_get_socket_node(transport.get())); if (channel_init_err.ok()) { // Use notify_on_receive_settings callback to enforce the // handshake deadline. - // Note: The reinterpret_cast<>s here are safe, because - // grpc_chttp2_transport is a C-style extension of - // Transport, so this is morally equivalent of a - // static_cast<> to a derived class. - // TODO(roth): Change to static_cast<> when we C++-ify the - // transport API. self->connection_->transport_ = - reinterpret_cast(transport)->Ref(); + DownCast(transport.get())->Ref(); self->Ref().release(); // Held by OnReceiveSettings(). GRPC_CLOSURE_INIT(&self->on_receive_settings_, OnReceiveSettings, self, grpc_schedule_on_exec_ctx); @@ -520,9 +515,9 @@ void Chttp2ServerListener::ActiveConnection::HandshakingState::OnHandshakeDone( grpc_schedule_on_exec_ctx_); cleanup_connection = true; } - grpc_chttp2_transport_start_reading(transport, args->read_buffer, - &self->on_receive_settings_, - on_close); + grpc_chttp2_transport_start_reading( + transport.get(), args->read_buffer, &self->on_receive_settings_, + on_close); self->timer_handle_ = self->connection_->event_engine_->RunAfter( self->deadline_ - Timestamp::Now(), [self = self->Ref()]() mutable { diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc index 118b1f99488..90cfdf3ad5e 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc @@ -82,7 +82,6 @@ #include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/gprpp/status_helper.h" #include "src/core/lib/gprpp/time.h" -#include "src/core/lib/http/parser.h" #include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/exec_ctx.h" @@ -108,6 +107,7 @@ #include "src/core/telemetry/stats.h" #include "src/core/telemetry/stats_data.h" #include "src/core/telemetry/tcp_tracer.h" +#include "src/core/util/http_client/parser.h" #include "src/core/util/string.h" #include "src/core/util/useful.h" diff --git a/src/core/ext/transport/chttp2/transport/ping_rate_policy.cc b/src/core/ext/transport/chttp2/transport/ping_rate_policy.cc index fed8ca20371..143b08a67c7 100644 --- a/src/core/ext/transport/chttp2/transport/ping_rate_policy.cc +++ b/src/core/ext/transport/chttp2/transport/ping_rate_policy.cc @@ -35,16 +35,18 @@ namespace grpc_core { namespace { -int g_default_max_pings_without_data = 2; +int g_default_max_pings_without_data_sent = 2; +constexpr Duration kThrottleIntervalWithoutDataSent = Duration::Minutes(1); absl::optional g_default_max_inflight_pings; } // namespace Chttp2PingRatePolicy::Chttp2PingRatePolicy(const ChannelArgs& args, bool is_client) - : max_pings_without_data_( + : max_pings_without_data_sent_( is_client - ? std::max(0, args.GetInt(GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA) - .value_or(g_default_max_pings_without_data)) + ? std::max(0, + args.GetInt(GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA) + .value_or(g_default_max_pings_without_data_sent)) : 0), // Configuration via channel arg dominates, otherwise if the multiping // experiment is enabled we use 100, otherwise 1. @@ -54,18 +56,15 @@ Chttp2PingRatePolicy::Chttp2PingRatePolicy(const ChannelArgs& args, IsMultipingEnabled() ? 100 : 1)))) {} void Chttp2PingRatePolicy::SetDefaults(const ChannelArgs& args) { - g_default_max_pings_without_data = + g_default_max_pings_without_data_sent = std::max(0, args.GetInt(GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA) - .value_or(g_default_max_pings_without_data)); + .value_or(g_default_max_pings_without_data_sent)); g_default_max_inflight_pings = args.GetInt(GRPC_ARG_HTTP2_MAX_INFLIGHT_PINGS); } Chttp2PingRatePolicy::RequestSendPingResult Chttp2PingRatePolicy::RequestSendPing(Duration next_allowed_ping_interval, size_t inflight_pings) const { - if (max_pings_without_data_ != 0 && pings_before_data_required_ == 0) { - return TooManyRecentPings{}; - } if (max_inflight_pings_ > 0 && inflight_pings > static_cast(max_inflight_pings_)) { return TooManyRecentPings{}; @@ -77,12 +76,29 @@ Chttp2PingRatePolicy::RequestSendPing(Duration next_allowed_ping_interval, return TooSoon{next_allowed_ping_interval, last_ping_sent_time_, next_allowed_ping - now}; } + // Throttle pings to 1 minute if we haven't sent any data recently + if (max_pings_without_data_sent_ != 0 && + pings_before_data_sending_required_ == 0) { + if (IsMaxPingsWoDataThrottleEnabled()) { + const Timestamp next_allowed_ping = + last_ping_sent_time_ + kThrottleIntervalWithoutDataSent; + if (next_allowed_ping > now) { + return TooSoon{kThrottleIntervalWithoutDataSent, last_ping_sent_time_, + next_allowed_ping - now}; + } + } else { + return TooManyRecentPings{}; + } + } + return SendGranted{}; } void Chttp2PingRatePolicy::SentPing() { last_ping_sent_time_ = Timestamp::Now(); - if (pings_before_data_required_) --pings_before_data_required_; + if (pings_before_data_sending_required_ > 0) { + --pings_before_data_sending_required_; + } } void Chttp2PingRatePolicy::ReceivedDataFrame() { @@ -90,13 +106,13 @@ void Chttp2PingRatePolicy::ReceivedDataFrame() { } void Chttp2PingRatePolicy::ResetPingsBeforeDataRequired() { - pings_before_data_required_ = max_pings_without_data_; + pings_before_data_sending_required_ = max_pings_without_data_sent_; } std::string Chttp2PingRatePolicy::GetDebugString() const { return absl::StrCat( - "max_pings_without_data: ", max_pings_without_data_, - ", pings_before_data_required: ", pings_before_data_required_, + "max_pings_without_data: ", max_pings_without_data_sent_, + ", pings_before_data_required: ", pings_before_data_sending_required_, ", last_ping_sent_time_: ", last_ping_sent_time_.ToString()); } diff --git a/src/core/ext/transport/chttp2/transport/ping_rate_policy.h b/src/core/ext/transport/chttp2/transport/ping_rate_policy.h index b9501686d95..6dab7a361bc 100644 --- a/src/core/ext/transport/chttp2/transport/ping_rate_policy.h +++ b/src/core/ext/transport/chttp2/transport/ping_rate_policy.h @@ -70,13 +70,14 @@ class Chttp2PingRatePolicy { void ReceivedDataFrame(); std::string GetDebugString() const; - int TestOnlyMaxPingsWithoutData() const { return max_pings_without_data_; } + int TestOnlyMaxPingsWithoutData() const { + return max_pings_without_data_sent_; + } private: - const int max_pings_without_data_; + const int max_pings_without_data_sent_; const int max_inflight_pings_; - // No pings allowed before receiving a header or data frame. - int pings_before_data_required_ = 0; + int pings_before_data_sending_required_ = 0; Timestamp last_ping_sent_time_ = Timestamp::InfPast(); }; diff --git a/src/core/ext/transport/inproc/inproc_transport.cc b/src/core/ext/transport/inproc/inproc_transport.cc index 7913e631fe8..c5ea01739f4 100644 --- a/src/core/ext/transport/inproc/inproc_transport.cc +++ b/src/core/ext/transport/inproc/inproc_transport.cc @@ -105,9 +105,9 @@ class InprocServerTransport final : public ServerTransport { case ConnectionState::kReady: break; } - auto* arena = call_arena_allocator_->MakeArena(); - auto server_call = MakeCallPair(std::move(md), event_engine_.get(), arena, - call_arena_allocator_, nullptr); + auto server_call = + MakeCallPair(std::move(md), event_engine_.get(), + call_arena_allocator_->MakeArena(), nullptr); unstarted_call_handler_->StartCall(std::move(server_call.handler)); return std::move(server_call.initiator); } diff --git a/src/core/handshaker/http_connect/http_connect_handshaker.cc b/src/core/handshaker/http_connect/http_connect_handshaker.cc index 32d218e06ea..30773fe99b4 100644 --- a/src/core/handshaker/http_connect/http_connect_handshaker.cc +++ b/src/core/handshaker/http_connect/http_connect_handshaker.cc @@ -44,14 +44,14 @@ #include "src/core/lib/gprpp/debug_location.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/gprpp/sync.h" -#include "src/core/lib/http/format_request.h" -#include "src/core/lib/http/parser.h" #include "src/core/lib/iomgr/closure.h" #include "src/core/lib/iomgr/endpoint.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/iomgr/iomgr_fwd.h" #include "src/core/lib/iomgr/tcp_server.h" +#include "src/core/util/http_client/format_request.h" +#include "src/core/util/http_client/parser.h" #include "src/core/util/string.h" namespace grpc_core { diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h index 31e0430a7c6..55cb2785abc 100644 --- a/src/core/lib/channel/channel_args.h +++ b/src/core/lib/channel/channel_args.h @@ -83,6 +83,16 @@ inline int PointerCompare(void* a_ptr, const grpc_arg_pointer_vtable* a_vtable, // before the crt refcount base class. template using RefType = absl::remove_cvref_t().Ref())>; + +template +struct IsRawPointerTagged { + static constexpr bool kValue = false; +}; +template +struct IsRawPointerTagged> { + static constexpr bool kValue = true; +}; } // namespace channel_args_detail // Specialization for ref-counted pointers. @@ -91,13 +101,14 @@ using RefType = absl::remove_cvref_t().Ref())>; template struct ChannelArgTypeTraits< T, absl::enable_if_t< - std::is_base_of>, - channel_args_detail::RefType>::value || - std::is_base_of, - NonPolymorphicRefCount>, - channel_args_detail::RefType>::value || - std::is_base_of>, - channel_args_detail::RefType>::value, + !channel_args_detail::IsRawPointerTagged::kValue && + (std::is_base_of>, + channel_args_detail::RefType>::value || + std::is_base_of, + NonPolymorphicRefCount>, + channel_args_detail::RefType>::value || + std::is_base_of>, + channel_args_detail::RefType>::value), void>> { static const grpc_arg_pointer_vtable* VTable() { static const grpc_arg_pointer_vtable tbl = { diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h index 9fc6564c8de..c414b33eb23 100644 --- a/src/core/lib/channel/channel_stack.h +++ b/src/core/lib/channel/channel_stack.h @@ -230,6 +230,7 @@ struct grpc_channel_stack { // full C++-ification for now. void IncrementRefCount(); void Unref(); + void Unref(const grpc_core::DebugLocation& location, const char* reason); grpc_core::RefCountedPtr Ref() { IncrementRefCount(); return grpc_core::RefCountedPtr(this); @@ -345,6 +346,11 @@ inline void grpc_channel_stack::Unref() { GRPC_CHANNEL_STACK_UNREF(this, "smart_pointer"); } +inline void grpc_channel_stack::Unref(const grpc_core::DebugLocation&, + const char* reason) { + GRPC_CHANNEL_STACK_UNREF(this, reason); +} + inline void grpc_call_stack::IncrementRefCount() { GRPC_CALL_STACK_REF(this, "smart_pointer"); } diff --git a/src/core/lib/channel/context.h b/src/core/lib/channel/context.h index 95ce62240bf..cd3dadf30e2 100644 --- a/src/core/lib/channel/context.h +++ b/src/core/lib/channel/context.h @@ -49,9 +49,6 @@ typedef enum { /// future anyway, so not super important. GRPC_CONTEXT_CALL_TRACER, - /// Reserved for traffic_class_context. - GRPC_CONTEXT_TRAFFIC, - /// Holds a pointer to ServiceConfigCallData associated with this call. GRPC_CONTEXT_SERVICE_CONFIG_CALL_DATA, @@ -59,9 +56,6 @@ typedef enum { /// the server. GRPC_CONTEXT_BACKEND_METRIC_PROVIDER, - /// Special Google context - GRPC_CONTEXT_GOOGLE, - GRPC_CONTEXT_COUNT } grpc_context_index; @@ -73,6 +67,8 @@ struct grpc_call_context_element { namespace grpc_core { class Call; class CallTracerAnnotationInterface; +class CallTracerInterface; +class ServiceConfigCallData; // Bind the legacy context array into the new style structure // TODO(ctiller): remove as we migrate these contexts to the new system. @@ -96,6 +92,17 @@ struct OldStyleContext { GRPC_CONTEXT_CALL_TRACER_ANNOTATION_INTERFACE; }; +template <> +struct OldStyleContext { + static constexpr grpc_context_index kIndex = GRPC_CONTEXT_CALL_TRACER; +}; + +template <> +struct OldStyleContext { + static constexpr grpc_context_index kIndex = + GRPC_CONTEXT_SERVICE_CONFIG_CALL_DATA; +}; + template class Context::kIndex)>> { public: @@ -104,6 +111,15 @@ class Context::kIndex)>> { GetContext()[OldStyleContext::kIndex] .value); } + static void set(T* value) { + auto& elem = + GetContext()[OldStyleContext::kIndex]; + if (elem.destroy != nullptr) { + elem.destroy(elem.value); + elem.destroy = nullptr; + } + elem.value = value; + } }; } // namespace promise_detail diff --git a/src/core/lib/config/config_vars.cc b/src/core/lib/config/config_vars.cc index b01070f81a7..7a4fed1a7c9 100644 --- a/src/core/lib/config/config_vars.cc +++ b/src/core/lib/config/config_vars.cc @@ -75,8 +75,6 @@ ABSL_FLAG(absl::optional, grpc_not_use_system_ssl_roots, {}, "Disable loading system root certificates."); ABSL_FLAG(absl::optional, grpc_ssl_cipher_suites, {}, "A colon separated list of cipher suites to use with OpenSSL"); -ABSL_FLAG(absl::optional, grpc_absl_logging, {}, - "Use absl logging from within gpr_log."); namespace grpc_core { @@ -94,8 +92,6 @@ ConfigVars::ConfigVars(const Overrides& overrides) not_use_system_ssl_roots_(LoadConfig( FLAGS_grpc_not_use_system_ssl_roots, "GRPC_NOT_USE_SYSTEM_SSL_ROOTS", overrides.not_use_system_ssl_roots, false)), - absl_logging_(LoadConfig(FLAGS_grpc_absl_logging, "GRPC_ABSL_LOGGING", - overrides.absl_logging, true)), dns_resolver_(LoadConfig(FLAGS_grpc_dns_resolver, "GRPC_DNS_RESOLVER", overrides.dns_resolver, "")), verbosity_(LoadConfig(FLAGS_grpc_verbosity, "GRPC_VERBOSITY", @@ -147,8 +143,7 @@ std::string ConfigVars::ToString() const { "\"", ", default_ssl_roots_file_path: ", "\"", absl::CEscape(DefaultSslRootsFilePath()), "\"", ", not_use_system_ssl_roots: ", NotUseSystemSslRoots() ? "true" : "false", - ", ssl_cipher_suites: ", "\"", absl::CEscape(SslCipherSuites()), "\"", - ", absl_logging: ", AbslLogging() ? "true" : "false"); + ", ssl_cipher_suites: ", "\"", absl::CEscape(SslCipherSuites()), "\""); } } // namespace grpc_core diff --git a/src/core/lib/config/config_vars.h b/src/core/lib/config/config_vars.h index 20ca3c2d6d9..8c534bf7c33 100644 --- a/src/core/lib/config/config_vars.h +++ b/src/core/lib/config/config_vars.h @@ -38,7 +38,6 @@ class GPR_DLL ConfigVars { absl::optional enable_fork_support; absl::optional abort_on_leaks; absl::optional not_use_system_ssl_roots; - absl::optional absl_logging; absl::optional dns_resolver; absl::optional verbosity; absl::optional stacktrace_minloglevel; @@ -103,8 +102,6 @@ class GPR_DLL ConfigVars { bool NotUseSystemSslRoots() const { return not_use_system_ssl_roots_; } // A colon separated list of cipher suites to use with OpenSSL absl::string_view SslCipherSuites() const { return ssl_cipher_suites_; } - // Use absl logging from within gpr_log. - bool AbslLogging() const { return absl_logging_; } private: explicit ConfigVars(const Overrides& overrides); @@ -114,7 +111,6 @@ class GPR_DLL ConfigVars { bool enable_fork_support_; bool abort_on_leaks_; bool not_use_system_ssl_roots_; - bool absl_logging_; std::string dns_resolver_; std::string verbosity_; std::string stacktrace_minloglevel_; diff --git a/src/core/lib/config/config_vars.yaml b/src/core/lib/config/config_vars.yaml index 3496ee6c096..8ccd41c2d41 100644 --- a/src/core/lib/config/config_vars.yaml +++ b/src/core/lib/config/config_vars.yaml @@ -126,8 +126,3 @@ ECDHE-ECDSA-AES256-GCM-SHA384:\ ECDHE-RSA-AES128-GCM-SHA256:\ ECDHE-RSA-AES256-GCM-SHA384" -- name: absl_logging - type: bool - default: true - description: - Use absl logging from within gpr_log. diff --git a/src/core/lib/experiments/experiments.cc b/src/core/lib/experiments/experiments.cc index 468884ec583..8fc435e0f24 100644 --- a/src/core/lib/experiments/experiments.cc +++ b/src/core/lib/experiments/experiments.cc @@ -29,8 +29,6 @@ const char* const description_call_status_override_on_cancellation = "with cancellation."; const char* const additional_constraints_call_status_override_on_cancellation = "{}"; -const char* const description_call_v3 = "Promise-based call version 3."; -const char* const additional_constraints_call_v3 = "{}"; const char* const description_canary_client_privacy = "If set, canary client privacy"; const char* const additional_constraints_canary_client_privacy = "{}"; @@ -59,6 +57,11 @@ 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_max_pings_wo_data_throttle = + "Experiment to throttle pings to a period of 1 min when " + "GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA limit has reached (instead of " + "completely blocking)."; +const char* const additional_constraints_max_pings_wo_data_throttle = "{}"; const char* const description_monitoring_experiment = "Placeholder experiment to prove/disprove our monitoring is working"; const char* const additional_constraints_monitoring_experiment = "{}"; @@ -128,6 +131,12 @@ const char* const description_work_serializer_dispatch = const char* const additional_constraints_work_serializer_dispatch = "{}"; const uint8_t required_experiments_work_serializer_dispatch[] = { static_cast(grpc_core::kExperimentIdEventEngineClient)}; +const char* const description_call_v3 = "Promise-based call version 3."; +const char* const additional_constraints_call_v3 = "{}"; +const uint8_t required_experiments_call_v3[] = { + static_cast(grpc_core::kExperimentIdEventEngineClient), + static_cast(grpc_core::kExperimentIdEventEngineListener), + static_cast(grpc_core::kExperimentIdWorkSerializerDispatch)}; } // namespace namespace grpc_core { @@ -137,8 +146,6 @@ const ExperimentMetadata g_experiment_metadata[] = { description_call_status_override_on_cancellation, additional_constraints_call_status_override_on_cancellation, nullptr, 0, true, true}, - {"call_v3", description_call_v3, additional_constraints_call_v3, nullptr, 0, - false, true}, {"canary_client_privacy", description_canary_client_privacy, additional_constraints_canary_client_privacy, nullptr, 0, false, false}, {"client_privacy", description_client_privacy, @@ -157,6 +164,9 @@ const ExperimentMetadata g_experiment_metadata[] = { additional_constraints_keepalive_fix, nullptr, 0, false, false}, {"keepalive_server_fix", description_keepalive_server_fix, additional_constraints_keepalive_server_fix, nullptr, 0, false, false}, + {"max_pings_wo_data_throttle", description_max_pings_wo_data_throttle, + additional_constraints_max_pings_wo_data_throttle, nullptr, 0, false, + true}, {"monitoring_experiment", description_monitoring_experiment, additional_constraints_monitoring_experiment, nullptr, 0, true, true}, {"multiping", description_multiping, additional_constraints_multiping, @@ -200,6 +210,8 @@ const ExperimentMetadata g_experiment_metadata[] = { {"work_serializer_dispatch", description_work_serializer_dispatch, additional_constraints_work_serializer_dispatch, required_experiments_work_serializer_dispatch, 1, false, true}, + {"call_v3", description_call_v3, additional_constraints_call_v3, + required_experiments_call_v3, 3, false, false}, }; } // namespace grpc_core @@ -211,8 +223,6 @@ const char* const description_call_status_override_on_cancellation = "with cancellation."; const char* const additional_constraints_call_status_override_on_cancellation = "{}"; -const char* const description_call_v3 = "Promise-based call version 3."; -const char* const additional_constraints_call_v3 = "{}"; const char* const description_canary_client_privacy = "If set, canary client privacy"; const char* const additional_constraints_canary_client_privacy = "{}"; @@ -241,6 +251,11 @@ 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_max_pings_wo_data_throttle = + "Experiment to throttle pings to a period of 1 min when " + "GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA limit has reached (instead of " + "completely blocking)."; +const char* const additional_constraints_max_pings_wo_data_throttle = "{}"; const char* const description_monitoring_experiment = "Placeholder experiment to prove/disprove our monitoring is working"; const char* const additional_constraints_monitoring_experiment = "{}"; @@ -310,6 +325,12 @@ const char* const description_work_serializer_dispatch = const char* const additional_constraints_work_serializer_dispatch = "{}"; const uint8_t required_experiments_work_serializer_dispatch[] = { static_cast(grpc_core::kExperimentIdEventEngineClient)}; +const char* const description_call_v3 = "Promise-based call version 3."; +const char* const additional_constraints_call_v3 = "{}"; +const uint8_t required_experiments_call_v3[] = { + static_cast(grpc_core::kExperimentIdEventEngineClient), + static_cast(grpc_core::kExperimentIdEventEngineListener), + static_cast(grpc_core::kExperimentIdWorkSerializerDispatch)}; } // namespace namespace grpc_core { @@ -319,14 +340,12 @@ const ExperimentMetadata g_experiment_metadata[] = { description_call_status_override_on_cancellation, additional_constraints_call_status_override_on_cancellation, nullptr, 0, true, true}, - {"call_v3", description_call_v3, additional_constraints_call_v3, nullptr, 0, - false, true}, {"canary_client_privacy", description_canary_client_privacy, additional_constraints_canary_client_privacy, nullptr, 0, false, false}, {"client_privacy", description_client_privacy, additional_constraints_client_privacy, nullptr, 0, false, false}, {"event_engine_client", description_event_engine_client, - additional_constraints_event_engine_client, nullptr, 0, true, true}, + additional_constraints_event_engine_client, nullptr, 0, false, true}, {"event_engine_dns", description_event_engine_dns, additional_constraints_event_engine_dns, nullptr, 0, true, false}, {"event_engine_listener", description_event_engine_listener, @@ -339,6 +358,9 @@ const ExperimentMetadata g_experiment_metadata[] = { additional_constraints_keepalive_fix, nullptr, 0, false, false}, {"keepalive_server_fix", description_keepalive_server_fix, additional_constraints_keepalive_server_fix, nullptr, 0, false, false}, + {"max_pings_wo_data_throttle", description_max_pings_wo_data_throttle, + additional_constraints_max_pings_wo_data_throttle, nullptr, 0, false, + true}, {"monitoring_experiment", description_monitoring_experiment, additional_constraints_monitoring_experiment, nullptr, 0, true, true}, {"multiping", description_multiping, additional_constraints_multiping, @@ -382,6 +404,8 @@ const ExperimentMetadata g_experiment_metadata[] = { {"work_serializer_dispatch", description_work_serializer_dispatch, additional_constraints_work_serializer_dispatch, required_experiments_work_serializer_dispatch, 1, false, true}, + {"call_v3", description_call_v3, additional_constraints_call_v3, + required_experiments_call_v3, 3, false, false}, }; } // namespace grpc_core @@ -393,8 +417,6 @@ const char* const description_call_status_override_on_cancellation = "with cancellation."; const char* const additional_constraints_call_status_override_on_cancellation = "{}"; -const char* const description_call_v3 = "Promise-based call version 3."; -const char* const additional_constraints_call_v3 = "{}"; const char* const description_canary_client_privacy = "If set, canary client privacy"; const char* const additional_constraints_canary_client_privacy = "{}"; @@ -423,6 +445,11 @@ 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_max_pings_wo_data_throttle = + "Experiment to throttle pings to a period of 1 min when " + "GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA limit has reached (instead of " + "completely blocking)."; +const char* const additional_constraints_max_pings_wo_data_throttle = "{}"; const char* const description_monitoring_experiment = "Placeholder experiment to prove/disprove our monitoring is working"; const char* const additional_constraints_monitoring_experiment = "{}"; @@ -492,6 +519,12 @@ const char* const description_work_serializer_dispatch = const char* const additional_constraints_work_serializer_dispatch = "{}"; const uint8_t required_experiments_work_serializer_dispatch[] = { static_cast(grpc_core::kExperimentIdEventEngineClient)}; +const char* const description_call_v3 = "Promise-based call version 3."; +const char* const additional_constraints_call_v3 = "{}"; +const uint8_t required_experiments_call_v3[] = { + static_cast(grpc_core::kExperimentIdEventEngineClient), + static_cast(grpc_core::kExperimentIdEventEngineListener), + static_cast(grpc_core::kExperimentIdWorkSerializerDispatch)}; } // namespace namespace grpc_core { @@ -501,8 +534,6 @@ const ExperimentMetadata g_experiment_metadata[] = { description_call_status_override_on_cancellation, additional_constraints_call_status_override_on_cancellation, nullptr, 0, true, true}, - {"call_v3", description_call_v3, additional_constraints_call_v3, nullptr, 0, - false, true}, {"canary_client_privacy", description_canary_client_privacy, additional_constraints_canary_client_privacy, nullptr, 0, false, false}, {"client_privacy", description_client_privacy, @@ -521,6 +552,9 @@ const ExperimentMetadata g_experiment_metadata[] = { additional_constraints_keepalive_fix, nullptr, 0, false, false}, {"keepalive_server_fix", description_keepalive_server_fix, additional_constraints_keepalive_server_fix, nullptr, 0, false, false}, + {"max_pings_wo_data_throttle", description_max_pings_wo_data_throttle, + additional_constraints_max_pings_wo_data_throttle, nullptr, 0, false, + true}, {"monitoring_experiment", description_monitoring_experiment, additional_constraints_monitoring_experiment, nullptr, 0, true, true}, {"multiping", description_multiping, additional_constraints_multiping, @@ -564,6 +598,8 @@ const ExperimentMetadata g_experiment_metadata[] = { {"work_serializer_dispatch", description_work_serializer_dispatch, additional_constraints_work_serializer_dispatch, required_experiments_work_serializer_dispatch, 1, true, true}, + {"call_v3", description_call_v3, additional_constraints_call_v3, + required_experiments_call_v3, 3, false, false}, }; } // namespace grpc_core diff --git a/src/core/lib/experiments/experiments.h b/src/core/lib/experiments/experiments.h index 9e3ba9148ba..eebbfe2afde 100644 --- a/src/core/lib/experiments/experiments.h +++ b/src/core/lib/experiments/experiments.h @@ -59,7 +59,6 @@ namespace grpc_core { #if defined(GRPC_CFSTREAM) #define GRPC_EXPERIMENT_IS_INCLUDED_CALL_STATUS_OVERRIDE_ON_CANCELLATION inline bool IsCallStatusOverrideOnCancellationEnabled() { return true; } -inline bool IsCallV3Enabled() { return false; } inline bool IsCanaryClientPrivacyEnabled() { return false; } inline bool IsClientPrivacyEnabled() { return false; } inline bool IsEventEngineClientEnabled() { return false; } @@ -70,6 +69,7 @@ inline bool IsFreeLargeAllocatorEnabled() { return false; } inline bool IsHttp2StatsFixEnabled() { return true; } inline bool IsKeepaliveFixEnabled() { return false; } inline bool IsKeepaliveServerFixEnabled() { return false; } +inline bool IsMaxPingsWoDataThrottleEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_MONITORING_EXPERIMENT inline bool IsMonitoringExperimentEnabled() { return true; } inline bool IsMultipingEnabled() { return false; } @@ -90,15 +90,14 @@ inline bool IsUnconstrainedMaxQuotaBufferSizeEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_WORK_SERIALIZER_CLEARS_TIME_CACHE inline bool IsWorkSerializerClearsTimeCacheEnabled() { return true; } inline bool IsWorkSerializerDispatchEnabled() { return false; } +inline bool IsCallV3Enabled() { return false; } #elif defined(GPR_WINDOWS) #define GRPC_EXPERIMENT_IS_INCLUDED_CALL_STATUS_OVERRIDE_ON_CANCELLATION inline bool IsCallStatusOverrideOnCancellationEnabled() { return true; } -inline bool IsCallV3Enabled() { return false; } inline bool IsCanaryClientPrivacyEnabled() { return false; } inline bool IsClientPrivacyEnabled() { return false; } -#define GRPC_EXPERIMENT_IS_INCLUDED_EVENT_ENGINE_CLIENT -inline bool IsEventEngineClientEnabled() { return true; } +inline bool IsEventEngineClientEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_EVENT_ENGINE_DNS inline bool IsEventEngineDnsEnabled() { return true; } #define GRPC_EXPERIMENT_IS_INCLUDED_EVENT_ENGINE_LISTENER @@ -108,6 +107,7 @@ inline bool IsFreeLargeAllocatorEnabled() { return false; } inline bool IsHttp2StatsFixEnabled() { return true; } inline bool IsKeepaliveFixEnabled() { return false; } inline bool IsKeepaliveServerFixEnabled() { return false; } +inline bool IsMaxPingsWoDataThrottleEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_MONITORING_EXPERIMENT inline bool IsMonitoringExperimentEnabled() { return true; } inline bool IsMultipingEnabled() { return false; } @@ -128,11 +128,11 @@ inline bool IsUnconstrainedMaxQuotaBufferSizeEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_WORK_SERIALIZER_CLEARS_TIME_CACHE inline bool IsWorkSerializerClearsTimeCacheEnabled() { return true; } inline bool IsWorkSerializerDispatchEnabled() { return false; } +inline bool IsCallV3Enabled() { return false; } #else #define GRPC_EXPERIMENT_IS_INCLUDED_CALL_STATUS_OVERRIDE_ON_CANCELLATION inline bool IsCallStatusOverrideOnCancellationEnabled() { return true; } -inline bool IsCallV3Enabled() { return false; } inline bool IsCanaryClientPrivacyEnabled() { return false; } inline bool IsClientPrivacyEnabled() { return false; } inline bool IsEventEngineClientEnabled() { return false; } @@ -145,6 +145,7 @@ inline bool IsFreeLargeAllocatorEnabled() { return false; } inline bool IsHttp2StatsFixEnabled() { return true; } inline bool IsKeepaliveFixEnabled() { return false; } inline bool IsKeepaliveServerFixEnabled() { return false; } +inline bool IsMaxPingsWoDataThrottleEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_MONITORING_EXPERIMENT inline bool IsMonitoringExperimentEnabled() { return true; } inline bool IsMultipingEnabled() { return false; } @@ -166,12 +167,12 @@ inline bool IsUnconstrainedMaxQuotaBufferSizeEnabled() { return false; } inline bool IsWorkSerializerClearsTimeCacheEnabled() { return true; } #define GRPC_EXPERIMENT_IS_INCLUDED_WORK_SERIALIZER_DISPATCH inline bool IsWorkSerializerDispatchEnabled() { return true; } +inline bool IsCallV3Enabled() { return false; } #endif #else enum ExperimentIds { kExperimentIdCallStatusOverrideOnCancellation, - kExperimentIdCallV3, kExperimentIdCanaryClientPrivacy, kExperimentIdClientPrivacy, kExperimentIdEventEngineClient, @@ -181,6 +182,7 @@ enum ExperimentIds { kExperimentIdHttp2StatsFix, kExperimentIdKeepaliveFix, kExperimentIdKeepaliveServerFix, + kExperimentIdMaxPingsWoDataThrottle, kExperimentIdMonitoringExperiment, kExperimentIdMultiping, kExperimentIdPeerStateBasedFraming, @@ -197,16 +199,13 @@ enum ExperimentIds { kExperimentIdUnconstrainedMaxQuotaBufferSize, kExperimentIdWorkSerializerClearsTimeCache, kExperimentIdWorkSerializerDispatch, + kExperimentIdCallV3, kNumExperiments }; #define GRPC_EXPERIMENT_IS_INCLUDED_CALL_STATUS_OVERRIDE_ON_CANCELLATION inline bool IsCallStatusOverrideOnCancellationEnabled() { return IsExperimentEnabled(kExperimentIdCallStatusOverrideOnCancellation); } -#define GRPC_EXPERIMENT_IS_INCLUDED_CALL_V3 -inline bool IsCallV3Enabled() { - return IsExperimentEnabled(kExperimentIdCallV3); -} #define GRPC_EXPERIMENT_IS_INCLUDED_CANARY_CLIENT_PRIVACY inline bool IsCanaryClientPrivacyEnabled() { return IsExperimentEnabled(kExperimentIdCanaryClientPrivacy); @@ -243,6 +242,10 @@ inline bool IsKeepaliveFixEnabled() { inline bool IsKeepaliveServerFixEnabled() { return IsExperimentEnabled(kExperimentIdKeepaliveServerFix); } +#define GRPC_EXPERIMENT_IS_INCLUDED_MAX_PINGS_WO_DATA_THROTTLE +inline bool IsMaxPingsWoDataThrottleEnabled() { + return IsExperimentEnabled(kExperimentIdMaxPingsWoDataThrottle); +} #define GRPC_EXPERIMENT_IS_INCLUDED_MONITORING_EXPERIMENT inline bool IsMonitoringExperimentEnabled() { return IsExperimentEnabled(kExperimentIdMonitoringExperiment); @@ -307,6 +310,10 @@ inline bool IsWorkSerializerClearsTimeCacheEnabled() { inline bool IsWorkSerializerDispatchEnabled() { return IsExperimentEnabled(kExperimentIdWorkSerializerDispatch); } +#define GRPC_EXPERIMENT_IS_INCLUDED_CALL_V3 +inline bool IsCallV3Enabled() { + return IsExperimentEnabled(kExperimentIdCallV3); +} extern const ExperimentMetadata g_experiment_metadata[kNumExperiments]; diff --git a/src/core/lib/experiments/experiments.yaml b/src/core/lib/experiments/experiments.yaml index 4d1a27e4d3c..5d2678f99d2 100644 --- a/src/core/lib/experiments/experiments.yaml +++ b/src/core/lib/experiments/experiments.yaml @@ -52,6 +52,8 @@ expiry: 2024/06/01 owner: ctiller@google.com test_tags: [] + requires: ["work_serializer_dispatch", "event_engine_listener", "event_engine_client"] + allow_in_fuzzing_config: false - name: canary_client_privacy description: If set, canary client privacy @@ -120,6 +122,14 @@ owner: yashkt@google.com test_tags: [] allow_in_fuzzing_config: false +- name: max_pings_wo_data_throttle + description: + Experiment to throttle pings to a period of 1 min when + GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA limit has reached (instead of + completely blocking). + expiry: 2024/12/31 + owner: yashkt@google.com + test_tags: [] - name: monitoring_experiment description: Placeholder experiment to prove/disprove our monitoring is working expiry: never-ever diff --git a/src/core/lib/experiments/rollouts.yaml b/src/core/lib/experiments/rollouts.yaml index 7187f8c2952..fe679a5718e 100644 --- a/src/core/lib/experiments/rollouts.yaml +++ b/src/core/lib/experiments/rollouts.yaml @@ -58,7 +58,7 @@ # not tested on iOS at all ios: broken posix: false - windows: true + windows: false - name: event_engine_dns default: # not tested on iOS at all @@ -79,6 +79,8 @@ default: false - name: keepalive_server_fix default: false +- name: max_pings_wo_data_throttle + default: false - name: monitoring_experiment default: true - name: peer_state_based_framing diff --git a/src/core/lib/gprpp/dual_ref_counted.h b/src/core/lib/gprpp/dual_ref_counted.h index 5641b0970d4..38365db381b 100644 --- a/src/core/lib/gprpp/dual_ref_counted.h +++ b/src/core/lib/gprpp/dual_ref_counted.h @@ -28,6 +28,7 @@ #include "src/core/lib/gprpp/debug_location.h" #include "src/core/lib/gprpp/down_cast.h" #include "src/core/lib/gprpp/orphanable.h" +#include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" namespace grpc_core { @@ -46,15 +47,16 @@ namespace grpc_core { // // This will be used by CRTP (curiously-recurring template pattern), e.g.: // class MyClass : public RefCounted { ... }; -template -class DualRefCounted { +// +// Impl & UnrefBehavior are as per RefCounted. +template +class DualRefCounted : public Impl { public: // Not copyable nor movable. DualRefCounted(const DualRefCounted&) = delete; DualRefCounted& operator=(const DualRefCounted&) = delete; - virtual ~DualRefCounted() = default; - GRPC_MUST_USE_RESULT RefCountedPtr Ref() { IncrementRefCount(); return RefCountedPtr(static_cast(this)); @@ -215,7 +217,7 @@ class DualRefCounted { CHECK_GT(weak_refs, 0u); #endif if (GPR_UNLIKELY(prev_ref_pair == MakeRefPair(0, 1))) { - delete static_cast(this); + unref_behavior_(static_cast(this)); } } void WeakUnref(const DebugLocation& location, const char* reason) { @@ -242,7 +244,7 @@ class DualRefCounted { (void)reason; #endif if (GPR_UNLIKELY(prev_ref_pair == MakeRefPair(0, 1))) { - delete static_cast(this); + unref_behavior_(static_cast(this)); } } @@ -266,6 +268,9 @@ class DualRefCounted { // Ref count has dropped to zero, so the object is now orphaned. virtual void Orphaned() = 0; + // Note: Depending on the Impl used, this dtor can be implicitly virtual. + ~DualRefCounted() = default; + private: // Allow RefCountedPtr<> to access IncrementRefCount(). template @@ -358,6 +363,7 @@ class DualRefCounted { const char* trace_; #endif std::atomic refs_{0}; + GPR_NO_UNIQUE_ADDRESS UnrefBehavior unref_behavior_; }; } // namespace grpc_core diff --git a/src/core/lib/promise/activity.h b/src/core/lib/promise/activity.h index daf3e76a6c2..715de5317f2 100644 --- a/src/core/lib/promise/activity.h +++ b/src/core/lib/promise/activity.h @@ -26,6 +26,7 @@ #include "absl/base/thread_annotations.h" #include "absl/log/check.h" #include "absl/status/status.h" +#include "absl/strings/str_cat.h" #include "absl/types/optional.h" #include @@ -121,6 +122,11 @@ class Waker { return wakeable_and_arg_.ActivityDebugTag(); } + std::string DebugString() { + return absl::StrFormat("Waker{%p, %d}", wakeable_and_arg_.wakeable, + wakeable_and_arg_.wakeup_mask); + } + // This is for tests to assert that a waker is occupied or not. bool is_unwakeable() const { return wakeable_and_arg_.wakeable == promise_detail::unwakeable(); @@ -283,6 +289,19 @@ class ContextHolder> { std::unique_ptr value_; }; +template +class ContextHolder> { + public: + using ContextType = Context; + + explicit ContextHolder(RefCountedPtr value) + : value_(std::move(value)) {} + Context* GetContext() { return value_.get(); } + + private: + RefCountedPtr value_; +}; + template <> class Context { public: @@ -290,19 +309,23 @@ class Context { }; template -using ContextTypeFromHeld = typename ContextHolder::ContextType; +using ContextTypeFromHeld = typename ContextHolder< + typename std::remove_reference::type>::ContextType; template -class ActivityContexts : public ContextHolder... { +class ActivityContexts + : public ContextHolder::type>... { public: explicit ActivityContexts(Contexts&&... contexts) - : ContextHolder(std::forward(contexts))... {} + : ContextHolder::type>( + std::forward(contexts))... {} class ScopedContext : public Context>... { public: explicit ScopedContext(ActivityContexts* contexts) : Context>( - static_cast*>(contexts) + static_cast::type>*>(contexts) ->GetContext())... { // Silence `unused-but-set-parameter` in case of Contexts = {} (void)contexts; diff --git a/src/core/lib/promise/context.h b/src/core/lib/promise/context.h index 47b2bac39f2..e1f1f6511d9 100644 --- a/src/core/lib/promise/context.h +++ b/src/core/lib/promise/context.h @@ -125,6 +125,11 @@ T* MaybeGetContext() { return promise_detail::Context::get(); } +template +void SetContext(T* p) { + promise_detail::Context::set(p); +} + // Given a promise and a context, return a promise that has that context set. template promise_detail::WithContext WithContext(F f, T* context) { diff --git a/src/core/lib/promise/map.h b/src/core/lib/promise/map.h index 6ee27fef83d..b1772ad5b51 100644 --- a/src/core/lib/promise/map.h +++ b/src/core/lib/promise/map.h @@ -72,6 +72,23 @@ promise_detail::Map Map(Promise promise, Fn fn) { return promise_detail::Map(std::move(promise), std::move(fn)); } +// Maps a promise to a new promise that returns a tuple of the original result +// and a bool indicating whether there was ever a Pending{} value observed from +// polling. +template +auto CheckDelayed(Promise promise) { + using P = promise_detail::PromiseLike; + return [delayed = false, promise = P(std::move(promise))]() mutable + -> Poll> { + auto r = promise(); + if (r.pending()) { + delayed = true; + return Pending{}; + } + return std::make_tuple(r.value(), delayed); + }; +} + // Callable that takes a tuple and returns one element template struct JustElem { diff --git a/src/core/lib/promise/observable.h b/src/core/lib/promise/observable.h index edf7a37515a..9337feace3f 100644 --- a/src/core/lib/promise/observable.h +++ b/src/core/lib/promise/observable.h @@ -125,6 +125,7 @@ class Observable { Observer& operator=(const Observer&) = delete; Observer(Observer&& other) noexcept : state_(std::move(other.state_)) { CHECK(other.waker_.is_unwakeable()); + DCHECK(waker_.is_unwakeable()); CHECK(!other.saw_pending_); } Observer& operator=(Observer&& other) noexcept = delete; diff --git a/src/core/lib/promise/party.cc b/src/core/lib/promise/party.cc index c030f43c4e0..58931d978d4 100644 --- a/src/core/lib/promise/party.cc +++ b/src/core/lib/promise/party.cc @@ -308,8 +308,10 @@ void Party::AddParticipants(Participant** participants, size_t count) { for (size_t i = 0; i < count; i++) { if (grpc_trace_party_state.enabled()) { gpr_log(GPR_INFO, - "Party %p AddParticipant: %s @ %" PRIdPTR, - &sync_, std::string(participants[i]->name()).c_str(), slots[i]); + "Party %p AddParticipant: %s @ %" PRIdPTR + " [participant=%p]", + &sync_, std::string(participants[i]->name()).c_str(), slots[i], + participants[i]); } participants_[slots[i]].store(participants[i], std::memory_order_release); } diff --git a/src/core/lib/promise/party.h b/src/core/lib/promise/party.h index 214c36a588f..d2467168c26 100644 --- a/src/core/lib/promise/party.h +++ b/src/core/lib/promise/party.h @@ -379,6 +379,11 @@ class Party : public Activity, private Wakeable { // The on_complete callback will be called with the result of the promise if // it completes. // A maximum of sixteen promises can be spawned onto a party. + // promise_factory called to create the promise with the party lock taken; + // after the promise is created the factory is destroyed. + // This means that pointers or references to factory members will be + // invalidated after the promise is created - so the promise should not retain + // any of these. template void Spawn(absl::string_view name, Factory promise_factory, OnComplete on_complete); diff --git a/src/core/lib/promise/promise.h b/src/core/lib/promise/promise.h index bad6aad81d0..1595f2a8782 100644 --- a/src/core/lib/promise/promise.h +++ b/src/core/lib/promise/promise.h @@ -18,6 +18,7 @@ #include #include "absl/functional/any_invocable.h" +#include "absl/log/log.h" #include "absl/status/status.h" #include "absl/types/optional.h" diff --git a/src/core/lib/resource_quota/arena.cc b/src/core/lib/resource_quota/arena.cc index a2969abe241..139f1e5cc61 100644 --- a/src/core/lib/resource_quota/arena.cc +++ b/src/core/lib/resource_quota/arena.cc @@ -21,17 +21,24 @@ #include #include +#include "absl/log/log.h" + #include #include +#include "src/core/lib/resource_quota/resource_quota.h" #include "src/core/util/alloc.h" +namespace grpc_core { namespace { -void* ArenaStorage(size_t initial_size) { +void* ArenaStorage(size_t& initial_size) { static constexpr size_t base_size = - GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_core::Arena)); + GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(Arena)); initial_size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(initial_size); + initial_size = std::max( + initial_size, GPR_ROUND_UP_TO_ALIGNMENT_SIZE( + arena_detail::BaseArenaContextTraits::ContextSize())); size_t alloc_size = base_size + initial_size; static constexpr size_t alignment = (GPR_CACHELINE_SIZE > GPR_MAX_ALIGNMENT && @@ -43,9 +50,15 @@ void* ArenaStorage(size_t initial_size) { } // namespace -namespace grpc_core { - Arena::~Arena() { + for (size_t i = 0; i < arena_detail::BaseArenaContextTraits::NumContexts(); + ++i) { + arena_detail::BaseArenaContextTraits::Destroy(i, contexts()[i]); + } + DestroyManagedNewObjects(); + arena_factory_->FinalizeArena(this); + arena_factory_->allocator().Release( + total_allocated_.load(std::memory_order_relaxed)); Zone* z = last_zone_; while (z) { Zone* prev_z = z->prev; @@ -53,24 +66,26 @@ Arena::~Arena() { gpr_free_aligned(z); z = prev_z; } -#ifdef GRPC_ARENA_TRACE_POOLED_ALLOCATIONS - gpr_log(GPR_ERROR, "DESTRUCT_ARENA %p", this); -#endif } -Arena* Arena::Create(size_t initial_size, MemoryAllocator* memory_allocator) { - return new (ArenaStorage(initial_size)) - Arena(initial_size, 0, memory_allocator); +RefCountedPtr Arena::Create(size_t initial_size, + RefCountedPtr arena_factory) { + void* p = ArenaStorage(initial_size); + return RefCountedPtr( + new (p) Arena(initial_size, std::move(arena_factory))); } -std::pair Arena::CreateWithAlloc( - size_t initial_size, size_t alloc_size, MemoryAllocator* memory_allocator) { - static constexpr size_t base_size = - GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(Arena)); - auto* new_arena = new (ArenaStorage(initial_size)) - Arena(initial_size, alloc_size, memory_allocator); - void* first_alloc = reinterpret_cast(new_arena) + base_size; - return std::make_pair(new_arena, first_alloc); +Arena::Arena(size_t initial_size, RefCountedPtr arena_factory) + : initial_zone_size_(initial_size), + total_used_(GPR_ROUND_UP_TO_ALIGNMENT_SIZE( + arena_detail::BaseArenaContextTraits::ContextSize())), + arena_factory_(std::move(arena_factory)) { + for (size_t i = 0; i < arena_detail::BaseArenaContextTraits::NumContexts(); + ++i) { + contexts()[i] = nullptr; + } + CHECK_GE(initial_size, arena_detail::BaseArenaContextTraits::ContextSize()); + arena_factory_->allocator().Reserve(initial_size); } void Arena::DestroyManagedNewObjects() { @@ -86,11 +101,9 @@ void Arena::DestroyManagedNewObjects() { } } -void Arena::Destroy() { - DestroyManagedNewObjects(); - memory_allocator_->Release(total_allocated_.load(std::memory_order_relaxed)); +void Arena::Destroy() const { this->~Arena(); - gpr_free_aligned(this); + gpr_free_aligned(const_cast(this)); } void* Arena::AllocZone(size_t size) { @@ -102,7 +115,7 @@ void* Arena::AllocZone(size_t size) { static constexpr size_t zone_base_size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(Zone)); size_t alloc_size = zone_base_size + size; - memory_allocator_->Reserve(alloc_size); + arena_factory_->allocator().Reserve(alloc_size); total_allocated_.fetch_add(alloc_size, std::memory_order_relaxed); Zone* z = new (gpr_malloc_aligned(alloc_size, GPR_MAX_ALIGNMENT)) Zone(); auto* prev = last_zone_.load(std::memory_order_relaxed); @@ -120,63 +133,27 @@ void Arena::ManagedNewObject::Link(std::atomic* head) { } } -#ifndef GRPC_ARENA_POOLED_ALLOCATIONS_USE_MALLOC -void* Arena::AllocPooled(size_t obj_size, size_t alloc_size, - std::atomic* head) { - // ABA mitigation: - // AllocPooled may be called by multiple threads, and to remove a node from - // the free list we need to manipulate the next pointer, which may be done - // differently by each thread in a naive implementation. - // The literature contains various ways of dealing with this. Here we expect - // to be mostly single threaded - Arena's are owned by calls and calls don't - // do a lot of concurrent work with the pooled allocator. The place that they - // do is allocating metadata batches for decoding HPACK headers in chttp2. - // So we adopt an approach that is simple and fast for the single threaded - // case, and that is also correct in the multi threaded case. - - // First, take ownership of the entire free list. At this point we know that - // no other thread can see free nodes and will be forced to allocate. - // We think we're mostly single threaded and so that's ok. - FreePoolNode* p = head->exchange(nullptr, std::memory_order_acquire); - // If there are no nodes in the free list, then go ahead and allocate from the - // arena. - if (p == nullptr) { - void* r = Alloc(alloc_size); - TracePoolAlloc(obj_size, r); - return r; - } - // We had a non-empty free list... but we own the *entire* free list. - // We only want one node, so if there are extras we'd better give them back. - if (p->next != nullptr) { - // We perform an exchange to do so, but if there were concurrent frees with - // this allocation then there'll be a free list that needs to be merged with - // ours. - FreePoolNode* extra = head->exchange(p->next, std::memory_order_acq_rel); - // If there was a free list concurrently created, we merge it into the - // overall free list here by simply freeing each node in turn. This is O(n), - // but only O(n) in the number of nodes that were freed concurrently, and - // again: we think real world use cases are going to see this as mostly - // single threaded. - while (extra != nullptr) { - FreePoolNode* next = extra->next; - FreePooled(extra, head); - extra = next; +RefCountedPtr SimpleArenaAllocator(size_t initial_size) { + class Allocator : public ArenaFactory { + public: + explicit Allocator(size_t initial_size) + : ArenaFactory( + ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator( + "simple-arena-allocator")), + initial_size_(initial_size) {} + + RefCountedPtr MakeArena() override { + return Arena::Create(initial_size_, Ref()); } - } - TracePoolAlloc(obj_size, p); - return p; -} -void Arena::FreePooled(void* p, std::atomic* head) { - // May spuriously trace a free of an already freed object - see AllocPooled - // ABA mitigation. - TracePoolFree(p); - FreePoolNode* node = static_cast(p); - node->next = head->load(std::memory_order_acquire); - while (!head->compare_exchange_weak( - node->next, node, std::memory_order_acq_rel, std::memory_order_relaxed)) { - } + void FinalizeArena(Arena*) override { + // No-op. + } + + private: + size_t initial_size_; + }; + return MakeRefCounted(initial_size); } -#endif } // namespace grpc_core diff --git a/src/core/lib/resource_quota/arena.h b/src/core/lib/resource_quota/arena.h index 813004087b7..0b92e4b5b74 100644 --- a/src/core/lib/resource_quota/arena.h +++ b/src/core/lib/resource_quota/arena.h @@ -40,76 +40,63 @@ #include "src/core/lib/resource_quota/memory_quota.h" #include "src/core/util/alloc.h" -#define GRPC_ARENA_POOLED_ALLOCATIONS_USE_MALLOC -// #define GRPC_ARENA_TRACE_POOLED_ALLOCATIONS - namespace grpc_core { -namespace arena_detail { +class Arena; -#ifndef GRPC_ARENA_POOLED_ALLOCATIONS_USE_MALLOC -struct PoolAndSize { - size_t alloc_size; - size_t pool_index; -}; +template +struct ArenaContextType; -template -struct PoolIndexForSize; - -template -struct PoolIndexForSize< - absl::enable_if_t, kIndex, - kObjectSize, kSmallestRemainingBucket, kBucketSizes...> { - static constexpr size_t kPool = kIndex; - static constexpr size_t kSize = kSmallestRemainingBucket; -}; +namespace arena_detail { -template -struct PoolIndexForSize< - absl::enable_if_t<(kObjectSize > kSmallestRemainingBucket)>, kIndex, - kObjectSize, kSmallestRemainingBucket, kBucketSizes...> - : public PoolIndexForSize { -}; +// Tracks all registered arena context types (these should only be registered +// via ArenaContextTraits at static initialization time). +class BaseArenaContextTraits { + public: + // Count of number of contexts that have been allocated. + static uint16_t NumContexts() { + return static_cast(RegisteredTraits().size()); + } -template -constexpr size_t PoolFromObjectSize( - absl::integer_sequence) { - return PoolIndexForSize::kPool; -} + // Number of bytes required to store the context pointers on an arena. + static size_t ContextSize() { return NumContexts() * sizeof(void*); } -template -constexpr size_t AllocationSizeFromObjectSize( - absl::integer_sequence) { - return PoolIndexForSize::kSize; -} + // Call the registered destruction function for a context. + static void Destroy(uint16_t id, void* ptr) { + if (ptr == nullptr) return; + RegisteredTraits()[id](ptr); + } -template -struct ChoosePoolForAllocationSizeImpl; + protected: + // Allocate a new context id and register the destruction function. + static uint16_t MakeId(void (*destroy)(void* ptr)) { + auto& traits = RegisteredTraits(); + const uint16_t id = static_cast(traits.size()); + traits.push_back(destroy); + return id; + } -template -struct ChoosePoolForAllocationSizeImpl { - static PoolAndSize Fn(size_t n) { - if (n <= kBucketSize) return {kBucketSize, kIndex}; - return ChoosePoolForAllocationSizeImpl::Fn(n); + private: + static std::vector& RegisteredTraits() { + static NoDestruct> registered_traits; + return *registered_traits; } }; -template -struct ChoosePoolForAllocationSizeImpl { - static PoolAndSize Fn(size_t n) { - return PoolAndSize{n, std::numeric_limits::max()}; - } +// Traits for a specific context type. +template +class ArenaContextTraits : public BaseArenaContextTraits { + public: + static uint16_t id() { return id_; } + + private: + static const uint16_t id_; }; -template -PoolAndSize ChoosePoolForAllocationSize( - size_t n, absl::integer_sequence) { - return ChoosePoolForAllocationSizeImpl<0, kBucketSizes...>::Fn(n); -} -#else +template +const uint16_t ArenaContextTraits::id_ = BaseArenaContextTraits::MakeId( + [](void* ptr) { ArenaContextType::Destroy(static_cast(ptr)); }); + template struct IfArray { using Result = A; @@ -119,30 +106,36 @@ template struct IfArray { using Result = B; }; -#endif + +struct UnrefDestroy { + void operator()(const Arena* arena) const; +}; } // namespace arena_detail -class Arena { -#ifndef GRPC_ARENA_POOLED_ALLOCATIONS_USE_MALLOC - // Selected pool sizes. - // How to tune: see tools/codegen/core/optimize_arena_pool_sizes.py - using PoolSizes = absl::integer_sequence; - struct FreePoolNode { - FreePoolNode* next; - }; -#endif +class ArenaFactory : public RefCounted { + public: + virtual RefCountedPtr MakeArena() = 0; + virtual void FinalizeArena(Arena* arena) = 0; + + MemoryAllocator& allocator() { return allocator_; } + protected: + explicit ArenaFactory(MemoryAllocator allocator) + : allocator_(std::move(allocator)) {} + + private: + MemoryAllocator allocator_; +}; + +RefCountedPtr SimpleArenaAllocator(size_t initial_size = 1024); + +class Arena final : public RefCounted { public: // Create an arena, with \a initial_size bytes in the first allocated buffer. - static Arena* Create(size_t initial_size, MemoryAllocator* memory_allocator); - - // Create an arena, with \a initial_size bytes in the first allocated buffer, - // and return both a void pointer to the returned arena and a void* with the - // first allocation. - static std::pair CreateWithAlloc( - size_t initial_size, size_t alloc_size, - MemoryAllocator* memory_allocator); + static RefCountedPtr Create(size_t initial_size, + RefCountedPtr arena_factory); // Destroy all `ManagedNew` allocated objects. // Allows safe destruction of these objects even if they need context held by @@ -151,9 +144,6 @@ class Arena { // TODO(ctiller): eliminate ManagedNew. void DestroyManagedNewObjects(); - // Destroy an arena. - void Destroy(); - // Return the total amount of memory allocated by this arena. size_t TotalUsedBytes() const { return total_used_.load(std::memory_order_relaxed); @@ -194,95 +184,6 @@ class Arena { return &p->t; } -#ifndef GRPC_ARENA_POOLED_ALLOCATIONS_USE_MALLOC - class PooledDeleter { - public: - explicit PooledDeleter(std::atomic* free_list) - : free_list_(free_list) {} - PooledDeleter() = default; - template - void operator()(T* p) { - // TODO(ctiller): promise based filter hijacks ownership of some pointers - // to make them appear as PoolPtr without really transferring ownership, - // by setting the arena to nullptr. - // This is a transitional hack and should be removed once promise based - // filter is removed. - if (free_list_ != nullptr) { - p->~T(); - FreePooled(p, free_list_); - } - } - - bool has_freelist() const { return free_list_ != nullptr; } - - private: - std::atomic* free_list_; - }; - - template - using PoolPtr = std::unique_ptr; - - // Make a unique_ptr to T that is allocated from the arena. - // When the pointer is released, the memory may be reused for other - // MakePooled(.*) calls. - // CAUTION: The amount of memory allocated is rounded up to the nearest - // value in Arena::PoolSizes, and so this may pessimize total - // arena size. - template - PoolPtr MakePooled(Args&&... args) { - auto* free_list = - &pools_[arena_detail::PoolFromObjectSize(PoolSizes())]; - return PoolPtr( - new (AllocPooled( - sizeof(T), - arena_detail::AllocationSizeFromObjectSize(PoolSizes()), - free_list)) T(std::forward(args)...), - PooledDeleter(free_list)); - } - - // Make a unique_ptr to an array of T that is allocated from the arena. - // When the pointer is released, the memory may be reused for other - // MakePooled(.*) calls. - // One can use MakePooledArray to allocate a buffer of bytes. - // CAUTION: The amount of memory allocated is rounded up to the nearest - // value in Arena::PoolSizes, and so this may pessimize total - // arena size. - template - PoolPtr MakePooledArray(size_t n) { - auto where = - arena_detail::ChoosePoolForAllocationSize(n * sizeof(T), PoolSizes()); - if (where.pool_index == std::numeric_limits::max()) { - return PoolPtr(new (Alloc(where.alloc_size)) T[n], - PooledDeleter(nullptr)); - } else { - return PoolPtr(new (AllocPooled(where.alloc_size, where.alloc_size, - &pools_[where.pool_index])) T[n], - PooledDeleter(&pools_[where.pool_index])); - } - } - - // Like MakePooled, but with manual memory management. - // The caller is responsible for calling DeletePooled() on the returned - // pointer, and expected to call it with the same type T as was passed to this - // function (else the free list returned to the arena will be corrupted). - template - T* NewPooled(Args&&... args) { - auto* free_list = - &pools_[arena_detail::PoolFromObjectSize(PoolSizes())]; - return new (AllocPooled( - sizeof(T), - arena_detail::AllocationSizeFromObjectSize(PoolSizes()), - free_list)) T(std::forward(args)...); - } - - template - void DeletePooled(T* p) { - auto* free_list = - &pools_[arena_detail::PoolFromObjectSize(PoolSizes())]; - p->~T(); - FreePooled(p, free_list); - } -#else class PooledDeleter { public: PooledDeleter() = default; @@ -364,9 +265,25 @@ class Arena { void DeletePooled(T* p) { delete p; } -#endif + + template + T* GetContext() { + return static_cast( + contexts()[arena_detail::ArenaContextTraits::id()]); + } + + template + void SetContext(T* context) { + void*& slot = contexts()[arena_detail::ArenaContextTraits::id()]; + if (slot != nullptr) { + ArenaContextType::Destroy(static_cast(slot)); + } + slot = context; + } private: + friend struct arena_detail::UnrefDestroy; + struct Zone { Zone* prev; }; @@ -396,41 +313,20 @@ class Arena { // quick optimization (avoiding an atomic fetch-add) for the common case // where we wish to create an arena and then perform an immediate // allocation. - explicit Arena(size_t initial_size, size_t initial_alloc, - MemoryAllocator* memory_allocator) - : total_used_(GPR_ROUND_UP_TO_ALIGNMENT_SIZE(initial_alloc)), - initial_zone_size_(initial_size), - memory_allocator_(memory_allocator) {} + explicit Arena(size_t initial_size, + RefCountedPtr arena_factory); ~Arena(); void* AllocZone(size_t size); - -#ifndef GRPC_ARENA_POOLED_ALLOCATIONS_USE_MALLOC - void* AllocPooled(size_t obj_size, size_t alloc_size, - std::atomic* head); - static void FreePooled(void* p, std::atomic* head); -#endif - - void TracePoolAlloc(size_t size, void* ptr) { - (void)size; - (void)ptr; -#ifdef GRPC_ARENA_TRACE_POOLED_ALLOCATIONS - gpr_log(GPR_ERROR, "ARENA %p ALLOC %" PRIdPTR " @ %p", this, size, ptr); -#endif - } - static void TracePoolFree(void* ptr) { - (void)ptr; -#ifdef GRPC_ARENA_TRACE_POOLED_ALLOCATIONS - gpr_log(GPR_ERROR, "FREE %p", ptr); -#endif - } + void Destroy() const; + void** contexts() { return reinterpret_cast(this + 1); } // Keep track of the total used size. We use this in our call sizing // hysteresis. - std::atomic total_used_{0}; - std::atomic total_allocated_{0}; const size_t initial_zone_size_; + std::atomic total_used_; + std::atomic total_allocated_{initial_zone_size_}; // If the initial arena allocation wasn't enough, we allocate additional zones // in a reverse linked list. Each additional zone consists of (1) a pointer to // the zone added before this zone (null if this is the first additional zone) @@ -438,27 +334,30 @@ class Arena { // last zone; the zone list is reverse-walked during arena destruction only. std::atomic last_zone_{nullptr}; std::atomic managed_new_head_{nullptr}; -#ifndef GRPC_ARENA_POOLED_ALLOCATIONS_USE_MALLOC - std::atomic pools_[PoolSizes::size()]{}; -#endif - // The backing memory quota - MemoryAllocator* const memory_allocator_; -}; - -// Smart pointer for arenas when the final size is not required. -struct ScopedArenaDeleter { - void operator()(Arena* arena) { arena->Destroy(); } + RefCountedPtr arena_factory_; }; -using ScopedArenaPtr = std::unique_ptr; -inline ScopedArenaPtr MakeScopedArena(size_t initial_size, - MemoryAllocator* memory_allocator) { - return ScopedArenaPtr(Arena::Create(initial_size, memory_allocator)); -} // Arenas form a context for activities template <> struct ContextType {}; +namespace arena_detail { +inline void UnrefDestroy::operator()(const Arena* arena) const { + arena->Destroy(); +} +} // namespace arena_detail + +namespace promise_detail { + +template +class Context::Destroy)>> { + public: + static T* get() { return GetContext()->GetContext(); } + static void set(T* value) { GetContext()->SetContext(value); } +}; + +} // namespace promise_detail + } // namespace grpc_core #endif // GRPC_SRC_CORE_LIB_RESOURCE_QUOTA_ARENA_H diff --git a/src/core/lib/resource_quota/memory_quota.cc b/src/core/lib/resource_quota/memory_quota.cc index 79702ce7fff..458597da5da 100644 --- a/src/core/lib/resource_quota/memory_quota.cc +++ b/src/core/lib/resource_quota/memory_quota.cc @@ -253,9 +253,9 @@ GrpcMemoryAllocatorImpl::GrpcMemoryAllocatorImpl( } GrpcMemoryAllocatorImpl::~GrpcMemoryAllocatorImpl() { - CHECK(free_bytes_.load(std::memory_order_acquire) + - sizeof(GrpcMemoryAllocatorImpl) == - taken_bytes_.load(std::memory_order_relaxed)); + CHECK_EQ(free_bytes_.load(std::memory_order_acquire) + + sizeof(GrpcMemoryAllocatorImpl), + taken_bytes_.load(std::memory_order_relaxed)); memory_quota_->Return(taken_bytes_.load(std::memory_order_relaxed)); } diff --git a/src/core/lib/security/credentials/channel_creds_registry_init.cc b/src/core/lib/security/credentials/channel_creds_registry_init.cc index 9b7a0e04372..832daba1284 100644 --- a/src/core/lib/security/credentials/channel_creds_registry_init.cc +++ b/src/core/lib/security/credentials/channel_creds_registry_init.cc @@ -96,6 +96,8 @@ class TlsChannelCredsFactory : public ChannelCredsFactory<> { } options->set_watch_root_cert(!config->ca_certificate_file().empty()); options->set_watch_identity_pair(!config->certificate_file().empty()); + options->set_certificate_verifier( + MakeRefCounted()); return MakeRefCounted(std::move(options)); } 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 06122b04a81..27d1b88ef1a 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 @@ -39,10 +39,10 @@ #include #include "src/core/lib/gprpp/env.h" -#include "src/core/lib/http/httpcli_ssl_credentials.h" #include "src/core/lib/iomgr/closure.h" #include "src/core/lib/security/credentials/credentials.h" #include "src/core/lib/uri/uri_parser.h" +#include "src/core/util/http_client/httpcli_ssl_credentials.h" #include "src/core/util/json/json.h" #include "src/core/util/json/json_reader.h" #include "src/core/util/json/json_writer.h" 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 50e7d86b58b..c7dc1f166c3 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 @@ -28,11 +28,11 @@ #include "src/core/lib/gprpp/orphanable.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" -#include "src/core/lib/http/httpcli.h" -#include "src/core/lib/http/parser.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/security/credentials/external/aws_request_signer.h" #include "src/core/lib/security/credentials/external/external_account_credentials.h" +#include "src/core/util/http_client/httpcli.h" +#include "src/core/util/http_client/parser.h" namespace grpc_core { 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 f604d1e9815..f7fd5a805e1 100644 --- a/src/core/lib/security/credentials/external/external_account_credentials.cc +++ b/src/core/lib/security/credentials/external/external_account_credentials.cc @@ -46,14 +46,14 @@ #include #include "src/core/lib/gprpp/status_helper.h" -#include "src/core/lib/http/httpcli_ssl_credentials.h" -#include "src/core/lib/http/parser.h" #include "src/core/lib/security/credentials/credentials.h" #include "src/core/lib/security/credentials/external/aws_external_account_credentials.h" #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/uri/uri_parser.h" +#include "src/core/util/http_client/httpcli_ssl_credentials.h" +#include "src/core/util/http_client/parser.h" #include "src/core/util/json/json_reader.h" #include "src/core/util/json/json_writer.h" 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 c194fd60163..f0023ab878e 100644 --- a/src/core/lib/security/credentials/external/external_account_credentials.h +++ b/src/core/lib/security/credentials/external/external_account_credentials.h @@ -30,12 +30,12 @@ #include "src/core/lib/gprpp/orphanable.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/gprpp/time.h" -#include "src/core/lib/http/httpcli.h" -#include "src/core/lib/http/parser.h" #include "src/core/lib/iomgr/closure.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/polling_entity.h" #include "src/core/lib/security/credentials/oauth2/oauth2_credentials.h" +#include "src/core/util/http_client/httpcli.h" +#include "src/core/util/http_client/parser.h" #include "src/core/util/json/json.h" namespace grpc_core { 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 cf9d646e579..b2a5359c596 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 @@ -37,11 +37,11 @@ #include #include -#include "src/core/lib/http/httpcli_ssl_credentials.h" -#include "src/core/lib/http/parser.h" #include "src/core/lib/iomgr/closure.h" #include "src/core/lib/security/credentials/credentials.h" #include "src/core/lib/transport/error_utils.h" +#include "src/core/util/http_client/httpcli_ssl_credentials.h" +#include "src/core/util/http_client/parser.h" #include "src/core/util/json/json.h" #include "src/core/util/json/json_reader.h" 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 6a5f00cd23b..209e652a15c 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 @@ -28,10 +28,10 @@ #include "src/core/lib/gprpp/orphanable.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" -#include "src/core/lib/http/httpcli.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/security/credentials/external/external_account_credentials.h" #include "src/core/lib/uri/uri_parser.h" +#include "src/core/util/http_client/httpcli.h" namespace grpc_core { diff --git a/src/core/lib/security/credentials/google_default/google_default_credentials.cc b/src/core/lib/security/credentials/google_default/google_default_credentials.cc index 86602f6c519..3e6b843b972 100644 --- a/src/core/lib/security/credentials/google_default/google_default_credentials.cc +++ b/src/core/lib/security/credentials/google_default/google_default_credentials.cc @@ -49,8 +49,6 @@ #include "src/core/lib/gprpp/status_helper.h" #include "src/core/lib/gprpp/sync.h" #include "src/core/lib/gprpp/time.h" -#include "src/core/lib/http/httpcli.h" -#include "src/core/lib/http/parser.h" #include "src/core/lib/iomgr/closure.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/exec_ctx.h" @@ -70,6 +68,8 @@ #include "src/core/lib/uri/uri_parser.h" #include "src/core/load_balancing/grpclb/grpclb.h" #include "src/core/load_balancing/xds/xds_channel_args.h" +#include "src/core/util/http_client/httpcli.h" +#include "src/core/util/http_client/parser.h" #include "src/core/util/json/json.h" #include "src/core/util/json/json_reader.h" diff --git a/src/core/lib/security/credentials/jwt/jwt_verifier.cc b/src/core/lib/security/credentials/jwt/jwt_verifier.cc index 02a7c548e98..e88b909696f 100644 --- a/src/core/lib/security/credentials/jwt/jwt_verifier.cc +++ b/src/core/lib/security/credentials/jwt/jwt_verifier.cc @@ -58,9 +58,6 @@ #include "src/core/lib/gprpp/manual_constructor.h" #include "src/core/lib/gprpp/memory.h" #include "src/core/lib/gprpp/orphanable.h" -#include "src/core/lib/http/httpcli.h" -#include "src/core/lib/http/httpcli_ssl_credentials.h" -#include "src/core/lib/http/parser.h" #include "src/core/lib/iomgr/closure.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/exec_ctx.h" @@ -71,6 +68,9 @@ #include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/uri/uri_parser.h" #include "src/core/tsi/ssl_types.h" +#include "src/core/util/http_client/httpcli.h" +#include "src/core/util/http_client/httpcli_ssl_credentials.h" +#include "src/core/util/http_client/parser.h" #include "src/core/util/json/json_reader.h" #include "src/core/util/string.h" diff --git a/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc b/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc index 313485e53d6..834dae28305 100644 --- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc +++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc @@ -51,7 +51,6 @@ #include "src/core/lib/gprpp/memory.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/gprpp/status_helper.h" -#include "src/core/lib/http/httpcli_ssl_credentials.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/pollset_set.h" #include "src/core/lib/promise/context.h" @@ -62,6 +61,7 @@ #include "src/core/lib/transport/error_utils.h" #include "src/core/lib/transport/metadata_batch.h" #include "src/core/lib/uri/uri_parser.h" +#include "src/core/util/http_client/httpcli_ssl_credentials.h" #include "src/core/util/json/json.h" #include "src/core/util/json/json_reader.h" diff --git a/src/core/lib/security/credentials/oauth2/oauth2_credentials.h b/src/core/lib/security/credentials/oauth2/oauth2_credentials.h index 5144905284b..199f35f33c8 100644 --- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.h +++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.h @@ -37,8 +37,6 @@ #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/gprpp/time.h" #include "src/core/lib/gprpp/unique_type_name.h" -#include "src/core/lib/http/httpcli.h" -#include "src/core/lib/http/parser.h" #include "src/core/lib/iomgr/closure.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/polling_entity.h" @@ -48,6 +46,8 @@ #include "src/core/lib/slice/slice.h" #include "src/core/lib/transport/transport.h" #include "src/core/lib/uri/uri_parser.h" +#include "src/core/util/http_client/httpcli.h" +#include "src/core/util/http_client/parser.h" #include "src/core/util/json/json.h" #include "src/core/util/useful.h" diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc index 9a54226862b..5f0d4a99310 100644 --- a/src/core/lib/surface/call.cc +++ b/src/core/lib/surface/call.cc @@ -380,15 +380,15 @@ void Call::Run() { class ChannelBasedCall : public Call { protected: - ChannelBasedCall(Arena* arena, bool is_client, Timestamp send_deadline, - RefCountedPtr channel) + ChannelBasedCall(RefCountedPtr arena, bool is_client, + Timestamp send_deadline, RefCountedPtr channel) : Call(is_client, send_deadline, channel->event_engine()), - arena_(arena), + arena_(std::move(arena)), channel_(std::move(channel)) { - DCHECK_NE(arena_, nullptr); + DCHECK_NE(arena_.get(), nullptr); } - Arena* arena() final { return arena_; } + Arena* arena() final { return arena_.get(); } char* GetPeer() final { Slice peer_slice = GetPeerString(); @@ -415,18 +415,17 @@ class ChannelBasedCall : public Call { void DeleteThis() { RefCountedPtr channel = std::move(channel_); - Arena* arena = arena_; + RefCountedPtr arena = arena_; this->~ChannelBasedCall(); - channel->DestroyArena(arena); } Channel* channel() const { return channel_.get(); } // Non-virtual arena accessor -- needed by PipeBasedCall - Arena* GetArena() { return arena_; } + Arena* GetArena() { return arena_.get(); } private: - Arena* const arena_; + const RefCountedPtr arena_; RefCountedPtr channel_; }; @@ -597,8 +596,9 @@ class FilterStackCall final : public ChannelBasedCall { void FinishBatch(grpc_error_handle error); }; - FilterStackCall(Arena* arena, const grpc_call_create_args& args) - : ChannelBasedCall(arena, args.server_transport_data == nullptr, + FilterStackCall(RefCountedPtr arena, const grpc_call_create_args& args) + : ChannelBasedCall(std::move(arena), + args.server_transport_data == nullptr, args.send_deadline, args.channel->Ref()), cq_(args.cq), stream_op_payload_(context_) { @@ -732,7 +732,7 @@ grpc_error_handle FilterStackCall::Create(grpc_call_create_args* args, GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(FilterStackCall)) + channel_stack->call_stack_size; - Arena* arena = channel->CreateArena(); + RefCountedPtr arena = channel->call_arena_allocator()->MakeArena(); call = new (arena->Alloc(call_alloc_size)) FilterStackCall(arena, *args); DCHECK(FromC(call->c_ptr()) == call); DCHECK(FromCallStack(call->call_stack()) == call); @@ -771,7 +771,7 @@ grpc_error_handle FilterStackCall::Create(grpc_call_create_args* args, args->server->server_call_tracer_factory() != nullptr) { auto* server_call_tracer = args->server->server_call_tracer_factory()->CreateNewServerCallTracer( - arena, args->server->channel_args()); + arena.get(), args->server->channel_args()); if (server_call_tracer != nullptr) { // Note that we are setting both // GRPC_CONTEXT_CALL_TRACER_ANNOTATION_INTERFACE and @@ -1906,10 +1906,12 @@ class BasicPromiseBasedCall : public ChannelBasedCall, public Party { public: using Call::arena; - BasicPromiseBasedCall(Arena* arena, uint32_t initial_external_refs, + BasicPromiseBasedCall(RefCountedPtr arena, + uint32_t initial_external_refs, uint32_t initial_internal_refs, const grpc_call_create_args& args) - : ChannelBasedCall(arena, args.server_transport_data == nullptr, + : ChannelBasedCall(std::move(arena), + args.server_transport_data == nullptr, args.send_deadline, args.channel->Ref()), Party(initial_internal_refs), external_refs_(initial_external_refs), @@ -2067,7 +2069,7 @@ class BasicPromiseBasedCall : public ChannelBasedCall, public Party { class PromiseBasedCall : public BasicPromiseBasedCall { public: - PromiseBasedCall(Arena* arena, uint32_t initial_external_refs, + PromiseBasedCall(RefCountedPtr arena, uint32_t initial_external_refs, const grpc_call_create_args& args); bool Completed() final { return finished_.IsSet(); } @@ -2348,17 +2350,17 @@ template grpc_error_handle MakePromiseBasedCall(grpc_call_create_args* args, grpc_call** out_call) { Channel* channel = args->channel.get(); - - auto* arena = channel->CreateArena(); + auto arena = channel->call_arena_allocator()->MakeArena(); PromiseBasedCall* call = arena->New(arena, args); *out_call = call->c_ptr(); DCHECK(Call::FromC(*out_call) == call); return absl::OkStatus(); } -PromiseBasedCall::PromiseBasedCall(Arena* arena, uint32_t initial_external_refs, +PromiseBasedCall::PromiseBasedCall(RefCountedPtr arena, + uint32_t initial_external_refs, const grpc_call_create_args& args) - : BasicPromiseBasedCall(arena, initial_external_refs, + : BasicPromiseBasedCall(std::move(arena), initial_external_refs, initial_external_refs != 0 ? 1 : 0, args) {} static void CToMetadata(grpc_metadata* metadata, size_t count, @@ -2591,8 +2593,9 @@ void PublishMetadataArray(grpc_metadata_batch* md, grpc_metadata_array* array, #ifdef GRPC_EXPERIMENT_IS_INCLUDED_PROMISE_BASED_CLIENT_CALL class ClientPromiseBasedCall final : public PromiseBasedCall { public: - ClientPromiseBasedCall(Arena* arena, grpc_call_create_args* args) - : PromiseBasedCall(arena, 1, *args), + ClientPromiseBasedCall(RefCountedPtr arena, + grpc_call_create_args* args) + : PromiseBasedCall(std::move(arena), 1, *args), polling_entity_( args->cq != nullptr ? grpc_polling_entity_create_from_pollset( diff --git a/src/core/lib/surface/call.h b/src/core/lib/surface/call.h index c0ccaf842cc..d464de2ec89 100644 --- a/src/core/lib/surface/call.h +++ b/src/core/lib/surface/call.h @@ -130,6 +130,8 @@ class Call : public CppImplOf, // Implementation of EventEngine::Closure, called when deadline expires void Run() final; + gpr_cycle_counter start_time() const { return start_time_; } + protected: // The maximum number of concurrent batches possible. // Based upon the maximum number of individually queueable ops in the batch @@ -209,8 +211,6 @@ class Call : public CppImplOf, void HandleCompressionAlgorithmNotAccepted( grpc_compression_algorithm compression_algorithm) GPR_ATTRIBUTE_NOINLINE; - gpr_cycle_counter start_time() const { return start_time_; } - virtual grpc_compression_options compression_options() = 0; private: diff --git a/src/core/lib/surface/channel.cc b/src/core/lib/surface/channel.cc index b8134974794..3d2deba0698 100644 --- a/src/core/lib/surface/channel.cc +++ b/src/core/lib/surface/channel.cc @@ -65,7 +65,12 @@ Channel::RegisteredCall::~RegisteredCall() {} Channel::Channel(std::string target, const ChannelArgs& channel_args) : target_(std::move(target)), channelz_node_(channel_args.GetObjectRef()), - compression_options_(CompressionOptionsFromChannelArgs(channel_args)) {} + compression_options_(CompressionOptionsFromChannelArgs(channel_args)), + call_arena_allocator_(MakeRefCounted( + channel_args.GetObject() + ->memory_quota() + ->CreateMemoryOwner(), + 1024)) {} Channel::RegisteredCall* Channel::RegisterCall(const char* method, const char* host) { diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h index 533a944c18c..9d207ae5f2c 100644 --- a/src/core/lib/surface/channel.h +++ b/src/core/lib/surface/channel.h @@ -40,8 +40,10 @@ #include "src/core/lib/gprpp/time.h" #include "src/core/lib/iomgr/iomgr_fwd.h" #include "src/core/lib/resource_quota/arena.h" +#include "src/core/lib/resource_quota/resource_quota.h" #include "src/core/lib/slice/slice.h" #include "src/core/lib/surface/channel_stack_type.h" +#include "src/core/lib/transport/call_arena_allocator.h" #include "src/core/lib/transport/connectivity_state.h" // Forward declaration to avoid dependency loop. @@ -52,7 +54,7 @@ namespace grpc_core { // Forward declaration to avoid dependency loop. class Transport; -class Channel : public RefCounted, +class Channel : public InternallyRefCounted, public CppImplOf { public: struct RegisteredCall { @@ -66,10 +68,17 @@ class Channel : public RefCounted, ~RegisteredCall(); }; - virtual void Orphan() = 0; - - virtual Arena* CreateArena() = 0; - virtual void DestroyArena(Arena* arena) = 0; + // Though internally ref counted channels expose their "Ref" method to + // create a RefCountedPtr to themselves. The OrphanablePtr owner is the + // singleton decision maker on whether the channel should be destroyed or + // not. + // TODO(ctiller): in a future change (I have it written) these will be removed + // and substituted with DualRefCounted as a base. + RefCountedPtr Ref() { return InternallyRefCounted::Ref(); } + template + RefCountedPtr RefAsSubclass() { + return InternallyRefCounted::RefAsSubclass(); + } virtual bool IsLame() const = 0; @@ -129,6 +138,10 @@ class Channel : public RefCounted, virtual bool is_client() const { return true; } virtual bool is_promising() const { return true; } + CallArenaAllocator* call_arena_allocator() const { + return call_arena_allocator_.get(); + } + protected: Channel(std::string target, const ChannelArgs& channel_args); @@ -143,6 +156,7 @@ class Channel : public RefCounted, // the C++ or other wrapped language Channel that registered these calls). std::map, RegisteredCall> registration_table_ ABSL_GUARDED_BY(mu_); + const RefCountedPtr call_arena_allocator_; }; } // namespace grpc_core diff --git a/src/core/lib/surface/channel_create.cc b/src/core/lib/surface/channel_create.cc index 5ae280171e7..6a22eeec630 100644 --- a/src/core/lib/surface/channel_create.cc +++ b/src/core/lib/surface/channel_create.cc @@ -22,8 +22,10 @@ #include #include "src/core/channelz/channelz.h" +#include "src/core/client_channel/client_channel.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.h" #include "src/core/lib/surface/lame_client.h" #include "src/core/lib/surface/legacy_channel.h" @@ -77,9 +79,13 @@ absl::StatusOr> ChannelCreate( if (optional_transport != nullptr) { args = args.SetObject(optional_transport); } - // Delegate to legacy channel impl. - return LegacyChannel::Create(std::move(target), std::move(args), - channel_stack_type); + // Delegate to appropriate channel impl. + if (!IsCallV3Enabled()) { + return LegacyChannel::Create(std::move(target), std::move(args), + channel_stack_type); + } + CHECK_EQ(channel_stack_type, GRPC_CLIENT_CHANNEL); + return ClientChannel::Create(std::move(target), std::move(args)); } } // namespace grpc_core diff --git a/src/core/lib/surface/legacy_channel.cc b/src/core/lib/surface/legacy_channel.cc index 69a41cf503e..c35e0158c51 100644 --- a/src/core/lib/surface/legacy_channel.cc +++ b/src/core/lib/surface/legacy_channel.cc @@ -113,10 +113,7 @@ LegacyChannel::LegacyChannel(bool is_client, bool is_promising, : Channel(std::move(target), channel_args), is_client_(is_client), is_promising_(is_promising), - channel_stack_(std::move(channel_stack)), - allocator_(channel_args.GetObject() - ->memory_quota() - ->CreateMemoryOwner()) { + channel_stack_(std::move(channel_stack)) { // We need to make sure that grpc_shutdown() does not shut things down // until after the channel is destroyed. However, the channel may not // actually be destroyed by the time grpc_channel_destroy() returns, diff --git a/src/core/lib/surface/legacy_channel.h b/src/core/lib/surface/legacy_channel.h index 0ebf7b4aacb..b5199e80939 100644 --- a/src/core/lib/surface/legacy_channel.h +++ b/src/core/lib/surface/legacy_channel.h @@ -39,6 +39,7 @@ #include "src/core/lib/surface/channel.h" #include "src/core/lib/surface/channel_stack_type.h" #include "src/core/lib/transport/call_arena_allocator.h" +#include "src/core/lib/transport/transport.h" #include "src/core/telemetry/stats.h" namespace grpc_core { @@ -56,16 +57,6 @@ class LegacyChannel final : public Channel { void Orphan() override; - Arena* CreateArena() override { - const size_t initial_size = call_size_estimator_.CallSizeEstimate(); - global_stats().IncrementCallInitialSize(initial_size); - return Arena::Create(initial_size, &allocator_); - } - void DestroyArena(Arena* arena) override { - call_size_estimator_.UpdateCallSizeEstimate(arena->TotalUsedBytes()); - arena->Destroy(); - } - bool IsLame() const override; grpc_call* CreateCall(grpc_call* parent_call, uint32_t propagation_mask, @@ -114,8 +105,6 @@ class LegacyChannel final : public Channel { const bool is_client_; const bool is_promising_; RefCountedPtr channel_stack_; - CallSizeEstimator call_size_estimator_{1024}; - grpc_event_engine::experimental::MemoryAllocator allocator_; }; } // namespace grpc_core diff --git a/src/core/lib/transport/call_arena_allocator.h b/src/core/lib/transport/call_arena_allocator.h index 1db02bf6902..ebc748854ec 100644 --- a/src/core/lib/transport/call_arena_allocator.h +++ b/src/core/lib/transport/call_arena_allocator.h @@ -28,7 +28,7 @@ namespace grpc_core { -class CallSizeEstimator { +class CallSizeEstimator final { public: explicit CallSizeEstimator(size_t initial_estimate) : call_size_estimate_(initial_estimate) {} @@ -52,19 +52,21 @@ class CallSizeEstimator { std::atomic call_size_estimate_; }; -class CallArenaAllocator : public RefCounted { +class CallArenaAllocator final : public ArenaFactory { public: CallArenaAllocator(MemoryAllocator allocator, size_t initial_size) - : allocator_(std::move(allocator)), call_size_estimator_(initial_size) {} + : ArenaFactory(std::move(allocator)), + call_size_estimator_(initial_size) {} - Arena* MakeArena() { - return Arena::Create(call_size_estimator_.CallSizeEstimate(), &allocator_); + RefCountedPtr MakeArena() override { + return Arena::Create(call_size_estimator_.CallSizeEstimate(), Ref()); } - void Destroy(Arena* arena) { arena->Destroy(); } + void FinalizeArena(Arena* arena) override { + call_size_estimator_.UpdateCallSizeEstimate(arena->TotalUsedBytes()); + } private: - MemoryAllocator allocator_; CallSizeEstimator call_size_estimator_; }; diff --git a/src/core/lib/transport/call_destination.h b/src/core/lib/transport/call_destination.h index 938e0fd3725..04d402569c9 100644 --- a/src/core/lib/transport/call_destination.h +++ b/src/core/lib/transport/call_destination.h @@ -31,6 +31,8 @@ namespace grpc_core { class UnstartedCallDestination : public DualRefCounted { public: + using DualRefCounted::DualRefCounted; + ~UnstartedCallDestination() override = default; // Start a call. The UnstartedCallHandler will be consumed by the Destination // and started. diff --git a/src/core/lib/transport/call_filters.cc b/src/core/lib/transport/call_filters.cc index 2b89babdde4..c4b18721c86 100644 --- a/src/core/lib/transport/call_filters.cc +++ b/src/core/lib/transport/call_filters.cc @@ -170,8 +170,15 @@ Poll InfallibleOperationExecutor::ContinueStep(void* call_data) { template class OperationExecutor; template class OperationExecutor; template class InfallibleOperationExecutor; + } // namespace filters_detail +namespace { +// Call data for those calls that don't have any call data +// (we form pointers to this that aren't allowed to be nullptr) +char g_empty_call_data; +} // namespace + /////////////////////////////////////////////////////////////////////////////// // CallFilters @@ -181,7 +188,7 @@ CallFilters::CallFilters(ClientMetadataHandle client_initial_metadata) client_initial_metadata_(std::move(client_initial_metadata)) {} CallFilters::~CallFilters() { - if (call_data_ != nullptr) { + if (call_data_ != nullptr && call_data_ != &g_empty_call_data) { for (const auto& destructor : stack_->data_.filter_destructor) { destructor.call_destroy(Offset(call_data_, destructor.call_offset)); } @@ -192,8 +199,12 @@ CallFilters::~CallFilters() { void CallFilters::SetStack(RefCountedPtr stack) { CHECK_EQ(call_data_, nullptr); stack_ = std::move(stack); - call_data_ = gpr_malloc_aligned(stack_->data_.call_data_size, - stack_->data_.call_data_alignment); + if (stack_->data_.call_data_size != 0) { + call_data_ = gpr_malloc_aligned(stack_->data_.call_data_size, + stack_->data_.call_data_alignment); + } else { + call_data_ = &g_empty_call_data; + } for (const auto& constructor : stack_->data_.filter_constructor) { constructor.call_init(Offset(call_data_, constructor.call_offset), constructor.channel_data); @@ -232,7 +243,8 @@ void CallFilters::PushServerTrailingMetadata(ServerMetadataHandle md) { md->DebugString().c_str(), DebugString().c_str()); } CHECK(md != nullptr); - if (server_trailing_metadata_ != nullptr) return; + if (cancelled_.is_set()) return; + cancelled_.Set(md->get(GrpcCallWasCancelled()).value_or(false)); server_trailing_metadata_ = std::move(md); client_initial_metadata_state_.CloseWithError(); server_initial_metadata_state_.CloseSending(); diff --git a/src/core/lib/transport/call_filters.h b/src/core/lib/transport/call_filters.h index fd267fd1685..c69ef82c1dc 100644 --- a/src/core/lib/transport/call_filters.h +++ b/src/core/lib/transport/call_filters.h @@ -23,6 +23,7 @@ #include +#include "src/core/lib/gprpp/dump_args.h" #include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/promise/latch.h" @@ -1944,11 +1945,7 @@ inline auto CallFilters::PullServerToClientMessage() { } inline auto CallFilters::PullServerTrailingMetadata() { - return Map(PullServerTrailingMetadataPromise(this), - [this](ServerMetadataHandle h) { - cancelled_.Set(h->get(GrpcCallWasCancelled()).value_or(false)); - return h; - }); + return PullServerTrailingMetadataPromise(this); } inline auto CallFilters::WasCancelled() { return cancelled_.Wait(); } diff --git a/src/core/lib/transport/call_spine.cc b/src/core/lib/transport/call_spine.cc index eb05608663f..99270ae09d1 100644 --- a/src/core/lib/transport/call_spine.cc +++ b/src/core/lib/transport/call_spine.cc @@ -94,12 +94,12 @@ void ForwardCall(CallHandler call_handler, CallInitiator call_initiator) { CallInitiatorAndHandler MakeCallPair( ClientMetadataHandle client_initial_metadata, - grpc_event_engine::experimental::EventEngine* event_engine, Arena* arena, - RefCountedPtr call_arena_allocator_if_arena_is_owned, - grpc_call_context_element* legacy_context) { - auto spine = CallSpine::Create( - std::move(client_initial_metadata), event_engine, arena, - std::move(call_arena_allocator_if_arena_is_owned), legacy_context); + grpc_event_engine::experimental::EventEngine* event_engine, + RefCountedPtr arena, grpc_call_context_element* legacy_context) { + CHECK_NE(arena.get(), nullptr); + auto spine = + CallSpine::Create(std::move(client_initial_metadata), event_engine, + std::move(arena), legacy_context); return {CallInitiator(spine), UnstartedCallHandler(spine)}; } diff --git a/src/core/lib/transport/call_spine.h b/src/core/lib/transport/call_spine.h index 59c1fc2da16..1dbc939d915 100644 --- a/src/core/lib/transport/call_spine.h +++ b/src/core/lib/transport/call_spine.h @@ -21,13 +21,16 @@ #include #include "src/core/lib/channel/context.h" +#include "src/core/lib/gprpp/dual_ref_counted.h" #include "src/core/lib/promise/detail/status.h" #include "src/core/lib/promise/if.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/prioritized_race.h" #include "src/core/lib/promise/promise.h" #include "src/core/lib/promise/status_flag.h" +#include "src/core/lib/promise/try_seq.h" #include "src/core/lib/transport/call_arena_allocator.h" #include "src/core/lib/transport/call_filters.h" #include "src/core/lib/transport/message.h" @@ -135,6 +138,23 @@ class CallSpineInterface { }); } + // Wrap a promise so that if the call completes that promise is cancelled. + template + auto UntilCallCompletes(Promise promise) { + using Result = PromiseResult; + return PrioritizedRace(std::move(promise), Map(WasCancelled(), [](bool) { + return FailureStatusCast(Failure{}); + })); + } + + template + void SpawnGuardedUntilCallCompletes(absl::string_view name, + PromiseFactory promise_factory) { + SpawnGuarded(name, [this, promise_factory]() mutable { + return UntilCallCompletes(promise_factory()); + }); + } + private: absl::AnyInvocable on_done_{nullptr}; }; @@ -260,19 +280,19 @@ class CallSpine final : public CallSpineInterface, public Party { public: static RefCountedPtr Create( ClientMetadataHandle client_initial_metadata, - grpc_event_engine::experimental::EventEngine* event_engine, Arena* arena, - RefCountedPtr call_arena_allocator_if_arena_is_owned, - grpc_call_context_element* legacy_context) { - return RefCountedPtr(arena->New( - std::move(client_initial_metadata), event_engine, arena, - std::move(call_arena_allocator_if_arena_is_owned), legacy_context)); + grpc_event_engine::experimental::EventEngine* event_engine, + RefCountedPtr arena, grpc_call_context_element* legacy_context) { + auto* arena_ptr = arena.get(); + return RefCountedPtr(arena_ptr->New( + std::move(client_initial_metadata), event_engine, std::move(arena), + legacy_context)); } ~CallSpine() override { if (legacy_context_is_owned_) { for (size_t i = 0; i < GRPC_CONTEXT_COUNT; i++) { grpc_call_context_element& elem = legacy_context_[i]; - if (elem.destroy != nullptr) elem.destroy(&elem); + if (elem.destroy != nullptr) elem.destroy(elem.value); } } } @@ -281,7 +301,7 @@ class CallSpine final : public CallSpineInterface, public Party { Party& party() override { return *this; } - Arena* arena() override { return arena_; } + Arena* arena() override { return arena_.get(); } void IncrementRefCount() override { Party::IncrementRefCount(); } @@ -365,18 +385,15 @@ class CallSpine final : public CallSpineInterface, public Party { friend class Arena; CallSpine(ClientMetadataHandle client_initial_metadata, grpc_event_engine::experimental::EventEngine* event_engine, - Arena* arena, - RefCountedPtr call_arena_allocator, + RefCountedPtr arena, grpc_call_context_element* legacy_context) : Party(1), + arena_(std::move(arena)), call_filters_(std::move(client_initial_metadata)), - arena_(arena), - event_engine_(event_engine), - call_arena_allocator_if_arena_is_owned_( - std::move(call_arena_allocator)) { + event_engine_(event_engine) { if (legacy_context == nullptr) { - legacy_context_ = static_cast( - arena->Alloc(sizeof(grpc_call_context_element) * GRPC_CONTEXT_COUNT)); + legacy_context_ = static_cast(arena_->Alloc( + sizeof(grpc_call_context_element) * GRPC_CONTEXT_COUNT)); memset(legacy_context_, 0, sizeof(grpc_call_context_element) * GRPC_CONTEXT_COUNT); legacy_context_is_owned_ = true; @@ -395,7 +412,7 @@ class CallSpine final : public CallSpineInterface, public Party { public: explicit ScopedContext(CallSpine* spine) : ScopedActivity(spine), - Context(spine->arena_), + Context(spine->arena_.get()), Context( spine->event_engine()), Context(spine->legacy_context_) {} @@ -407,29 +424,23 @@ class CallSpine final : public CallSpineInterface, public Party { } void PartyOver() override { - Arena* a = arena_; - RefCountedPtr call_arena_allocator_if_arena_is_owned = - std::move(call_arena_allocator_if_arena_is_owned_); + auto arena = arena_; { ScopedContext context(this); CancelRemainingParticipants(); - a->DestroyManagedNewObjects(); + arena->DestroyManagedNewObjects(); } this->~CallSpine(); - if (call_arena_allocator_if_arena_is_owned != nullptr) { - call_arena_allocator_if_arena_is_owned->Destroy(a); - } } + const RefCountedPtr arena_; // Call filters/pipes part of the spine CallFilters call_filters_; - Arena* const arena_; // Event engine associated with this call grpc_event_engine::experimental::EventEngine* const event_engine_; // Legacy context // TODO(ctiller): remove grpc_call_context_element* legacy_context_; - RefCountedPtr call_arena_allocator_if_arena_is_owned_; bool legacy_context_is_owned_; }; @@ -472,6 +483,12 @@ class CallInitiator { spine_->SpawnGuarded(name, std::move(promise_factory)); } + template + void SpawnGuardedUntilCallCompletes(absl::string_view name, + PromiseFactory promise_factory) { + spine_->SpawnGuardedUntilCallCompletes(name, std::move(promise_factory)); + } + template void SpawnInfallible(absl::string_view name, PromiseFactory promise_factory) { spine_->SpawnInfallible(name, std::move(promise_factory)); @@ -526,6 +543,12 @@ class CallHandler { spine_->SpawnGuarded(name, std::move(promise_factory), whence); } + template + void SpawnGuardedUntilCallCompletes(absl::string_view name, + PromiseFactory promise_factory) { + spine_->SpawnGuardedUntilCallCompletes(name, std::move(promise_factory)); + } + template void SpawnInfallible(absl::string_view name, PromiseFactory promise_factory) { spine_->SpawnInfallible(name, std::move(promise_factory)); @@ -577,6 +600,12 @@ class UnstartedCallHandler { spine_->SpawnGuarded(name, std::move(promise_factory), whence); } + template + void SpawnGuardedUntilCallCompletes(absl::string_view name, + PromiseFactory promise_factory) { + spine_->SpawnGuardedUntilCallCompletes(name, std::move(promise_factory)); + } + template void SpawnInfallible(absl::string_view name, PromiseFactory promise_factory) { spine_->SpawnInfallible(name, std::move(promise_factory)); @@ -616,9 +645,8 @@ struct CallInitiatorAndHandler { CallInitiatorAndHandler MakeCallPair( ClientMetadataHandle client_initial_metadata, - grpc_event_engine::experimental::EventEngine* event_engine, Arena* arena, - RefCountedPtr call_arena_allocator_if_arena_is_owned, - grpc_call_context_element* legacy_context); + grpc_event_engine::experimental::EventEngine* event_engine, + RefCountedPtr arena, grpc_call_context_element* legacy_context); template auto OutgoingMessages(CallHalf h) { diff --git a/src/core/lib/transport/interception_chain.cc b/src/core/lib/transport/interception_chain.cc index 4d6ad34e315..667077af586 100644 --- a/src/core/lib/transport/interception_chain.cc +++ b/src/core/lib/transport/interception_chain.cc @@ -40,7 +40,7 @@ CallInitiator HijackedCall::MakeCall() { CallInitiator HijackedCall::MakeCallWithMetadata( ClientMetadataHandle metadata) { auto call = MakeCallPair(std::move(metadata), call_handler_.event_engine(), - call_handler_.arena(), nullptr, + call_handler_.arena()->Ref(), call_handler_.legacy_context()); destination_->StartCall(std::move(call.handler)); return std::move(call.initiator); diff --git a/src/core/lib/transport/metadata_batch.h b/src/core/lib/transport/metadata_batch.h index c8611a225fa..a5a934803ee 100644 --- a/src/core/lib/transport/metadata_batch.h +++ b/src/core/lib/transport/metadata_batch.h @@ -528,6 +528,14 @@ struct WaitForReady { static std::string DisplayValue(ValueType x); }; +// Annotation added by retry code to indicate a transparent retry. +struct IsTransparentRetry { + static absl::string_view DebugKey() { return "IsTransparentRetry"; } + static constexpr bool kRepeatable = false; + using ValueType = bool; + static std::string DisplayValue(ValueType x) { return x ? "true" : "false"; } +}; + // Annotation added by a transport to note that server trailing metadata // is a Trailers-Only response. struct GrpcTrailersOnly { @@ -1536,7 +1544,8 @@ using grpc_metadata_batch_base = grpc_core::MetadataMap< grpc_core::GrpcStreamNetworkState, grpc_core::PeerString, grpc_core::GrpcStatusContext, grpc_core::GrpcStatusFromWire, grpc_core::GrpcCallWasCancelled, grpc_core::WaitForReady, - grpc_core::GrpcTrailersOnly, grpc_core::GrpcTarPit, + grpc_core::IsTransparentRetry, grpc_core::GrpcTrailersOnly, + grpc_core::GrpcTarPit, grpc_core::GrpcRegisteredMethod GRPC_CUSTOM_CLIENT_METADATA GRPC_CUSTOM_SERVER_METADATA>; diff --git a/src/core/load_balancing/lb_policy.h b/src/core/load_balancing/lb_policy.h index 838d89ae2d5..1ac1deb2055 100644 --- a/src/core/load_balancing/lb_policy.h +++ b/src/core/load_balancing/lb_policy.h @@ -484,6 +484,11 @@ class LoadBalancingPolicy : public InternallyRefCounted { ChannelArgs channel_args_; }; +template <> +struct ArenaContextType { + static void Destroy(LoadBalancingPolicy::SubchannelCallTrackerInterface*) {} +}; + } // namespace grpc_core #endif // GRPC_SRC_CORE_LOAD_BALANCING_LB_POLICY_H diff --git a/src/core/telemetry/call_tracer.h b/src/core/telemetry/call_tracer.h index 3f98c7098e0..967658fa36b 100644 --- a/src/core/telemetry/call_tracer.h +++ b/src/core/telemetry/call_tracer.h @@ -33,6 +33,7 @@ #include "src/core/lib/channel/context.h" #include "src/core/lib/gprpp/ref_counted_string.h" #include "src/core/lib/iomgr/error.h" +#include "src/core/lib/promise/context.h" #include "src/core/lib/resource_quota/arena.h" #include "src/core/lib/slice/slice_buffer.h" #include "src/core/lib/transport/call_final_info.h" @@ -221,6 +222,21 @@ void AddClientCallTracerToContext(grpc_call_context_element* call_context, void AddServerCallTracerToContext(grpc_call_context_element* call_context, ServerCallTracer* tracer); +template <> +struct ContextSubclass { + using Base = CallTracerInterface; +}; + +template <> +struct ContextSubclass { + using Base = CallTracerInterface; +}; + +template <> +struct ContextSubclass { + using Base = CallTracerAnnotationInterface; +}; + } // namespace grpc_core #endif // GRPC_SRC_CORE_TELEMETRY_CALL_TRACER_H diff --git a/src/core/telemetry/metrics.h b/src/core/telemetry/metrics.h index 0a02cf9acfc..2fb92d4597e 100644 --- a/src/core/telemetry/metrics.h +++ b/src/core/telemetry/metrics.h @@ -329,6 +329,9 @@ class StatsPlugin { // Removes a callback previously added via AddCallback(). The stats // plugin may not use the callback after this method returns. virtual void RemoveCallback(RegisteredMetricCallback* callback) = 0; + // Returns true if instrument \a handle is enabled. + virtual bool IsInstrumentEnabled( + GlobalInstrumentsRegistry::GlobalInstrumentHandle handle) = 0; // Gets a ClientCallTracer associated with this stats plugin which can be used // in a call. @@ -424,6 +427,17 @@ class GlobalStatsPluginRegistry { optional_values); } } + // Returns true if any of the stats plugins in the group have enabled \a + // handle. + bool IsInstrumentEnabled( + GlobalInstrumentsRegistry::GlobalInstrumentHandle handle) { + for (auto& state : plugins_state_) { + if (state.plugin->IsInstrumentEnabled(handle)) { + return true; + } + } + return false; + } // Registers a callback to be used to populate callback metrics. // The callback will update the specified metrics. The callback diff --git a/src/core/lib/http/format_request.cc b/src/core/util/http_client/format_request.cc similarity index 97% rename from src/core/lib/http/format_request.cc rename to src/core/util/http_client/format_request.cc index d358a57f5bc..1d785835e2b 100644 --- a/src/core/lib/http/format_request.cc +++ b/src/core/util/http_client/format_request.cc @@ -16,7 +16,9 @@ // // -#include "src/core/lib/http/format_request.h" +#include + +#include "src/core/util/http_client/format_request.h" #include #include @@ -31,9 +33,8 @@ #include "absl/strings/string_view.h" #include -#include -#include "src/core/lib/http/httpcli.h" +#include "src/core/util/http_client/httpcli.h" static void fill_common_header(const grpc_http_request* request, const char* host, const char* path, diff --git a/src/core/lib/http/format_request.h b/src/core/util/http_client/format_request.h similarity index 86% rename from src/core/lib/http/format_request.h rename to src/core/util/http_client/format_request.h index a9e76643556..ab9d6a9d7d5 100644 --- a/src/core/lib/http/format_request.h +++ b/src/core/util/http_client/format_request.h @@ -16,13 +16,14 @@ // // -#ifndef GRPC_SRC_CORE_LIB_HTTP_FORMAT_REQUEST_H -#define GRPC_SRC_CORE_LIB_HTTP_FORMAT_REQUEST_H +#ifndef GRPC_SRC_CORE_UTIL_HTTP_CLIENT_FORMAT_REQUEST_H +#define GRPC_SRC_CORE_UTIL_HTTP_CLIENT_FORMAT_REQUEST_H -#include #include -#include "src/core/lib/http/parser.h" +#include + +#include "src/core/util/http_client/parser.h" grpc_slice grpc_httpcli_format_get_request(const grpc_http_request* request, const char* host, const char* path); @@ -34,4 +35,4 @@ grpc_slice grpc_httpcli_format_connect_request(const grpc_http_request* request, const char* host, const char* path); -#endif // GRPC_SRC_CORE_LIB_HTTP_FORMAT_REQUEST_H +#endif // GRPC_SRC_CORE_UTIL_HTTP_CLIENT_FORMAT_REQUEST_H diff --git a/src/core/lib/http/httpcli.cc b/src/core/util/http_client/httpcli.cc similarity index 99% rename from src/core/lib/http/httpcli.cc rename to src/core/util/http_client/httpcli.cc index ee2a5ad528d..2771787dd00 100644 --- a/src/core/lib/http/httpcli.cc +++ b/src/core/util/http_client/httpcli.cc @@ -16,7 +16,9 @@ // // -#include "src/core/lib/http/httpcli.h" +#include + +#include "src/core/util/http_client/httpcli.h" #include @@ -32,7 +34,6 @@ #include #include #include -#include #include "src/core/handshaker/handshaker_registry.h" #include "src/core/handshaker/tcp_connect/tcp_connect_handshaker.h" @@ -41,8 +42,6 @@ #include "src/core/lib/channel/channel_args_preconditioning.h" #include "src/core/lib/config/core_configuration.h" #include "src/core/lib/gprpp/status_helper.h" -#include "src/core/lib/http/format_request.h" -#include "src/core/lib/http/parser.h" #include "src/core/lib/iomgr/endpoint.h" #include "src/core/lib/iomgr/iomgr_internal.h" #include "src/core/lib/iomgr/pollset_set.h" @@ -52,6 +51,8 @@ #include "src/core/lib/security/security_connector/security_connector.h" #include "src/core/lib/slice/slice.h" #include "src/core/lib/transport/error_utils.h" +#include "src/core/util/http_client/format_request.h" +#include "src/core/util/http_client/parser.h" namespace grpc_core { diff --git a/src/core/lib/http/httpcli.h b/src/core/util/http_client/httpcli.h similarity index 98% rename from src/core/lib/http/httpcli.h rename to src/core/util/http_client/httpcli.h index 960b46d16c3..2ad2810f027 100644 --- a/src/core/lib/http/httpcli.h +++ b/src/core/util/http_client/httpcli.h @@ -16,8 +16,10 @@ // // -#ifndef GRPC_SRC_CORE_LIB_HTTP_HTTPCLI_H -#define GRPC_SRC_CORE_LIB_HTTP_HTTPCLI_H +#ifndef GRPC_SRC_CORE_UTIL_HTTP_CLIENT_HTTPCLI_H +#define GRPC_SRC_CORE_UTIL_HTTP_CLIENT_HTTPCLI_H + +#include #include @@ -32,7 +34,6 @@ #include #include -#include #include "src/core/handshaker/handshaker.h" #include "src/core/lib/gprpp/debug_location.h" @@ -40,7 +41,6 @@ #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/gprpp/sync.h" #include "src/core/lib/gprpp/time.h" -#include "src/core/lib/http/parser.h" #include "src/core/lib/iomgr/closure.h" #include "src/core/lib/iomgr/endpoint.h" #include "src/core/lib/iomgr/error.h" @@ -52,6 +52,7 @@ #include "src/core/lib/iomgr/resolved_address.h" #include "src/core/lib/resource_quota/resource_quota.h" #include "src/core/lib/uri/uri_parser.h" +#include "src/core/util/http_client/parser.h" // User agent this library reports #define GRPC_HTTPCLI_USER_AGENT "grpc-httpcli/0.0" @@ -264,4 +265,4 @@ class HttpRequest : public InternallyRefCounted { } // namespace grpc_core -#endif // GRPC_SRC_CORE_LIB_HTTP_HTTPCLI_H +#endif // GRPC_SRC_CORE_UTIL_HTTP_CLIENT_HTTPCLI_H diff --git a/src/core/lib/http/httpcli_security_connector.cc b/src/core/util/http_client/httpcli_security_connector.cc similarity index 99% rename from src/core/lib/http/httpcli_security_connector.cc rename to src/core/util/http_client/httpcli_security_connector.cc index 7db2021b71c..ac0c1adb257 100644 --- a/src/core/lib/http/httpcli_security_connector.cc +++ b/src/core/util/http_client/httpcli_security_connector.cc @@ -16,6 +16,8 @@ // // +#include + #include #include @@ -32,7 +34,6 @@ #include #include #include -#include #include #include "src/core/handshaker/handshaker.h" diff --git a/src/core/lib/http/httpcli_ssl_credentials.h b/src/core/util/http_client/httpcli_ssl_credentials.h similarity index 85% rename from src/core/lib/http/httpcli_ssl_credentials.h rename to src/core/util/http_client/httpcli_ssl_credentials.h index dc6182a0779..45364c64a46 100644 --- a/src/core/lib/http/httpcli_ssl_credentials.h +++ b/src/core/util/http_client/httpcli_ssl_credentials.h @@ -14,12 +14,13 @@ // limitations under the License. // -#ifndef GRPC_SRC_CORE_LIB_HTTP_HTTPCLI_SSL_CREDENTIALS_H -#define GRPC_SRC_CORE_LIB_HTTP_HTTPCLI_SSL_CREDENTIALS_H +#ifndef GRPC_SRC_CORE_UTIL_HTTP_CLIENT_HTTPCLI_SSL_CREDENTIALS_H +#define GRPC_SRC_CORE_UTIL_HTTP_CLIENT_HTTPCLI_SSL_CREDENTIALS_H -#include #include +#include + #include "src/core/lib/gprpp/ref_counted_ptr.h" namespace grpc_core { @@ -35,4 +36,4 @@ RefCountedPtr CreateHttpRequestSSLCredentials(); } // namespace grpc_core -#endif // GRPC_SRC_CORE_LIB_HTTP_HTTPCLI_SSL_CREDENTIALS_H +#endif // GRPC_SRC_CORE_UTIL_HTTP_CLIENT_HTTPCLI_SSL_CREDENTIALS_H diff --git a/src/core/lib/http/parser.cc b/src/core/util/http_client/parser.cc similarity index 99% rename from src/core/lib/http/parser.cc rename to src/core/util/http_client/parser.cc index aad7963f1d7..c344f438cf3 100644 --- a/src/core/lib/http/parser.cc +++ b/src/core/util/http_client/parser.cc @@ -16,7 +16,9 @@ // // -#include "src/core/lib/http/parser.h" +#include + +#include "src/core/util/http_client/parser.h" #include @@ -27,7 +29,6 @@ #include #include -#include grpc_core::TraceFlag grpc_http1_trace(false, "http1"); diff --git a/src/core/lib/http/parser.h b/src/core/util/http_client/parser.h similarity index 96% rename from src/core/lib/http/parser.h rename to src/core/util/http_client/parser.h index e9a1088b85f..cfd1ed7ab3a 100644 --- a/src/core/lib/http/parser.h +++ b/src/core/util/http_client/parser.h @@ -16,14 +16,15 @@ // // -#ifndef GRPC_SRC_CORE_LIB_HTTP_PARSER_H -#define GRPC_SRC_CORE_LIB_HTTP_PARSER_H +#ifndef GRPC_SRC_CORE_UTIL_HTTP_CLIENT_PARSER_H +#define GRPC_SRC_CORE_UTIL_HTTP_CLIENT_PARSER_H + +#include #include #include #include -#include #include "src/core/lib/debug/trace.h" #include "src/core/lib/iomgr/error.h" @@ -126,4 +127,4 @@ void grpc_http_response_destroy(grpc_http_response* response); extern grpc_core::TraceFlag grpc_http1_trace; -#endif // GRPC_SRC_CORE_LIB_HTTP_PARSER_H +#endif // GRPC_SRC_CORE_UTIL_HTTP_CLIENT_PARSER_H diff --git a/src/cpp/ext/otel/otel_plugin.cc b/src/cpp/ext/otel/otel_plugin.cc index 588404f75df..18cee7af41f 100644 --- a/src/cpp/ext/otel/otel_plugin.cc +++ b/src/cpp/ext/otel/otel_plugin.cc @@ -913,6 +913,12 @@ grpc_core::ServerCallTracer* OpenTelemetryPlugin::GetServerCallTracer( scope_config)); } +bool OpenTelemetryPlugin::IsInstrumentEnabled( + grpc_core::GlobalInstrumentsRegistry::GlobalInstrumentHandle handle) { + return !absl::holds_alternative( + instruments_data_.at(handle.index).instrument); +} + } // namespace internal constexpr absl::string_view diff --git a/src/cpp/ext/otel/otel_plugin.h b/src/cpp/ext/otel/otel_plugin.h index 5bce0cc39ac..9928390222a 100644 --- a/src/cpp/ext/otel/otel_plugin.h +++ b/src/cpp/ext/otel/otel_plugin.h @@ -404,6 +404,9 @@ class OpenTelemetryPlugin : public grpc_core::StatsPlugin { grpc_core::ServerCallTracer* GetServerCallTracer( std::shared_ptr scope_config) override; + bool IsInstrumentEnabled( + grpc_core::GlobalInstrumentsRegistry::GlobalInstrumentHandle handle) + override; const absl::AnyInvocable& server_selector() const { diff --git a/src/objective-c/BoringSSL-GRPC.podspec b/src/objective-c/BoringSSL-GRPC.podspec index 34bb565a76f..50267fefd64 100644 --- a/src/objective-c/BoringSSL-GRPC.podspec +++ b/src/objective-c/BoringSSL-GRPC.podspec @@ -39,7 +39,7 @@ Pod::Spec.new do |s| s.name = 'BoringSSL-GRPC' - version = '0.0.34' + version = '0.0.35' s.version = version s.summary = 'BoringSSL is a fork of OpenSSL that is designed to meet Google\'s needs.' # Adapted from the homepage: @@ -76,7 +76,7 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/google/boringssl.git', - :commit => "5a2bca2124800f2861263959b72bc35cdf18949b", + :commit => "b8a2bffc598f230484ff48a247526a9820facfc2", } s.ios.deployment_target = '10.0' @@ -177,520 +177,521 @@ Pod::Spec.new do |s| *) opts="--ignore-garbage" ;; esac base64 --decode $opts < src/include/openssl/boringssl_prefix_symbols.h - H4sICAAAAAAC/2JvcmluZ3NzbF9wcmVmaXhfc3ltYm9scy5oALS9XXPbuJaofT+/wnXm5kzVrpnY6WSn - 3zvFVjqaOLZHUvp0zg2LkiCLOxSpEJRj968/AEmJ+FgL5FrwW7VrpmPpeRYFgPgiCPzXf108ikJUaS02 - F6uX8z+SVVllxaOUeXKoxDZ7TnYi3YjqP+XuoiwuPjafLha3F+tyv8/q/+/iXXq1WqdXl1e/fXjzZnv1 - 4f3l1fu3v7/7ffVP9fe379ab7eWH33/7ffVv//Zf/3VxXR5equxxV1/87/V/XFy9ufzwj4s/yvIxFxez - Yv2f6iv6Ww+i2mdSZipeXV4cpfiHinZ4+cfFvtxkW/X/02LzX2V1sclkXWWrYy0u6l0mL2S5rX+llbjY - qg/T4kW7DsfqUEpx8Sur1Q+omv9fHuuLrRAXCtmJSuhfX6WFSoh/XByq8inbqCSpd2mt/o+4SFflk9Cm - 9fnai7LO1kJfRRv30F/v6aPDQaTVRVZcpHmuyUzI069bfp5eLO4/Lf/PZD69mC0uHub3f85upjcX/2uy - UP/+XxeTu5vmS5Nvy8/384ub2eL6djL7uriY3N5eKGo+uVvOpgvt+j+z5eeL+fSPyVwh94pSvt59d337 - 7WZ290cDzr4+3M5UlF5wcf9JO75O59ef1V8mH2e3s+X3Jvyn2fJuulj8p3Jc3N1fTP+c3i0vFp+1x7iy - j9OL29nk4+304pP61+Tuu9YtHqbXs8ntP9R1z6fXy38oxem/1Jeu7+8W0//5pnTqOxc3k6+TP/SFNPTp - n80P+zxZLu5V3Ln6eYtvt0v9Mz7N779e3N4v9JVffFtMVYzJcqJplYbqkhf/UNxUXeBcX/dE/e96Obu/ - 0z4FqNDL+URfx930j9vZH9O766lm7xtgeT9X3/226Jh/XEzms4UOev9tqel77WyK8P3d3bT5Tpv6Oj3U - tTRXMZ2rhPg6acSf7Nz4z6b8f7yfK6e6fZLJzU3yMJ9+mv11cUhlLeRF/au8UEWvqLNtJiqpCo8q/GUh - VCbUuoipQr2X+g9alNX6btUlrtxe7NN1VV6I50NaNIVQ/S+r5UVaPR73yicvVkLBogmk7t7//Ld/36g7 - uxDg5fzv9B8Xq/8AP0pm6qfP2y8EHeYXL9KLf//3i0T/H1UHnKnZfbJNVC0DX0P/x/YP/+iB/7AcUtRU - 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 - CcLf//Z/2aoCAcHMBAA= + H4sICAAAAAAC/2JvcmluZ3NzbF9wcmVmaXhfc3ltYm9scy5oALS9XXPbuJaofT+/wnXm5kzVrpnY6WRn + v3eKrXQ0cWxvSenpzA2LkiCLOxSpEJRj968/AEmJ+FgL5FrwW7VrpmPpeRYFgPgiCPzXf108ikJUaS02 + F6uX8z+SVVllxaOUeXKoxDZ7TnYi3YjqP+XuoiwuPjafLha3F+tyv8/q/+9i9SG9Wm2363f/+LC9evvm + tw+/bbe/qb/99vd3V+/Tf3y4erNN19v11b/923/918V1eXipssddffF/1/9xcfXm8sPfLn4vy8dcXMyK + 9X+qr+hvPYhqn0mZqXh1eXGU4m8q2uHlbxf7cpNt1f9Pi81/ldXFJpN1la2Otbiod5m8kOW2/pVW4mKr + PkyLF+06HKtDKcXFr6xWP6Bq/n95rC+2QlwoZCcqoX99lRYqIf52cajKp2yjkqTepbX6P+IiXZVPQpvW + 52svyjpbC30VbdxDf72njw4HkVYXWXGR5rkmMyFPv275eXqxuP+0/J/JfHoxW1w8zO//mN1Mby7+z2Sh + /v1/LiZ3N82XJt+Wn+/nFzezxfXtZPZ1cTG5vb1Q1Hxyt5xNF9r1P7Pl54v59PfJXCH3ilK+3n13ffvt + Znb3ewPOvj7czlSUXnBx/0k7vk7n15/VXyYfZ7ez5fcm/KfZ8m66WPynclzc3V9M/5jeLS8Wn7XHuLKP + 04vb2eTj7fTik/rX5O671i0eptezye3f1HXPp9fLvynF6b/Ul67v7xbTf35TOvWdi5vJ18nv+kIa+vTP + 5od9niwX9yruXP28xbfbpf4Zn+b3Xy9u7xf6yi++LaYqxmQ50bRKQ3XJi78pbqoucK6ve6L+d72c3d9p + nwJU6OV8oq/jbvr77ez36d31VLP3DbC8n6vvflt0zN8uJvPZQge9/7bU9L12NkX4/u5u2nynTX2dHupa + mquYzlVCfJ004k92bvxnU/4/3s+VU90+yeTmJnmYTz/N/rw4pLIW8qL+VV6oolfU2TYTlVSFRxX+shAq + E2pdxFSh3kv9By3Kan236hJXbi/26boqL8TzIS2aQqj+l9XyIq0ej3vlkxcroWDRBFJ373/+279v1J1d + CPBy/m/6t4vVf4AfJTP10+ftF4IO84sX6cW///tFov/P6t96anafbBNVy8DX0P+x/cPfeuA/LIcUNdXS + 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 EOF # PrivacyInfo.xcprivacy is not part of BoringSSL repo, inject it during pod installation diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/observability.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/observability.pyx.pxi index aa7dce5e8ac..a29ccdd9376 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/observability.pyx.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/observability.pyx.pxi @@ -23,11 +23,13 @@ cdef const char* CLIENT_CALL_TRACER = "client_call_tracer" cdef const char* SERVER_CALL_TRACER_FACTORY = "server_call_tracer_factory" -def set_server_call_tracer_factory(object observability_plugin) -> None: - capsule = observability_plugin.create_server_call_tracer_factory() - capsule_ptr = cpython.PyCapsule_GetPointer(capsule, SERVER_CALL_TRACER_FACTORY) - _register_server_call_tracer_factory(capsule_ptr) - +def get_server_call_tracer_factory_address(object observability_plugin, bint xds) -> Optional[int]: + capsule = observability_plugin.create_server_call_tracer_factory(xds=xds) + if capsule: + capsule_ptr = cpython.PyCapsule_GetPointer(capsule, SERVER_CALL_TRACER_FACTORY) + return int(capsule_ptr) + else: + return None def clear_server_call_tracer_factory() -> None: _register_server_call_tracer_factory(NULL) diff --git a/src/python/grpcio/grpc/_observability.py b/src/python/grpcio/grpc/_observability.py index e18dbc1dd0f..3caf6b5265c 100644 --- a/src/python/grpcio/grpc/_observability.py +++ b/src/python/grpcio/grpc/_observability.py @@ -21,6 +21,7 @@ import threading from typing import Any, Generator, Generic, List, Optional, TypeVar from grpc._cython import cygrpc as _cygrpc +from grpc._typing import ChannelArgumentType _LOGGER = logging.getLogger(__name__) @@ -36,6 +37,20 @@ _SERVICES_TO_EXCLUDE: List[bytes] = [ ] +class ServerCallTracerFactory: + """An encapsulation of a ServerCallTracerFactory. + + Instances of this class can be passed to a Channel as values for the + grpc.experimental.server_call_tracer_factory option + """ + + def __init__(self, address): + self._address = address + + def __int__(self): + return self._address + + class ObservabilityPlugin( Generic[ClientCallTracerCapsule, ServerCallTracerFactoryCapsule], metaclass=abc.ABCMeta, @@ -126,19 +141,23 @@ class ObservabilityPlugin( @abc.abstractmethod def create_server_call_tracer_factory( self, - ) -> ServerCallTracerFactoryCapsule: + *, + xds: bool = False, + ) -> Optional[ServerCallTracerFactoryCapsule]: """Creates a ServerCallTracerFactoryCapsule. - After register the plugin, if tracing or stats is enabled, this method - will be called by calling observability_init, the ServerCallTracerFactory - created by this method will be registered to gRPC core. + This method will be called at server initialization time to create a + ServerCallTracerFactory, which will be registered to gRPC core. The ServerCallTracerFactory is an object which implements `grpc_core::ServerCallTracerFactory` interface and wrapped in a PyCapsule using `server_call_tracer_factory` as name. + Args: + xds: Whether the server is xds server. Returns: - A PyCapsule which stores a ServerCallTracerFactory object. + A PyCapsule which stores a ServerCallTracerFactory object. Or None if + plugin decides not to create ServerCallTracerFactory. """ raise NotImplementedError() @@ -221,7 +240,7 @@ def set_plugin(observability_plugin: Optional[ObservabilityPlugin]) -> None: Raises: ValueError: If an ObservabilityPlugin was already registered at the - time of calling this method. + time of calling this method. """ global _OBSERVABILITY_PLUGIN # pylint: disable=global-statement with _plugin_lock: @@ -241,13 +260,9 @@ def observability_init(observability_plugin: ObservabilityPlugin) -> None: Raises: ValueError: If an ObservabilityPlugin was already registered at the - time of calling this method. + time of calling this method. """ set_plugin(observability_plugin) - try: - _cygrpc.set_server_call_tracer_factory(observability_plugin) - except Exception: # pylint:disable=broad-except - _LOGGER.exception("Failed to set server call tracer factory!") def observability_deinit() -> None: @@ -284,17 +299,34 @@ def maybe_record_rpc_latency(state: "_channel._RPCState") -> None: Args: state: a grpc._channel._RPCState object which contains the stats related to the - RPC. + RPC. """ # TODO(xuanwn): use channel args to exclude those metrics. for exclude_prefix in _SERVICES_TO_EXCLUDE: if exclude_prefix in state.method.encode("utf8"): return with get_plugin() as plugin: - if not (plugin and plugin.stats_enabled): - return - rpc_latency_s = state.rpc_end_time - state.rpc_start_time - rpc_latency_ms = rpc_latency_s * 1000 - plugin.record_rpc_latency( - state.method, state.target, rpc_latency_ms, state.code - ) + if plugin and plugin.stats_enabled: + rpc_latency_s = state.rpc_end_time - state.rpc_start_time + rpc_latency_ms = rpc_latency_s * 1000 + plugin.record_rpc_latency( + state.method, state.target, rpc_latency_ms, state.code + ) + + +def create_server_call_tracer_factory_option(xds: bool) -> ChannelArgumentType: + with get_plugin() as plugin: + if plugin and plugin.stats_enabled: + server_call_tracer_factory_address = ( + _cygrpc.get_server_call_tracer_factory_address(plugin, xds) + ) + if server_call_tracer_factory_address: + return ( + ( + "grpc.experimental.server_call_tracer_factory", + ServerCallTracerFactory( + server_call_tracer_factory_address + ), + ), + ) + return () diff --git a/src/python/grpcio/grpc/_server.py b/src/python/grpcio/grpc/_server.py index ade13718091..c8af57c0806 100644 --- a/src/python/grpcio/grpc/_server.py +++ b/src/python/grpcio/grpc/_server.py @@ -43,6 +43,7 @@ import grpc # pytype: disable=pyi-error from grpc import _common # pytype: disable=pyi-error from grpc import _compression # pytype: disable=pyi-error from grpc import _interceptor # pytype: disable=pyi-error +from grpc import _observability # pytype: disable=pyi-error from grpc._cython import cygrpc from grpc._typing import ArityAgnosticMethodHandler from grpc._typing import ChannelArgumentType @@ -1403,9 +1404,17 @@ def _validate_generic_rpc_handlers( def _augment_options( base_options: Sequence[ChannelArgumentType], compression: Optional[grpc.Compression], + xds: bool, ) -> Sequence[ChannelArgumentType]: compression_option = _compression.create_channel_option(compression) - return tuple(base_options) + compression_option + maybe_server_call_tracer_factory_option = ( + _observability.create_server_call_tracer_factory_option(xds) + ) + return ( + tuple(base_options) + + compression_option + + maybe_server_call_tracer_factory_option + ) class _Server(grpc.Server): @@ -1423,7 +1432,7 @@ class _Server(grpc.Server): xds: bool, ): completion_queue = cygrpc.CompletionQueue() - server = cygrpc.Server(_augment_options(options, compression), xds) + server = cygrpc.Server(_augment_options(options, compression, xds), xds) server.register_completion_queue(completion_queue) self._state = _ServerState( completion_queue, diff --git a/src/python/grpcio/grpc/aio/_call.py b/src/python/grpcio/grpc/aio/_call.py index 82b0d3ce522..24f2090651a 100644 --- a/src/python/grpcio/grpc/aio/_call.py +++ b/src/python/grpcio/grpc/aio/_call.py @@ -19,7 +19,15 @@ from functools import partial import inspect import logging import traceback -from typing import Any, AsyncIterator, Generator, Generic, Optional, Tuple +from typing import ( + Any, + AsyncIterator, + Generator, + Generic, + Optional, + Tuple, + Union, +) import grpc from grpc import _common @@ -29,6 +37,7 @@ from . import _base_call from ._metadata import Metadata from ._typing import DeserializingFunction from ._typing import DoneCallbackType +from ._typing import EOFType from ._typing import MetadatumType from ._typing import RequestIterableType from ._typing import RequestType @@ -380,7 +389,7 @@ class _StreamResponseMixin(Call): raw_response, self._response_deserializer ) - async def read(self) -> ResponseType: + async def read(self) -> Union[EOFType, ResponseType]: if self.done(): await self._raise_for_status() return cygrpc.EOF diff --git a/src/python/grpcio/grpc/aio/_interceptor.py b/src/python/grpcio/grpc/aio/_interceptor.py index e7ceb00fbbf..1401a08ee4c 100644 --- a/src/python/grpcio/grpc/aio/_interceptor.py +++ b/src/python/grpcio/grpc/aio/_interceptor.py @@ -43,6 +43,7 @@ from ._call import _RPC_HALF_CLOSED_DETAILS from ._metadata import Metadata from ._typing import DeserializingFunction from ._typing import DoneCallbackType +from ._typing import EOFType from ._typing import RequestIterableType from ._typing import RequestType from ._typing import ResponseIterableType @@ -494,12 +495,15 @@ class _InterceptedStreamResponseMixin: ) return self._response_aiter - async def read(self) -> ResponseType: + async def read(self) -> Union[EOFType, ResponseType]: if self._response_aiter is None: self._response_aiter = ( self._wait_for_interceptor_task_response_iterator() ) - return await self._response_aiter.asend(None) + try: + return await self._response_aiter.asend(None) + except StopAsyncIteration: + return cygrpc.EOF class _InterceptedStreamRequestMixin: @@ -1141,7 +1145,7 @@ class UnaryStreamCallResponseIterator( ): """UnaryStreamCall class wich uses an alternative response iterator.""" - async def read(self) -> ResponseType: + async def read(self) -> Union[EOFType, ResponseType]: # Behind the scenes everyting goes through the # async iterator. So this path should not be reached. raise NotImplementedError() @@ -1152,7 +1156,7 @@ class StreamStreamCallResponseIterator( ): """StreamStreamCall class wich uses an alternative response iterator.""" - async def read(self) -> ResponseType: + async def read(self) -> Union[EOFType, ResponseType]: # Behind the scenes everyting goes through the # async iterator. So this path should not be reached. raise NotImplementedError() diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index 6db04ed62fe..3ed50fe703b 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -19,6 +19,7 @@ CORE_SOURCE_FILES = [ 'src/core/channelz/channelz.cc', 'src/core/channelz/channelz_registry.cc', 'src/core/client_channel/backup_poller.cc', + 'src/core/client_channel/client_channel.cc', 'src/core/client_channel/client_channel_factory.cc', 'src/core/client_channel/client_channel_filter.cc', 'src/core/client_channel/client_channel_plugin.cc', @@ -26,6 +27,7 @@ CORE_SOURCE_FILES = [ 'src/core/client_channel/config_selector.cc', 'src/core/client_channel/dynamic_filters.cc', 'src/core/client_channel/global_subchannel_pool.cc', + 'src/core/client_channel/load_balanced_call_destination.cc', 'src/core/client_channel/local_subchannel_pool.cc', 'src/core/client_channel/retry_filter.cc', 'src/core/client_channel/retry_filter_legacy_call_data.cc', @@ -486,6 +488,7 @@ CORE_SOURCE_FILES = [ 'src/core/lib/experiments/config.cc', 'src/core/lib/experiments/experiments.cc', 'src/core/lib/gprpp/crash.cc', + 'src/core/lib/gprpp/dump_args.cc', 'src/core/lib/gprpp/examine_stack.cc', 'src/core/lib/gprpp/fork.cc', 'src/core/lib/gprpp/host_port.cc', @@ -511,10 +514,6 @@ CORE_SOURCE_FILES = [ 'src/core/lib/gprpp/windows/stat.cc', 'src/core/lib/gprpp/windows/thd.cc', 'src/core/lib/gprpp/work_serializer.cc', - 'src/core/lib/http/format_request.cc', - 'src/core/lib/http/httpcli.cc', - 'src/core/lib/http/httpcli_security_connector.cc', - 'src/core/lib/http/parser.cc', 'src/core/lib/iomgr/buffer_list.cc', 'src/core/lib/iomgr/call_combiner.cc', 'src/core/lib/iomgr/cfstream_handle.cc', @@ -807,6 +806,10 @@ CORE_SOURCE_FILES = [ 'src/core/util/alloc.cc', 'src/core/util/android/log.cc', 'src/core/util/atm.cc', + 'src/core/util/http_client/format_request.cc', + 'src/core/util/http_client/httpcli.cc', + 'src/core/util/http_client/httpcli_security_connector.cc', + 'src/core/util/http_client/parser.cc', 'src/core/util/iphone/cpu.cc', 'src/core/util/json/json_object_loader.cc', 'src/core/util/json/json_reader.cc', @@ -1076,6 +1079,7 @@ CORE_SOURCE_FILES = [ 'third_party/boringssl-with-bazel/src/crypto/dh_extra/dh_asn1.c', 'third_party/boringssl-with-bazel/src/crypto/dh_extra/params.c', 'third_party/boringssl-with-bazel/src/crypto/digest_extra/digest_extra.c', + 'third_party/boringssl-with-bazel/src/crypto/dilithium/dilithium.c', 'third_party/boringssl-with-bazel/src/crypto/dsa/dsa.c', 'third_party/boringssl-with-bazel/src/crypto/dsa/dsa_asn1.c', 'third_party/boringssl-with-bazel/src/crypto/ec_extra/ec_asn1.c', diff --git a/src/python/grpcio_csm_observability/MANIFEST.in b/src/python/grpcio_csm_observability/MANIFEST.in new file mode 100644 index 00000000000..754eb1d7e13 --- /dev/null +++ b/src/python/grpcio_csm_observability/MANIFEST.in @@ -0,0 +1,4 @@ +graft src/python/grpcio_csm_observability/grpc_csm_observability.egg-info +graft grpc_csm_observability +include grpc_version.py +include README.rst diff --git a/src/python/grpcio_csm_observability/README.rst b/src/python/grpcio_csm_observability/README.rst new file mode 100644 index 00000000000..8f2dc6ccd82 --- /dev/null +++ b/src/python/grpcio_csm_observability/README.rst @@ -0,0 +1,5 @@ +gRPC Python CSM Observability +========================= + +Package for gRPC Python CSM Observability. +TODO(xuanwn): Add more content. diff --git a/src/python/grpcio_csm_observability/grpc_csm_observability/BUILD.bazel b/src/python/grpcio_csm_observability/grpc_csm_observability/BUILD.bazel new file mode 100644 index 00000000000..8d65857630f --- /dev/null +++ b/src/python/grpcio_csm_observability/grpc_csm_observability/BUILD.bazel @@ -0,0 +1,36 @@ +# Copyright 2024 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. + +load("@grpc_python_dependencies//:requirements.bzl", "requirement") + +package(default_visibility = ["//:__subpackages__"]) + +# Since packages in requirement() are non-hermetic, +# csm_observability is for internal use only. +py_library( + name = "csm_observability", + srcs = glob(["*.py"]), + imports = [ + ".", + "../", + ], + srcs_version = "PY3ONLY", + deps = [ + requirement("opentelemetry-resourcedetector-gcp"), + requirement("opentelemetry-sdk"), + "//src/python/grpcio/grpc:grpcio", + "//src/python/grpcio_observability/grpc_observability:pyobservability", + "@com_google_protobuf//:protobuf_python", + ], +) diff --git a/src/python/grpcio_csm_observability/grpc_csm_observability/__init__.py b/src/python/grpcio_csm_observability/grpc_csm_observability/__init__.py new file mode 100644 index 00000000000..bfed07d3869 --- /dev/null +++ b/src/python/grpcio_csm_observability/grpc_csm_observability/__init__.py @@ -0,0 +1,18 @@ +# Copyright 2024 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 grpc_csm_observability._csm_observability_plugin import ( + CsmOpenTelemetryPlugin, +) + +__all__ = ("CsmOpenTelemetryPlugin",) diff --git a/src/python/grpcio_csm_observability/grpc_csm_observability/_csm_observability_plugin.py b/src/python/grpcio_csm_observability/grpc_csm_observability/_csm_observability_plugin.py new file mode 100644 index 00000000000..49828565c62 --- /dev/null +++ b/src/python/grpcio_csm_observability/grpc_csm_observability/_csm_observability_plugin.py @@ -0,0 +1,343 @@ +# Copyright 2024 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +import os +import re +from typing import AnyStr, Callable, Dict, Iterable, List, Optional, Union + +from google.protobuf import struct_pb2 +from grpc_observability._observability import OptionalLabelType +from grpc_observability._open_telemetry_plugin import OpenTelemetryLabelInjector +from grpc_observability._open_telemetry_plugin import OpenTelemetryPlugin +from grpc_observability._open_telemetry_plugin import OpenTelemetryPluginOption + +# pytype: disable=pyi-error +from opentelemetry.metrics import MeterProvider +from opentelemetry.resourcedetector.gcp_resource_detector import ( + GoogleCloudResourceDetector, +) +from opentelemetry.sdk.resources import Resource +from opentelemetry.semconv.resource import ResourceAttributes + +TRAFFIC_DIRECTOR_AUTHORITY = "traffic-director-global.xds.googleapis.com" +UNKNOWN_VALUE = "unknown" +TYPE_GCE = "gcp_compute_engine" +TYPE_GKE = "gcp_kubernetes_engine" +MESH_ID_PREFIX = "mesh:" + +METADATA_EXCHANGE_KEY_FIXED_MAP = { + "type": "csm.remote_workload_type", + "canonical_service": "csm.remote_workload_canonical_service", +} + +METADATA_EXCHANGE_KEY_GKE_MAP = { + "workload_name": "csm.remote_workload_name", + "namespace_name": "csm.remote_workload_namespace_name", + "cluster_name": "csm.remote_workload_cluster_name", + "location": "csm.remote_workload_location", + "project_id": "csm.remote_workload_project_id", +} + +METADATA_EXCHANGE_KEY_GCE_MAP = { + "workload_name": "csm.remote_workload_name", + "location": "csm.remote_workload_location", + "project_id": "csm.remote_workload_project_id", +} + + +class CSMOpenTelemetryLabelInjector(OpenTelemetryLabelInjector): + """ + An implementation of OpenTelemetryLabelInjector for CSM. + + This injector will fetch labels from GCP resource detector and + environment, it's also responsible for serialize and deserialize + metadata exchange labels. + """ + + _exchange_labels: Dict[str, AnyStr] + _additional_exchange_labels: Dict[str, str] + + def __init__(self): + fields = {} + self._exchange_labels = {} + self._additional_exchange_labels = {} + + # Labels from environment + canonical_service_value = os.getenv( + "CSM_CANONICAL_SERVICE_NAME", UNKNOWN_VALUE + ) + workload_name_value = os.getenv("CSM_WORKLOAD_NAME", UNKNOWN_VALUE) + + gcp_resource = GoogleCloudResourceDetector().detect() + resource_type_value = get_resource_type(gcp_resource) + namespace_value = get_str_value_from_resource( + ResourceAttributes.K8S_NAMESPACE_NAME, gcp_resource + ) + cluster_name_value = get_str_value_from_resource( + ResourceAttributes.K8S_CLUSTER_NAME, gcp_resource + ) + # ResourceAttributes.CLOUD_AVAILABILITY_ZONE are called + # "zones" on Google Cloud. + location_value = get_str_value_from_resource("cloud.zone", gcp_resource) + if UNKNOWN_VALUE == location_value: + location_value = get_str_value_from_resource( + ResourceAttributes.CLOUD_REGION, gcp_resource + ) + project_id_value = get_str_value_from_resource( + ResourceAttributes.CLOUD_ACCOUNT_ID, gcp_resource + ) + + fields["type"] = struct_pb2.Value(string_value=resource_type_value) + fields["canonical_service"] = struct_pb2.Value( + string_value=canonical_service_value + ) + if resource_type_value == TYPE_GKE: + fields["workload_name"] = struct_pb2.Value( + string_value=workload_name_value + ) + fields["namespace_name"] = struct_pb2.Value( + string_value=namespace_value + ) + fields["cluster_name"] = struct_pb2.Value( + string_value=cluster_name_value + ) + fields["location"] = struct_pb2.Value(string_value=location_value) + fields["project_id"] = struct_pb2.Value( + string_value=project_id_value + ) + elif resource_type_value == TYPE_GCE: + fields["workload_name"] = struct_pb2.Value( + string_value=workload_name_value + ) + fields["location"] = struct_pb2.Value(string_value=location_value) + fields["project_id"] = struct_pb2.Value( + string_value=project_id_value + ) + + serialized_struct = struct_pb2.Struct(fields=fields) + serialized_str = serialized_struct.SerializeToString() + + self._exchange_labels = {"XEnvoyPeerMetadata": serialized_str} + self._additional_exchange_labels[ + "csm.workload_canonical_service" + ] = canonical_service_value + self._additional_exchange_labels["csm.mesh_id"] = get_mesh_id() + + def get_labels_for_exchange(self) -> Dict[str, AnyStr]: + return self._exchange_labels + + def get_additional_labels( + self, include_exchange_labels: bool + ) -> Dict[str, str]: + if include_exchange_labels: + return self._additional_exchange_labels + else: + return {} + + @staticmethod + def deserialize_labels(labels: Dict[str, AnyStr]) -> Dict[str, AnyStr]: + deserialized_labels = {} + for key, value in labels.items(): + if "XEnvoyPeerMetadata" == key: + pb_struct = struct_pb2.Struct() + pb_struct.ParseFromString(value) + + remote_type = get_value_from_struct("type", pb_struct) + + for ( + local_key, + remote_key, + ) in METADATA_EXCHANGE_KEY_FIXED_MAP.items(): + deserialized_labels[remote_key] = get_value_from_struct( + local_key, pb_struct + ) + if remote_type == TYPE_GKE: + for ( + local_key, + remote_key, + ) in METADATA_EXCHANGE_KEY_GKE_MAP.items(): + deserialized_labels[remote_key] = get_value_from_struct( + local_key, pb_struct + ) + elif remote_type == TYPE_GCE: + for ( + local_key, + remote_key, + ) in METADATA_EXCHANGE_KEY_GCE_MAP.items(): + deserialized_labels[remote_key] = get_value_from_struct( + local_key, pb_struct + ) + # If CSM label injector is enabled on server side but client didn't send + # XEnvoyPeerMetadata, we'll record remote label as unknown. + else: + for _, remote_key in METADATA_EXCHANGE_KEY_FIXED_MAP.items(): + deserialized_labels[remote_key] = UNKNOWN_VALUE + deserialized_labels[key] = value + + return deserialized_labels + + +class CsmOpenTelemetryPluginOption(OpenTelemetryPluginOption): + """ + An implementation of OpenTelemetryPlugin for CSM. + """ + + _label_injector: CSMOpenTelemetryLabelInjector + + def __init__(self): + self._label_injector = CSMOpenTelemetryLabelInjector() + + @staticmethod + def is_active_on_client_channel(target: str) -> bool: + """Determines whether this plugin option is active on a channel based on target. + + Args: + target: Required. The target for the RPC. + + Returns: + True if this this plugin option is active on the channel, false otherwise. + """ + # CSM channels should have an "xds" scheme + if not target.startswith("xds:"): + return False + # If scheme is correct, the authority should be TD if exist + authority_pattern = r"^xds:\/\/([^/]+)" + match = re.search(authority_pattern, target) + if match: + return TRAFFIC_DIRECTOR_AUTHORITY in match.group(1) + else: + # Return True if the authority doesn't exist + return True + + @staticmethod + def is_active_on_server( + xds: bool, # pylint: disable=unused-argument + ) -> bool: + """Determines whether this plugin option is active on a given server. + + Since servers don't need to be xds enabled to work as part of a service + mesh, we're returning True and enable this PluginOption for all servers. + + Note: This always returns true because server can be part of the mesh even + if it's not xds-enabled. And we want CSM labels for those servers too. + + Args: + xds: Required. if this server is build for xds. + + Returns: + True if this this plugin option is active on the server, false otherwise. + """ + return True + + def get_label_injector(self) -> OpenTelemetryLabelInjector: + return self._label_injector + + +# pylint: disable=no-self-use +class CsmOpenTelemetryPlugin(OpenTelemetryPlugin): + """Describes a Plugin for CSM OpenTelemetry observability. + + This is class is part of an EXPERIMENTAL API. + """ + + plugin_options: Iterable[OpenTelemetryPluginOption] + meter_provider: Optional[MeterProvider] + generic_method_attribute_filter: Callable[[str], bool] + + def __init__( + self, + *, + plugin_options: Iterable[OpenTelemetryPluginOption] = [], + meter_provider: Optional[MeterProvider] = None, + generic_method_attribute_filter: Optional[Callable[[str], bool]] = None, + ): + new_options = list(plugin_options) + [CsmOpenTelemetryPluginOption()] + super().__init__( + plugin_options=new_options, + meter_provider=meter_provider, + generic_method_attribute_filter=generic_method_attribute_filter, + ) + + def _get_enabled_optional_labels(self) -> List[OptionalLabelType]: + return [OptionalLabelType.XDS_SERVICE_LABELS] + + +def get_value_from_struct(key: str, struct: struct_pb2.Struct) -> str: + value = struct.fields.get(key) + if not value: + return UNKNOWN_VALUE + return value.string_value + + +def get_str_value_from_resource( + attribute: Union[ResourceAttributes, str], resource: Resource +) -> str: + value = resource.attributes.get(attribute, UNKNOWN_VALUE) + return str(value) + + +# pylint: disable=line-too-long +def get_resource_type(gcp_resource: Resource) -> str: + # Convert resource type from GoogleCloudResourceDetector to the value we used for + # metadata exchange. + # Reference: https://github.com/GoogleCloudPlatform/opentelemetry-operations-python/blob/cc61f23a5ff2f16f4aa2c38d07e55153828849cc/opentelemetry-resourcedetector-gcp/src/opentelemetry/resourcedetector/gcp_resource_detector/__init__.py#L96 + gcp_resource_type = get_str_value_from_resource( + "gcp.resource_type", gcp_resource + ) + if gcp_resource_type == "gke_container": + return TYPE_GKE + elif gcp_resource_type == "gce_instance": + return TYPE_GCE + else: + return gcp_resource_type + + +# Returns the mesh ID by reading and parsing the bootstrap file. Returns "unknown" +# if for some reason, mesh ID could not be figured out. +def get_mesh_id() -> str: + config_contents = get_bootstrap_config_contents() + + try: + config_json = json.loads(config_contents) + # The expected format of the Node ID is - + # projects/[GCP Project number]/networks/mesh:[Mesh ID]/nodes/[UUID] + node_id_parts = config_json.get("node", {}).get("id", "").split("/") + if len(node_id_parts) == 6 and node_id_parts[3].startswith( + MESH_ID_PREFIX + ): + return node_id_parts[3][len(MESH_ID_PREFIX) :] + except json.decoder.JSONDecodeError: + return UNKNOWN_VALUE + + return UNKNOWN_VALUE + + +def get_bootstrap_config_contents() -> str: + """Get the contents of the bootstrap config from environment variable or file. + + Returns: + The content from environment variable. Or empty str if no config was found. + """ + contents_str = "" + for source in ("GRPC_XDS_BOOTSTRAP", "GRPC_XDS_BOOTSTRAP_CONFIG"): + config = os.getenv(source) + if config: + if os.path.isfile(config): # Prioritize file over raw config + with open(config, "r") as f: + contents_str = f.read() + else: + contents_str = config + + return contents_str diff --git a/src/python/grpcio_csm_observability/grpc_version.py b/src/python/grpcio_csm_observability/grpc_version.py new file mode 100644 index 00000000000..930d11a6dcb --- /dev/null +++ b/src/python/grpcio_csm_observability/grpc_version.py @@ -0,0 +1,17 @@ +# Copyright 2024 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. + +# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_csm_observability/grpc_version.py.template`!!! + +VERSION = '1.65.0.dev0' diff --git a/src/python/grpcio_csm_observability/setup.py b/src/python/grpcio_csm_observability/setup.py new file mode 100644 index 00000000000..582c6d9906c --- /dev/null +++ b/src/python/grpcio_csm_observability/setup.py @@ -0,0 +1,63 @@ +# Copyright 2024 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. + +import os + +import setuptools + +_PACKAGE_PATH = os.path.realpath(os.path.dirname(__file__)) +_README_PATH = os.path.join(_PACKAGE_PATH, "README.rst") + +# Ensure we're in the proper directory whether or not we're being used by pip. +os.chdir(os.path.dirname(os.path.abspath(__file__))) + +import grpc_version + +CLASSIFIERS = [ + "Development Status :: 4 - Beta", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "License :: OSI Approved :: Apache Software License", +] + +PACKAGE_DIRECTORIES = { + "": ".", +} + +INSTALL_REQUIRES = ( + "opentelemetry-sdk>=1.24.0", + "opentelemetry-resourcedetector-gcp>=1.6.0a0", + "grpcio=={version}".format(version=grpc_version.VERSION), + "protobuf>=5.26.1,<6.0dev", +) + +setuptools.setup( + name="grpcio-csm-observability", + version=grpc_version.VERSION, + description="gRPC Python CSM observability package", + long_description=open(_README_PATH, "r").read(), + author="The gRPC Authors", + author_email="grpc-io@googlegroups.com", + url="https://grpc.io", + project_urls={ + "Source Code": "https://github.com/grpc/grpc/tree/master/src/python/grpcio_csm_observability", + "Bug Tracker": "https://github.com/grpc/grpc/issues", + }, + license="Apache License 2.0", + classifiers=CLASSIFIERS, + package_dir=PACKAGE_DIRECTORIES, + packages=setuptools.find_packages("."), + python_requires=">=3.8", + install_requires=INSTALL_REQUIRES, +) diff --git a/src/python/grpcio_observability/grpc_observability/BUILD.bazel b/src/python/grpcio_observability/grpc_observability/BUILD.bazel index 3447bdaf1f2..f6144418273 100644 --- a/src/python/grpcio_observability/grpc_observability/BUILD.bazel +++ b/src/python/grpcio_observability/grpc_observability/BUILD.bazel @@ -21,6 +21,7 @@ cc_library( name = "observability", srcs = [ "client_call_tracer.cc", + "metadata_exchange.cc", "observability_util.cc", "python_observability_context.cc", "rpc_encoding.cc", @@ -30,6 +31,7 @@ cc_library( hdrs = [ "client_call_tracer.h", "constants.h", + "metadata_exchange.h", "observability_util.h", "python_observability_context.h", "rpc_encoding.h", diff --git a/src/python/grpcio_observability/grpc_observability/_cyobservability.pxd b/src/python/grpcio_observability/grpc_observability/_cyobservability.pxd index 240bf66e03a..124c08b48bb 100644 --- a/src/python/grpcio_observability/grpc_observability/_cyobservability.pxd +++ b/src/python/grpcio_observability/grpc_observability/_cyobservability.pxd @@ -59,6 +59,7 @@ cdef extern from "python_observability_context.h" namespace "grpc_observability" MeasurementType type MeasurementValue value bint registered_method + bint include_exchange_labels ctypedef struct SpanCensusData: string name @@ -80,8 +81,11 @@ cdef extern from "observability_util.h" namespace "grpc_observability": const char* target, const char* trace_id, const char* parent_span_id, + const char* identifier, + const vector[Label] exchange_labels, + bint add_csm_optional_labels, bint registered_method) except + - cdef void* CreateServerCallTracerFactory() except + + cdef void* CreateServerCallTracerFactory(const vector[Label] exchange_labels, const char* identifier) except + cdef queue[NativeCensusData]* g_census_data_buffer cdef void AwaitNextBatchLocked(unique_lock[mutex]&, int) nogil cdef bint PythonCensusStatsEnabled() nogil @@ -91,6 +95,7 @@ cdef extern from "observability_util.h" namespace "grpc_observability": cppclass NativeCensusData "::grpc_observability::CensusData": DataType type + string identifier Measurement measurement_data SpanCensusData span_data vector[Label] labels diff --git a/src/python/grpcio_observability/grpc_observability/_cyobservability.pyx b/src/python/grpcio_observability/grpc_observability/_cyobservability.pyx index 143d24731a7..91d00fe631d 100644 --- a/src/python/grpcio_observability/grpc_observability/_cyobservability.pyx +++ b/src/python/grpcio_observability/grpc_observability/_cyobservability.pyx @@ -20,7 +20,7 @@ import functools import logging import os from threading import Thread -from typing import List, Mapping, Tuple, Union +from typing import AnyStr, Dict, List, Mapping, Tuple, Union from grpc_observability import _observability @@ -33,6 +33,8 @@ cdef const char* SERVER_CALL_TRACER_FACTORY = "server_call_tracer_factory" cdef bint GLOBAL_SHUTDOWN_EXPORT_THREAD = False cdef object GLOBAL_EXPORT_THREAD +PLUGIN_IDENTIFIER_SEP = "," + _LOGGER = logging.getLogger(__name__) @@ -114,10 +116,9 @@ def activate_config(object py_config) -> None: def activate_stats() -> None: EnablePythonCensusStats(True); - -def create_client_call_tracer(bytes method_name, bytes target, - bytes trace_id, bint registered_method, - bytes parent_span_id=b'') -> cpython.PyObject: +def create_client_call_tracer(bytes method_name, bytes target, bytes trace_id, str identifier, + dict exchange_labels, object enabled_optional_labels, + bint registered_method, bytes parent_span_id=b'') -> cpython.PyObject: """Create a ClientCallTracer and save to PyCapsule. Returns: A grpc_observability._observability.ClientCallTracerCapsule object. @@ -126,18 +127,30 @@ def create_client_call_tracer(bytes method_name, bytes target, cdef char* c_target = cpython.PyBytes_AsString(target) cdef char* c_trace_id = cpython.PyBytes_AsString(trace_id) cdef char* c_parent_span_id = cpython.PyBytes_AsString(parent_span_id) - - cdef void* call_tracer = CreateClientCallTracer(c_method, c_target, c_trace_id, c_parent_span_id, registered_method) + identifier_bytes = _encode(identifier) + cdef char* c_identifier = cpython.PyBytes_AsString(identifier_bytes) + cdef vector[Label] c_labels = _labels_to_c_labels(exchange_labels) + cdef bint add_csm_optional_labels = False + + for label_type in enabled_optional_labels: + if label_type == _observability.OptionalLabelType.XDS_SERVICE_LABELS: + add_csm_optional_labels = True + + cdef void* call_tracer = CreateClientCallTracer(c_method, c_target, c_trace_id, c_parent_span_id, + c_identifier, c_labels, add_csm_optional_labels, + registered_method) capsule = cpython.PyCapsule_New(call_tracer, CLIENT_CALL_TRACER, NULL) return capsule -def create_server_call_tracer_factory_capsule() -> cpython.PyObject: +def create_server_call_tracer_factory_capsule(dict exchange_labels, str identifier) -> cpython.PyObject: """Create a ServerCallTracerFactory and save to PyCapsule. Returns: A grpc_observability._observability.ServerCallTracerFactoryCapsule object. """ - cdef void* call_tracer_factory = CreateServerCallTracerFactory() + cdef vector[Label] c_labels = _labels_to_c_labels(exchange_labels) + cdef char* c_identifier = cpython.PyBytes_AsString(_encode(identifier)) + cdef void* call_tracer_factory = CreateServerCallTracerFactory(c_labels, c_identifier) capsule = cpython.PyCapsule_New(call_tracer_factory, SERVER_CALL_TRACER_FACTORY, NULL) return capsule @@ -151,13 +164,25 @@ def delete_client_call_tracer(object client_call_tracer) -> None: del call_tracer_ptr -def _c_label_to_labels(vector[Label] c_labels) -> Mapping[str, str]: +def _c_label_to_labels(vector[Label] c_labels) -> Dict[str, AnyStr]: py_labels = {} for label in c_labels: - py_labels[_decode(label.key)] = _decode(label.value) + py_labels[_decode(label.key)] = label.value return py_labels +def _labels_to_c_labels(dict py_labels) -> vector[Label]: + cdef vector[Label] c_labels + cdef Label label + + for key, value in py_labels.items(): + label.key = _encode(key) + label.value = _encode(value) + c_labels.push_back(label) + + return c_labels + + def _c_measurement_to_measurement(object measurement ) -> Mapping[str, Union[enum, Mapping[str, Union[float, int], bool]]]: """Convert Cython Measurement to Python measurement. @@ -171,6 +196,7 @@ def _c_measurement_to_measurement(object measurement name -> cMetricsName type -> MeasurementType registered_method -> bool + include_exchange_labels -> bool value -> {value_double: float | value_int: int} """ measurement: Measurement @@ -179,6 +205,7 @@ def _c_measurement_to_measurement(object measurement py_measurement['name'] = measurement['name'] py_measurement['type'] = measurement['type'] py_measurement['registered_method'] = measurement['registered_method'] + py_measurement['include_exchange_labels'] = measurement['include_exchange_labels'] if measurement['type'] == kMeasurementDouble: py_measurement['value'] = {'value_double': measurement['value']['value_double']} else: @@ -208,7 +235,7 @@ def _cy_metric_name_to_py_metric_name(cMetricsName metric_name) -> MetricsName: raise ValueError('Invalid metric name %s' % metric_name) -def _get_stats_data(object measurement, object labels) -> _observability.StatsData: +def _get_stats_data(object measurement, object labels, object identifier) -> _observability.StatsData: """Convert a Python measurement to StatsData. Args: @@ -216,23 +243,31 @@ def _get_stats_data(object measurement, object labels) -> _observability.StatsDa with keys and values as following: name -> cMetricsName type -> MeasurementType + registered_method -> bool + include_exchange_labels -> bool value -> {value_double: float | value_int: int} - labels: Labels assciociated with stats data with type of dict[str, str]. + labels: Labels assciociated with stats data with type of Mapping[str, AnyStr]. + identifier: Specifies the plugins associated with this stats data. """ measurement: Measurement - labels: Mapping[str, str] + labels: Mapping[str, AnyStr] metric_name = _cy_metric_name_to_py_metric_name(measurement['name']) + identifiers = set(identifier.split(PLUGIN_IDENTIFIER_SEP)) if measurement['type'] == kMeasurementDouble: py_stat = _observability.StatsData(name=metric_name, measure_double=True, value_float=measurement['value']['value_double'], + labels=labels, + identifiers=identifiers, registered_method=measurement['registered_method'], - labels=labels) + include_exchange_labels=measurement['include_exchange_labels'],) else: py_stat = _observability.StatsData(name=metric_name, measure_double=False, value_int=measurement['value']['value_int'], + labels=labels, + identifiers=identifiers, registered_method=measurement['registered_method'], - labels=labels) + include_exchange_labels=measurement['include_exchange_labels'],) return py_stat @@ -253,8 +288,8 @@ def _get_tracing_data(SpanCensusData span_data, vector[Label] span_labels, span_annotations = py_span_annotations) -def _record_rpc_latency(object exporter, str method, str target, - float rpc_latency, str status_code, bint registered_method) -> None: +def _record_rpc_latency(object exporter, str method, str target, float rpc_latency, + str status_code, str identifier, bint registered_method) -> None: exporter: _observability.Exporter measurement = {} @@ -262,12 +297,13 @@ def _record_rpc_latency(object exporter, str method, str target, measurement['type'] = kMeasurementDouble measurement['value'] = {'value_double': rpc_latency} measurement['registered_method'] = registered_method + measurement['include_exchange_labels'] = False labels = {} labels[_decode(kClientMethod)] = method.strip("/") labels[_decode(kClientTarget)] = target labels[_decode(kClientStatus)] = status_code - metric = _get_stats_data(measurement, labels) + metric = _get_stats_data(measurement, labels, identifier) exporter.export_stats_data([metric]) @@ -313,8 +349,9 @@ cdef void _flush_census_data(object exporter): c_census_data = g_census_data_buffer.front() if c_census_data.type == kMetricData: py_labels = _c_label_to_labels(c_census_data.labels) + py_identifier = _decode(c_census_data.identifier) py_measurement = _c_measurement_to_measurement(c_census_data.measurement_data) - py_metric = _get_stats_data(py_measurement, py_labels) + py_metric = _get_stats_data(py_measurement, py_labels, py_identifier) py_metrics_batch.append(py_metric) else: py_span = _get_tracing_data(c_census_data.span_data, c_census_data.span_data.span_labels, @@ -344,3 +381,14 @@ cdef str _decode(bytes bytestring): except UnicodeDecodeError: _LOGGER.exception('Invalid encoding on %s', bytestring) return bytestring.decode('latin1') + + +cdef bytes _encode(object string_or_none): + if string_or_none is None: + return b'' + elif isinstance(string_or_none, (bytes,)): + return string_or_none + elif isinstance(string_or_none, (unicode,)): + return string_or_none.encode('utf8') + else: + raise TypeError('Expected str, not {}'.format(type(string_or_none))) diff --git a/src/python/grpcio_observability/grpc_observability/_gcp_observability.py b/src/python/grpcio_observability/grpc_observability/_gcp_observability.py deleted file mode 100644 index 5e4b6610e21..00000000000 --- a/src/python/grpcio_observability/grpc_observability/_gcp_observability.py +++ /dev/null @@ -1,167 +0,0 @@ -# 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. -from __future__ import annotations - -import logging -import time -from typing import Any, Set - -import grpc - -# pytype: disable=pyi-error -from grpc_observability import _cyobservability -from grpc_observability import _observability_config - -_LOGGER = logging.getLogger(__name__) - -ClientCallTracerCapsule = Any # it appears only once in the function signature -ServerCallTracerFactoryCapsule = ( - Any # it appears only once in the function signature -) -grpc_observability = Any # grpc_observability.py imports this module. - -GRPC_STATUS_CODE_TO_STRING = { - grpc.StatusCode.OK: "OK", - grpc.StatusCode.CANCELLED: "CANCELLED", - grpc.StatusCode.UNKNOWN: "UNKNOWN", - grpc.StatusCode.INVALID_ARGUMENT: "INVALID_ARGUMENT", - grpc.StatusCode.DEADLINE_EXCEEDED: "DEADLINE_EXCEEDED", - grpc.StatusCode.NOT_FOUND: "NOT_FOUND", - grpc.StatusCode.ALREADY_EXISTS: "ALREADY_EXISTS", - grpc.StatusCode.PERMISSION_DENIED: "PERMISSION_DENIED", - grpc.StatusCode.UNAUTHENTICATED: "UNAUTHENTICATED", - grpc.StatusCode.RESOURCE_EXHAUSTED: "RESOURCE_EXHAUSTED", - grpc.StatusCode.FAILED_PRECONDITION: "FAILED_PRECONDITION", - grpc.StatusCode.ABORTED: "ABORTED", - grpc.StatusCode.OUT_OF_RANGE: "OUT_OF_RANGE", - grpc.StatusCode.UNIMPLEMENTED: "UNIMPLEMENTED", - grpc.StatusCode.INTERNAL: "INTERNAL", - grpc.StatusCode.UNAVAILABLE: "UNAVAILABLE", - grpc.StatusCode.DATA_LOSS: "DATA_LOSS", -} - - -# pylint: disable=no-self-use -class GCPOpenCensusObservability(grpc._observability.ObservabilityPlugin): - """GCP OpenCensus based plugin implementation. - - If no exporter is passed, the default will be OpenCensus StackDriver - based exporter. - - For more details, please refer to User Guide: - * https://cloud.google.com/stackdriver/docs/solutions/grpc - - Attributes: - config: Configuration for GCP OpenCensus Observability. - exporter: Exporter used to export data. - """ - - config: _observability_config.GcpObservabilityConfig - exporter: "grpc_observability.Exporter" - _registered_method: Set[bytes] - - def __init__(self, exporter: "grpc_observability.Exporter" = None): - self.exporter = None - 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: - raise ValueError(f"Please provide an exporter!") - - if self.config.tracing_enabled: - self.set_tracing(True) - if self.config.stats_enabled: - self.set_stats(True) - - def __enter__(self): - try: - _cyobservability.cyobservability_init(self.exporter) - # TODO(xuanwn): Use specific exceptons - except Exception as e: # pylint: disable=broad-except - _LOGGER.exception("GCPOpenCensusObservability failed with: %s", e) - - grpc._observability.observability_init(self) - return self - - def __exit__(self, exc_type, exc_val, exc_tb) -> None: - self.exit() - - def exit(self) -> None: - # Sleep so we don't loss any data. If we shutdown export thread - # immediately after exit, it's possible that core didn't call RecordEnd - # in callTracer, and all data recorded by calling RecordEnd will be - # lost. - # CENSUS_EXPORT_BATCH_INTERVAL_SECS: The time equals to the time in - # AwaitNextBatchLocked. - # TODO(xuanwn): explicit synchronization - # https://github.com/grpc/grpc/issues/33262 - time.sleep(_cyobservability.CENSUS_EXPORT_BATCH_INTERVAL_SECS) - self.set_tracing(False) - self.set_stats(False) - _cyobservability.observability_deinit() - grpc._observability.observability_deinit() - - def create_client_call_tracer( - self, method_name: bytes, target: bytes - ) -> ClientCallTracerCapsule: - trace_id = b"TRACE_ID" - capsule = _cyobservability.create_client_call_tracer( - method_name, - target, - trace_id, - method_name in self._registered_methods, - ) - return capsule - - def create_server_call_tracer_factory( - self, - ) -> ServerCallTracerFactoryCapsule: - capsule = _cyobservability.create_server_call_tracer_factory_capsule() - return capsule - - def delete_client_call_tracer( - self, client_call_tracer: ClientCallTracerCapsule - ) -> None: - _cyobservability.delete_client_call_tracer(client_call_tracer) - - def save_trace_context( - self, trace_id: str, span_id: str, is_sampled: bool - ) -> None: - pass - - def record_rpc_latency( - self, - method: str, - target: str, - rpc_latency: float, - status_code: grpc.StatusCode, - ) -> None: - status_code = GRPC_STATUS_CODE_TO_STRING.get(status_code, "UNKNOWN") - _cyobservability._record_rpc_latency( - self.exporter, - method, - target, - rpc_latency, - status_code, - method in self._registered_methods, - ) - - def save_registered_method(self, method_name: bytes) -> None: - self._registered_methods.add(method_name) diff --git a/src/python/grpcio_observability/grpc_observability/_observability.py b/src/python/grpcio_observability/grpc_observability/_observability.py index 352a25c69d7..4d4d7dbb81c 100644 --- a/src/python/grpcio_observability/grpc_observability/_observability.py +++ b/src/python/grpcio_observability/grpc_observability/_observability.py @@ -16,7 +16,8 @@ from __future__ import annotations import abc from dataclasses import dataclass from dataclasses import field -from typing import List, Mapping, Tuple +import enum +from typing import AnyStr, Dict, List, Mapping, Set, Tuple class Exporter(metaclass=abc.ABCMeta): @@ -52,18 +53,23 @@ class StatsData: value. value_int: The actual metric value if measure_double is False. value_float: The actual metric value if measure_double is True. - registered_method: Whether the method in this data is a registered method - in stubs. + include_exchange_labels: Whether this data should include exchanged labels. labels: A dictionary that maps label tags associated with this metric to corresponding label value. + identifiers: A set of strings identifying which stats plugins this StatsData + belongs to. + registered_method: Whether the method in this data is a registered method + in stubs. """ name: "grpc_observability._cyobservability.MetricsName" measure_double: bool value_int: int = 0 value_float: float = 0.0 + include_exchange_labels: bool = False + labels: Dict[str, AnyStr] = field(default_factory=dict) + identifiers: Set[str] = field(default_factory=set) registered_method: bool = False - labels: Mapping[str, str] = field(default_factory=dict) @dataclass(frozen=True) @@ -102,5 +108,12 @@ class TracingData: status: str should_sample: bool child_span_count: int - span_labels: Mapping[str, str] = field(default_factory=dict) + span_labels: Mapping[str, AnyStr] = field(default_factory=dict) span_annotations: List[Tuple[str, str]] = field(default_factory=list) + + +@enum.unique +class OptionalLabelType(enum.Enum): + """What kinds of optional labels to add to metrics.""" + + XDS_SERVICE_LABELS = "kXdsServiceLabels" diff --git a/src/python/grpcio_observability/grpc_observability/_open_telemetry_measures.py b/src/python/grpcio_observability/grpc_observability/_open_telemetry_measures.py index 209ecd22c91..99a2fd94ce8 100644 --- a/src/python/grpcio_observability/grpc_observability/_open_telemetry_measures.py +++ b/src/python/grpcio_observability/grpc_observability/_open_telemetry_measures.py @@ -87,7 +87,8 @@ def base_metrics() -> List[Metric]: return [ CLIENT_ATTEMPT_STARTED, CLIENT_ATTEMPT_DURATION, - CLIENT_RPC_DURATION, + # CLIENT_RPC_DURATION is not required yet + # CLIENT_RPC_DURATION, CLIENT_ATTEMPT_SEND_BYTES, CLIENT_ATTEMPT_RECEIVED_BYTES, SERVER_STARTED_RPCS, diff --git a/src/python/grpcio_observability/grpc_observability/_open_telemetry_observability.py b/src/python/grpcio_observability/grpc_observability/_open_telemetry_observability.py index 24eee8e062f..b382bbea1fb 100644 --- a/src/python/grpcio_observability/grpc_observability/_open_telemetry_observability.py +++ b/src/python/grpcio_observability/grpc_observability/_open_telemetry_observability.py @@ -15,7 +15,7 @@ import logging import threading import time -from typing import Any, Dict, Iterable, List, Optional, Set, Union +from typing import Any, AnyStr, Dict, Iterable, List, Optional, Set, Union import grpc @@ -24,6 +24,8 @@ from grpc_observability import _cyobservability from grpc_observability import _observability from grpc_observability import _open_telemetry_measures from grpc_observability._cyobservability import MetricsName +from grpc_observability._cyobservability import PLUGIN_IDENTIFIER_SEP +from grpc_observability._observability import OptionalLabelType from grpc_observability._observability import StatsData from opentelemetry.metrics import Counter from opentelemetry.metrics import Histogram @@ -37,9 +39,13 @@ ServerCallTracerFactoryCapsule = ( ) grpc_observability = Any # grpc_observability.py imports this module. OpenTelemetryPlugin = Any # _open_telemetry_plugin.py imports this module. +OpenTelemetryPluginOption = ( + Any # _open_telemetry_plugin.py imports this module. +) GRPC_METHOD_LABEL = "grpc.method" GRPC_TARGET_LABEL = "grpc.target" +GRPC_CLIENT_METRIC_PREFIX = "grpc.client" GRPC_OTHER_LABEL_VALUE = "other" _observability_lock: threading.RLock = threading.RLock() _OPEN_TELEMETRY_OBSERVABILITY: Optional["OpenTelemetryObservability"] = None @@ -68,10 +74,16 @@ GRPC_STATUS_CODE_TO_STRING = { class _OpenTelemetryPlugin: _plugin: OpenTelemetryPlugin _metric_to_recorder: Dict[MetricsName, Union[Counter, Histogram]] + _enabled_client_plugin_options: Optional[List[OpenTelemetryPluginOption]] + _enabled_server_plugin_options: Optional[List[OpenTelemetryPluginOption]] + identifier: str def __init__(self, plugin: OpenTelemetryPlugin): self._plugin = plugin self._metric_to_recorder = dict() + self.identifier = str(id(self)) + self._enabled_client_plugin_options = None + self._enabled_server_plugin_options = None meter_provider = self._plugin.meter_provider if meter_provider: @@ -87,16 +99,38 @@ class _OpenTelemetryPlugin: def _record_stats_data(self, stats_data: StatsData) -> None: recorder = self._metric_to_recorder[stats_data.name] + enabled_plugin_options = [] + if GRPC_CLIENT_METRIC_PREFIX in recorder.name: + enabled_plugin_options = self._enabled_client_plugin_options + else: + enabled_plugin_options = self._enabled_server_plugin_options + # Only deserialize labels if we need add exchanged labels. + if stats_data.include_exchange_labels: + deserialized_labels = self._deserialize_labels( + stats_data.labels, enabled_plugin_options + ) + else: + deserialized_labels = stats_data.labels + labels = self._maybe_add_labels( + stats_data.include_exchange_labels, + deserialized_labels, + enabled_plugin_options, + ) + decoded_labels = self.decode_labels(labels) - target = stats_data.labels.get(GRPC_TARGET_LABEL, "") + target = decoded_labels.get(GRPC_TARGET_LABEL, "") if not self._plugin.target_attribute_filter(target): # Filter target name. - stats_data.labels[GRPC_TARGET_LABEL] = GRPC_OTHER_LABEL_VALUE + decoded_labels[GRPC_TARGET_LABEL] = GRPC_OTHER_LABEL_VALUE - method = stats_data.labels.get(GRPC_METHOD_LABEL, "") - if not self._plugin.generic_method_attribute_filter(method): - # Filter method name. - stats_data.labels[GRPC_METHOD_LABEL] = GRPC_OTHER_LABEL_VALUE + method = decoded_labels.get(GRPC_METHOD_LABEL, "") + if not ( + stats_data.registered_method + or self._plugin.generic_method_attribute_filter(method) + ): + # Filter method name if it's not registered method and + # generic_method_attribute_filter returns false. + decoded_labels[GRPC_METHOD_LABEL] = GRPC_OTHER_LABEL_VALUE value = 0 if stats_data.measure_double: @@ -104,18 +138,109 @@ class _OpenTelemetryPlugin: else: value = stats_data.value_int if isinstance(recorder, Counter): - recorder.add(value, attributes=stats_data.labels) + recorder.add(value, attributes=decoded_labels) elif isinstance(recorder, Histogram): - recorder.record(value, attributes=stats_data.labels) + recorder.record(value, attributes=decoded_labels) - # pylint: disable=no-self-use def maybe_record_stats_data(self, stats_data: List[StatsData]) -> None: # Records stats data to MeterProvider. if self._should_record(stats_data): self._record_stats_data(stats_data) + def get_client_exchange_labels(self) -> Dict[str, AnyStr]: + """Get labels used for client side Metadata Exchange.""" + + labels_for_exchange = {} + for plugin_option in self._enabled_client_plugin_options: + if hasattr(plugin_option, "get_label_injector") and hasattr( + plugin_option.get_label_injector(), "get_labels_for_exchange" + ): + labels_for_exchange.update( + plugin_option.get_label_injector().get_labels_for_exchange() + ) + return labels_for_exchange + + def get_server_exchange_labels(self) -> Dict[str, str]: + """Get labels used for server side Metadata Exchange.""" + labels_for_exchange = {} + for plugin_option in self._enabled_server_plugin_options: + if hasattr(plugin_option, "get_label_injector") and hasattr( + plugin_option.get_label_injector(), "get_labels_for_exchange" + ): + labels_for_exchange.update( + plugin_option.get_label_injector().get_labels_for_exchange() + ) + return labels_for_exchange + + def activate_client_plugin_options(self, target: bytes) -> None: + """Activate client plugin options based on option settings.""" + target_str = target.decode("utf-8", "replace") + if not self._enabled_client_plugin_options: + self._enabled_client_plugin_options = [] + for plugin_option in self._plugin.plugin_options: + if hasattr( + plugin_option, "is_active_on_client_channel" + ) and plugin_option.is_active_on_client_channel(target_str): + self._enabled_client_plugin_options.append(plugin_option) + + def activate_server_plugin_options(self, xds: bool) -> None: + """Activate server plugin options based on option settings.""" + if not self._enabled_server_plugin_options: + self._enabled_server_plugin_options = [] + for plugin_option in self._plugin.plugin_options: + if hasattr( + plugin_option, "is_active_on_server" + ) and plugin_option.is_active_on_server(xds): + self._enabled_server_plugin_options.append(plugin_option) + + @staticmethod + def _deserialize_labels( + labels: Dict[str, AnyStr], + enabled_plugin_options: List[OpenTelemetryPluginOption], + ) -> Dict[str, AnyStr]: + for plugin_option in enabled_plugin_options: + if all( + [ + hasattr(plugin_option, "get_label_injector"), + hasattr( + plugin_option.get_label_injector(), "deserialize_labels" + ), + ] + ): + labels = plugin_option.get_label_injector().deserialize_labels( + labels + ) + return labels + + @staticmethod + def _maybe_add_labels( + include_exchange_labels: bool, + labels: Dict[str, str], + enabled_plugin_options: List[OpenTelemetryPluginOption], + ) -> Dict[str, AnyStr]: + for plugin_option in enabled_plugin_options: + if all( + [ + hasattr(plugin_option, "get_label_injector"), + hasattr( + plugin_option.get_label_injector(), + "get_additional_labels", + ), + ] + ): + labels.update( + plugin_option.get_label_injector().get_additional_labels( + include_exchange_labels + ) + ) + return labels + + def get_enabled_optional_labels(self) -> List[OptionalLabelType]: + return self._plugin._get_enabled_optional_labels() + + @staticmethod def _register_metrics( - self, meter: Meter, metrics: List[_open_telemetry_measures.Metric] + meter: Meter, metrics: List[_open_telemetry_measures.Metric] ) -> Dict[MetricsName, Union[Counter, Histogram]]: metric_to_recorder_map = {} recorder = None @@ -179,6 +304,15 @@ class _OpenTelemetryPlugin: metric_to_recorder_map[metric.cyname] = recorder return metric_to_recorder_map + @staticmethod + def decode_labels(labels: Dict[str, AnyStr]) -> Dict[str, str]: + decoded_labels = {} + for key, value in labels.items(): + if isinstance(value, bytes): + value = value.decode() + decoded_labels[key] = value + return decoded_labels + def start_open_telemetry_observability( *, @@ -220,19 +354,25 @@ class OpenTelemetryObservability(grpc._observability.ObservabilityPlugin): This is class is part of an EXPERIMENTAL API. Args: - plugin: _OpenTelemetryPlugin to enable. + plugins: _OpenTelemetryPlugins to enable. """ - exporter: "grpc_observability.Exporter" + _exporter: "grpc_observability.Exporter" + _plugins: List[_OpenTelemetryPlugin] _registered_method: Set[bytes] + _client_option_activated: bool + _server_option_activated: bool def __init__( self, *, plugins: Optional[Iterable[_OpenTelemetryPlugin]], ): - self.exporter = _OpenTelemetryExporterDelegator(plugins) + self._exporter = _OpenTelemetryExporterDelegator(plugins) self._registered_methods = set() + self._plugins = plugins + self._client_option_activated = False + self._server_option_activated = False def observability_init(self): try: @@ -242,7 +382,7 @@ class OpenTelemetryObservability(grpc._observability.ObservabilityPlugin): raise ValueError(f"Activate observability metrics failed with: {e}") try: - _cyobservability.cyobservability_init(self.exporter) + _cyobservability.cyobservability_init(self._exporter) # TODO(xuanwn): Use specific exceptons except Exception as e: # pylint: disable=broad-except _LOGGER.exception("Initiate observability failed with: %s", e) @@ -268,18 +408,34 @@ class OpenTelemetryObservability(grpc._observability.ObservabilityPlugin): self, method_name: bytes, target: bytes ) -> ClientCallTracerCapsule: trace_id = b"TRACE_ID" - registered_method = False - if method_name in self._registered_methods: - registered_method = True + self._maybe_activate_client_plugin_options(target) + exchange_labels = self._get_client_exchange_labels() + enabled_optional_labels = set() + for plugin in self._plugins: + enabled_optional_labels.update(plugin.get_enabled_optional_labels()) + capsule = _cyobservability.create_client_call_tracer( - method_name, target, trace_id, registered_method + method_name, + target, + trace_id, + self._get_identifier(), + exchange_labels, + enabled_optional_labels, + method_name in self._registered_methods, ) return capsule def create_server_call_tracer_factory( self, - ) -> ServerCallTracerFactoryCapsule: - capsule = _cyobservability.create_server_call_tracer_factory_capsule() + *, + xds: bool = False, + ) -> Optional[ServerCallTracerFactoryCapsule]: + capsule = None + self._maybe_activate_server_plugin_options(xds) + exchange_labels = self._get_server_exchange_labels() + capsule = _cyobservability.create_server_call_tracer_factory_capsule( + exchange_labels, self._get_identifier() + ) return capsule def delete_client_call_tracer( @@ -300,22 +456,53 @@ class OpenTelemetryObservability(grpc._observability.ObservabilityPlugin): status_code: grpc.StatusCode, ) -> None: status_code = GRPC_STATUS_CODE_TO_STRING.get(status_code, "UNKNOWN") - registered_method = False encoded_method = method.encode("utf8") - if encoded_method in self._registered_methods: - registered_method = True _cyobservability._record_rpc_latency( - self.exporter, + self._exporter, method, target, rpc_latency, status_code, - registered_method, + self._get_identifier(), + encoded_method in self._registered_methods, ) def save_registered_method(self, method_name: bytes) -> None: self._registered_methods.add(method_name) + def _get_client_exchange_labels(self) -> Dict[str, AnyStr]: + client_exchange_labels = {} + for _plugin in self._plugins: + client_exchange_labels.update(_plugin.get_client_exchange_labels()) + return client_exchange_labels + + def _get_server_exchange_labels(self) -> Dict[str, AnyStr]: + server_exchange_labels = {} + for _plugin in self._plugins: + server_exchange_labels.update(_plugin.get_server_exchange_labels()) + return server_exchange_labels + + def _maybe_activate_client_plugin_options(self, target: bytes) -> None: + if not self._client_option_activated: + for _plugin in self._plugins: + _plugin.activate_client_plugin_options(target) + self._client_option_activated = True + + def _maybe_activate_server_plugin_options(self, xds: bool) -> None: + if not self._server_option_activated: + for _plugin in self._plugins: + _plugin.activate_server_plugin_options(xds) + self._server_option_activated = True + + def _get_identifier(self) -> str: + plugin_identifiers = [] + for _plugin in self._plugins: + plugin_identifiers.append(_plugin.identifier) + return PLUGIN_IDENTIFIER_SEP.join(plugin_identifiers) + + def get_enabled_optional_labels(self) -> List[OptionalLabelType]: + return [] + def _start_open_telemetry_observability( otel_o11y: OpenTelemetryObservability, diff --git a/src/python/grpcio_observability/grpc_observability/_open_telemetry_plugin.py b/src/python/grpcio_observability/grpc_observability/_open_telemetry_plugin.py index 16c89d9594e..b0c7e9841e3 100644 --- a/src/python/grpcio_observability/grpc_observability/_open_telemetry_plugin.py +++ b/src/python/grpcio_observability/grpc_observability/_open_telemetry_plugin.py @@ -12,70 +12,79 @@ # See the License for the specific language governing permissions and # limitations under the License. -import abc -from typing import Callable, Dict, Iterable, List, Optional +from typing import AnyStr, Callable, Dict, Iterable, List, Optional # pytype: disable=pyi-error from grpc_observability import _open_telemetry_observability +from grpc_observability._observability import OptionalLabelType from opentelemetry.metrics import MeterProvider +GRPC_METHOD_LABEL = "grpc.method" +GRPC_TARGET_LABEL = "grpc.target" +GRPC_CLIENT_METRIC_PREFIX = "grpc.client" +GRPC_OTHER_LABEL_VALUE = "other" -class OpenTelemetryLabelInjector(abc.ABC): + +class OpenTelemetryLabelInjector: """ An interface that allows you to add additional labels on the calls traced. - - Please note that this class is still work in progress and NOT READY to be used. """ - _labels: List[Dict[str, str]] - - def __init__(self): - # Calls Python OTel API to detect resource and get labels, save - # those lables to OpenTelemetryLabelInjector.labels. - pass + def get_labels_for_exchange(self) -> Dict[str, AnyStr]: + """ + Get labels used for metadata exchange. - @abc.abstractmethod - def get_labels(self): - # Get additional labels for this OpenTelemetryLabelInjector. + Returns: + A dict of labels, with a string as key representing label name, string or bytes + as value representing label value. + """ raise NotImplementedError() + def get_additional_labels( + self, include_exchange_labels: bool + ) -> Dict[str, str]: + """ + Get additional labels added by this injector. -class OpenTelemetryPluginOption(abc.ABC): - """ - An interface that allows you to add additional function to OpenTelemetryPlugin. - - Please note that this class is still work in progress and NOT READY to be used. - """ - - @abc.abstractmethod - def is_active_on_method(self, method: str) -> bool: - """Determines whether this plugin option is active on a given method. + The return value from this method will be added directly to metric data. Args: - method: Required. The RPC method, for example: `/helloworld.Greeter/SayHello`. + include_exchange_labels: Whether to add additional metadata exchange related labels. Returns: - True if this this plugin option is active on the giving method, false otherwise. + A dict of labels. """ raise NotImplementedError() - @abc.abstractmethod - def is_active_on_server(self, channel_args: List[str]) -> bool: - """Determines whether this plugin option is active on a given server. + # pylint: disable=no-self-use + def deserialize_labels( + self, labels: Dict[str, AnyStr] + ) -> Dict[str, AnyStr]: + """ + Deserialize the labels if required. - Args: - channel_args: Required. The channel args used for server. - TODO(xuanwn): detail on what channel_args will contain. + If this injector added labels for metadata exchange, this method will be called to + deserialize the exchanged labels. + + For example, if this injector added xds_peer_metadata_label for exchange: + + labels: {"labelA": b"valueA", "xds_peer_metadata_label": b"exchanged_bytes"} + + This method should deserialize xds_peer_metadata_label and return labels as: + + labels: {"labelA": b"valueA", "xds_label_A": "xds_label_A", + "xds_label_B": "xds_label_B"} Returns: - True if this this plugin option is active on the server, false otherwise. + A dict of deserialized labels. """ - raise NotImplementedError() + return labels - @abc.abstractmethod - def get_label_injector(self) -> Optional[OpenTelemetryLabelInjector]: - # Returns the LabelsInjector used by this plugin option, or None. - raise NotImplementedError() + +class OpenTelemetryPluginOption: + """ + An interface that allows you to add additional function to OpenTelemetryPlugin. + """ # pylint: disable=no-self-use @@ -86,7 +95,7 @@ class OpenTelemetryPlugin: meter_provider: Optional[MeterProvider] target_attribute_filter: Callable[[str], bool] generic_method_attribute_filter: Callable[[str], bool] - _plugin: _open_telemetry_observability._OpenTelemetryPlugin + _plugins: List[_open_telemetry_observability._OpenTelemetryPlugin] def __init__( self, @@ -120,17 +129,15 @@ class OpenTelemetryPlugin: """ self.plugin_options = plugin_options self.meter_provider = meter_provider - if target_attribute_filter: - self.target_attribute_filter = target_attribute_filter - else: - self.target_attribute_filter = lambda target: True - if generic_method_attribute_filter: - self.generic_method_attribute_filter = ( - generic_method_attribute_filter - ) - else: - self.generic_method_attribute_filter = lambda method: False - self._plugin = _open_telemetry_observability._OpenTelemetryPlugin(self) + self.target_attribute_filter = target_attribute_filter or ( + lambda target: True + ) + self.generic_method_attribute_filter = ( + generic_method_attribute_filter or (lambda target: False) + ) + self._plugins = [ + _open_telemetry_observability._OpenTelemetryPlugin(self) + ] def register_global(self) -> None: """ @@ -140,7 +147,7 @@ class OpenTelemetryPlugin: RuntimeError: If a global plugin was already registered. """ _open_telemetry_observability.start_open_telemetry_observability( - plugins=[self._plugin] + plugins=self._plugins ) def deregister_global(self) -> None: @@ -154,8 +161,11 @@ class OpenTelemetryPlugin: def __enter__(self) -> None: _open_telemetry_observability.start_open_telemetry_observability( - plugins=[self._plugin] + plugins=self._plugins ) def __exit__(self, exc_type, exc_val, exc_tb) -> None: _open_telemetry_observability.end_open_telemetry_observability() + + def _get_enabled_optional_labels(self) -> List[OptionalLabelType]: + return [] 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 5d31619b949..9d9ca694be1 100644 --- a/src/python/grpcio_observability/grpc_observability/client_call_tracer.cc +++ b/src/python/grpcio_observability/grpc_observability/client_call_tracer.cc @@ -22,6 +22,7 @@ #include "absl/strings/str_cat.h" #include "absl/time/clock.h" #include "constants.h" +#include "metadata_exchange.h" #include "observability_util.h" #include "python_observability_context.h" @@ -42,10 +43,15 @@ constexpr uint32_t PythonOpenCensusCallTracer::PythonOpenCensusCallTracer( const char* method, const char* target, const char* trace_id, - const char* parent_span_id, bool tracing_enabled, bool registered_method) + const char* parent_span_id, const char* identifier, + const std::vector