diff --git a/BUILD b/BUILD index 887a2c2a6c1..2df4affb927 100644 --- a/BUILD +++ b/BUILD @@ -1800,6 +1800,7 @@ grpc_cc_library( "stats", "//src/core:arena", "//src/core:call_arena_allocator", + "//src/core:call_destination", "//src/core:channel_args", "//src/core:channel_stack_type", "//src/core:compression", @@ -1992,15 +1993,17 @@ grpc_cc_library( "//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/call_utils.cc", + "//src/core:lib/surface/client_call.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/filter_stack_call.cc", "//src/core:lib/surface/lame_client.cc", "//src/core:lib/surface/metadata_array.cc", + "//src/core:lib/surface/server_call.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/transport.cc", "//src/core:lib/transport/transport_op_string.cc", ], @@ -2013,14 +2016,16 @@ grpc_cc_library( "//src/core:lib/compression/message_compress.h", "//src/core:lib/surface/call.h", "//src/core:lib/surface/call_test_only.h", + "//src/core:lib/surface/call_utils.h", + "//src/core:lib/surface/client_call.h", "//src/core:lib/surface/completion_queue.h", "//src/core:lib/surface/completion_queue_factory.h", "//src/core:lib/surface/event_string.h", + "//src/core:lib/surface/filter_stack_call.h", "//src/core:lib/surface/init.h", "//src/core:lib/surface/lame_client.h", + "//src/core:lib/surface/server_call.h", "//src/core:lib/surface/validate_metadata.h", - "//src/core:lib/surface/wait_for_cq_end_op.h", - "//src/core:lib/transport/batch_builder.h", "//src/core:lib/transport/transport.h", ], defines = select({ @@ -2033,8 +2038,8 @@ grpc_cc_library( "absl/container:inlined_vector", "absl/functional:any_invocable", "absl/functional:function_ref", + "absl/log", "absl/log:check", - "absl/log:log", "absl/meta:type_traits", "absl/status", "absl/status:statusor", @@ -2065,6 +2070,7 @@ grpc_cc_library( "debug_location", "exec_ctx", "gpr", + "grpc_core_credentials_header", "grpc_public_hdrs", "grpc_trace", "iomgr", @@ -2125,6 +2131,7 @@ grpc_cc_library( "//src/core:ref_counted", "//src/core:seq", "//src/core:server_interface", + "//src/core:single_set_ptr", "//src/core:slice", "//src/core:slice_buffer", "//src/core:slice_cast", @@ -3713,8 +3720,8 @@ grpc_cc_library( "absl/container:flat_hash_set", "absl/container:inlined_vector", "absl/functional:any_invocable", + "absl/log", "absl/log:check", - "absl/log:log", "absl/status", "absl/status:statusor", "absl/strings", @@ -3751,7 +3758,6 @@ grpc_cc_library( "stats", "uri_parser", "work_serializer", - "//src/core:activity", "//src/core:arena", "//src/core:arena_promise", "//src/core:backend_metric_parser", @@ -3811,7 +3817,6 @@ grpc_cc_library( "//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", diff --git a/CMakeLists.txt b/CMakeLists.txt index 22540a4b7c4..ae0d73b684f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -966,6 +966,7 @@ if(gRPC_BUILD_TESTS) add_dependencies(buildtests_cxx call_finalization_test) add_dependencies(buildtests_cxx call_host_override_test) add_dependencies(buildtests_cxx call_tracer_test) + add_dependencies(buildtests_cxx call_utils_test) add_dependencies(buildtests_cxx cancel_after_accept_test) add_dependencies(buildtests_cxx cancel_after_client_done_test) add_dependencies(buildtests_cxx cancel_after_invoke_test) @@ -1000,6 +1001,9 @@ if(gRPC_BUILD_TESTS) add_dependencies(buildtests_cxx cli_call_test) add_dependencies(buildtests_cxx client_auth_filter_test) add_dependencies(buildtests_cxx client_authority_filter_test) + if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) + add_dependencies(buildtests_cxx client_call_test) + endif() add_dependencies(buildtests_cxx client_callback_end2end_test) add_dependencies(buildtests_cxx client_channel_service_config_test) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) @@ -1382,6 +1386,9 @@ if(gRPC_BUILD_TESTS) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) add_dependencies(buildtests_cxx server_builder_with_socket_mutator_test) endif() + if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) + add_dependencies(buildtests_cxx server_call_test) + endif() add_dependencies(buildtests_cxx server_call_tracer_factory_test) add_dependencies(buildtests_cxx server_chttp2_test) add_dependencies(buildtests_cxx server_config_selector_test) @@ -2475,22 +2482,24 @@ add_library(grpc 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/call_utils.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/client_call.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/filter_stack_call.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_call.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_arena_allocator.cc src/core/lib/transport/call_filters.cc @@ -3234,22 +3243,24 @@ add_library(grpc_unsecure 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/call_utils.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/client_call.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/filter_stack_call.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_call.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_arena_allocator.cc src/core/lib/transport/call_filters.cc @@ -5354,19 +5365,21 @@ add_library(grpc_authorization_provider 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/call_utils.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/client_call.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/filter_stack_call.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/server_call.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_arena_allocator.cc src/core/lib/transport/call_filters.cc src/core/lib/transport/call_final_info.cc @@ -7538,6 +7551,7 @@ add_executable(bad_ping_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -8014,6 +8028,7 @@ add_executable(binary_metadata_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -8456,6 +8471,7 @@ add_executable(call_creds_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -8665,6 +8681,7 @@ add_executable(call_host_override_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -8758,6 +8775,310 @@ target_link_libraries(call_tracer_test ) +endif() +if(gRPC_BUILD_TESTS) + +add_executable(call_utils_test + src/core/channelz/channel_trace.cc + src/core/channelz/channelz.cc + src/core/channelz/channelz_registry.cc + src/core/ext/upb-gen/google/protobuf/any.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/handshaker/handshaker_registry.cc + src/core/handshaker/proxy_mapper_registry.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/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/connected_channel.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/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/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 + 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/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/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/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/security/certificate_provider/certificate_provider_registry.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/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/call_utils.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/client_call.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/filter_stack_call.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/server_call.cc + src/core/lib/surface/validate_metadata.cc + src/core/lib/surface/version.cc + src/core/lib/transport/call_arena_allocator.cc + src/core/lib/transport/call_filters.cc + src/core/lib/transport/call_final_info.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/interception_chain.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/telemetry/call_tracer.cc + src/core/telemetry/histogram_view.cc + src/core/telemetry/metrics.cc + src/core/telemetry/stats.cc + src/core/telemetry/stats_data.cc + src/core/tsi/alts/handshaker/transport_security_common_api.cc + src/core/util/json/json_writer.cc + test/core/call/call_utils_test.cc + 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/encode.c + third_party/upb/upb/wire/eps_copy_input_stream.c + third_party/upb/upb/wire/internal/decode_fast.c + third_party/upb/upb/wire/reader.c +) +if(WIN32 AND MSVC) + if(BUILD_SHARED_LIBS) + target_compile_definitions(call_utils_test + PRIVATE + "GPR_DLL_IMPORTS" + ) + endif() +endif() +target_compile_features(call_utils_test PUBLIC cxx_std_14) +target_include_directories(call_utils_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(call_utils_test + ${_gRPC_ALLTARGETS_LIBRARIES} + gtest + utf8_range_lib + upb_message_lib + ${_gRPC_ZLIB_LIBRARIES} + absl::config + absl::no_destructor + absl::cleanup + absl::flat_hash_map + absl::inlined_vector + absl::function_ref + absl::hash + absl::type_traits + absl::statusor + absl::span + absl::utility + ${_gRPC_CARES_LIBRARIES} + gpr + ${_gRPC_ADDRESS_SORTING_LIBRARIES} +) + + endif() if(gRPC_BUILD_TESTS) @@ -8771,6 +9092,7 @@ add_executable(cancel_after_accept_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -8834,6 +9156,7 @@ add_executable(cancel_after_client_done_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -8897,6 +9220,7 @@ add_executable(cancel_after_invoke_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -8960,6 +9284,7 @@ add_executable(cancel_after_round_trip_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -9070,6 +9395,7 @@ add_executable(cancel_before_invoke_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -9217,6 +9543,7 @@ add_executable(cancel_in_a_vacuum_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -9280,6 +9607,7 @@ add_executable(cancel_with_status_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -10479,6 +10807,61 @@ target_link_libraries(client_authority_filter_test ) +endif() +if(gRPC_BUILD_TESTS) +if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) + + add_executable(client_call_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/batch_builder.cc + test/core/call/client_call_test.cc + test/core/call/yodel/test_main.cc + test/core/call/yodel/yodel_test.cc + test/core/end2end/cq_verifier.cc + test/core/event_engine/event_engine_test_utils.cc + test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc + ) + if(WIN32 AND MSVC) + if(BUILD_SHARED_LIBS) + target_compile_definitions(client_call_test + PRIVATE + "GPR_DLL_IMPORTS" + "GRPC_DLL_IMPORTS" + ) + endif() + endif() + target_compile_features(client_call_test PUBLIC cxx_std_14) + target_include_directories(client_call_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_call_test + ${_gRPC_ALLTARGETS_LIBRARIES} + gtest + ${_gRPC_PROTOBUF_LIBRARIES} + grpc_test_util + ) + + +endif() endif() if(gRPC_BUILD_TESTS) @@ -10594,6 +10977,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) 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/event_engine_test_utils.cc test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc ) if(WIN32 AND MSVC) @@ -10935,6 +11319,7 @@ add_executable(client_streaming_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -11274,6 +11659,7 @@ add_executable(compressed_payload_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -11420,6 +11806,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) 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/event_engine_test_utils.cc test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc ) if(WIN32 AND MSVC) @@ -11611,6 +11998,7 @@ add_executable(connectivity_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -12040,6 +12428,7 @@ add_executable(default_host_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -12248,6 +12637,7 @@ add_executable(disappearing_server_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -12603,6 +12993,7 @@ add_executable(empty_batch_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -13983,6 +14374,7 @@ add_executable(filter_causes_close_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -14046,6 +14438,7 @@ add_executable(filter_init_fails_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -14159,6 +14552,7 @@ add_executable(filtered_metadata_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -14944,6 +15338,7 @@ add_executable(graceful_server_shutdown_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -15310,6 +15705,7 @@ add_executable(grpc_authz_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -16312,6 +16708,7 @@ endif() if(gRPC_BUILD_TESTS) add_executable(h2_ssl_cert_test + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/data/client_certs.cc test/core/end2end/data/server1_cert.cc @@ -16701,6 +17098,7 @@ add_executable(high_initial_seqno_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -17010,6 +17408,7 @@ add_executable(hpack_size_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -17166,6 +17565,7 @@ add_executable(http2_stats_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -17621,6 +18021,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) ${_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/event_engine_test_utils.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 @@ -18005,19 +18406,21 @@ add_executable(interception_chain_test 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/call_utils.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/client_call.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/filter_stack_call.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/server_call.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_arena_allocator.cc src/core/lib/transport/call_filters.cc src/core/lib/transport/call_final_info.cc @@ -18359,6 +18762,7 @@ add_executable(invoke_large_request_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -18748,6 +19152,7 @@ add_executable(keepalive_timeout_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -18854,6 +19259,7 @@ add_executable(large_metadata_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -19055,6 +19461,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) 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/event_engine_test_utils.cc test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc ) if(WIN32 AND MSVC) @@ -19577,6 +19984,7 @@ add_executable(max_concurrent_streams_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -19640,6 +20048,7 @@ add_executable(max_connection_age_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -19703,6 +20112,7 @@ add_executable(max_connection_idle_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -19766,6 +20176,7 @@ add_executable(max_message_length_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -20448,6 +20859,7 @@ add_executable(negative_deadline_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -20543,6 +20955,7 @@ add_executable(no_logging_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -20606,6 +21019,7 @@ add_executable(no_op_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -21535,6 +21949,7 @@ add_executable(payload_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -21908,6 +22323,7 @@ add_executable(ping_pong_streaming_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -22022,6 +22438,7 @@ add_executable(ping_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -23016,6 +23433,7 @@ add_executable(proxy_auth_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -23592,6 +24010,7 @@ add_executable(registered_call_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -23699,6 +24118,7 @@ add_executable(request_with_flags_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -23762,6 +24182,7 @@ add_executable(request_with_payload_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -24096,6 +24517,7 @@ add_executable(resource_quota_server_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -24201,6 +24623,7 @@ add_executable(retry_cancel_after_first_attempt_starts_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -24264,6 +24687,7 @@ add_executable(retry_cancel_during_delay_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -24327,6 +24751,7 @@ add_executable(retry_cancel_with_multiple_send_batches_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -24390,6 +24815,7 @@ add_executable(retry_cancellation_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -24453,6 +24879,7 @@ add_executable(retry_disabled_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -24516,6 +24943,7 @@ add_executable(retry_exceeds_buffer_size_in_delay_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -24579,6 +25007,7 @@ add_executable(retry_exceeds_buffer_size_in_initial_batch_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -24642,6 +25071,7 @@ add_executable(retry_exceeds_buffer_size_in_subsequent_batch_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -24705,6 +25135,7 @@ add_executable(retry_lb_drop_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -24768,6 +25199,7 @@ add_executable(retry_lb_fail_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -24831,6 +25263,7 @@ add_executable(retry_non_retriable_status_before_trailers_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -24894,6 +25327,7 @@ add_executable(retry_non_retriable_status_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -24957,6 +25391,7 @@ add_executable(retry_per_attempt_recv_timeout_on_last_attempt_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -25020,6 +25455,7 @@ add_executable(retry_per_attempt_recv_timeout_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -25083,6 +25519,7 @@ add_executable(retry_recv_initial_metadata_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -25146,6 +25583,7 @@ add_executable(retry_recv_message_replay_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -25209,6 +25647,7 @@ add_executable(retry_recv_message_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -25272,6 +25711,7 @@ add_executable(retry_recv_trailing_metadata_error_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -25335,6 +25775,7 @@ add_executable(retry_send_initial_metadata_refs_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -25398,6 +25839,7 @@ add_executable(retry_send_op_fails_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -25461,6 +25903,7 @@ add_executable(retry_send_recv_batch_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -25524,6 +25967,7 @@ add_executable(retry_server_pushback_delay_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -25587,6 +26031,7 @@ add_executable(retry_server_pushback_disabled_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -25692,6 +26137,7 @@ add_executable(retry_streaming_after_commit_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -25755,6 +26201,7 @@ add_executable(retry_streaming_succeeds_before_replay_finished_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -25818,6 +26265,7 @@ add_executable(retry_streaming_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -25881,6 +26329,7 @@ add_executable(retry_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -25986,6 +26435,7 @@ add_executable(retry_throttled_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -26049,6 +26499,7 @@ add_executable(retry_too_many_attempts_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -26112,6 +26563,7 @@ add_executable(retry_transparent_goaway_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -26175,6 +26627,7 @@ add_executable(retry_transparent_max_concurrent_streams_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -26238,6 +26691,7 @@ add_executable(retry_transparent_not_sent_on_wire_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -26301,6 +26755,7 @@ add_executable(retry_unref_before_finish_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -26364,6 +26819,7 @@ add_executable(retry_unref_before_recv_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -27108,6 +27564,61 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) ) +endif() +endif() +if(gRPC_BUILD_TESTS) +if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) + + add_executable(server_call_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/batch_builder.cc + test/core/call/server_call_test.cc + test/core/call/yodel/test_main.cc + test/core/call/yodel/yodel_test.cc + test/core/end2end/cq_verifier.cc + test/core/event_engine/event_engine_test_utils.cc + test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc + ) + if(WIN32 AND MSVC) + if(BUILD_SHARED_LIBS) + target_compile_definitions(server_call_test + PRIVATE + "GPR_DLL_IMPORTS" + "GRPC_DLL_IMPORTS" + ) + endif() + endif() + target_compile_features(server_call_test PUBLIC cxx_std_14) + target_include_directories(server_call_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(server_call_test + ${_gRPC_ALLTARGETS_LIBRARIES} + gtest + ${_gRPC_PROTOBUF_LIBRARIES} + grpc_test_util + ) + + endif() endif() if(gRPC_BUILD_TESTS) @@ -27350,6 +27861,7 @@ add_executable(server_finishes_request_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -27634,6 +28146,7 @@ add_executable(server_streaming_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -27896,6 +28409,7 @@ add_executable(shutdown_finishes_calls_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -27959,6 +28473,7 @@ add_executable(shutdown_finishes_tags_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -28085,6 +28600,7 @@ add_executable(simple_delayed_request_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -28148,6 +28664,7 @@ add_executable(simple_metadata_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -28255,6 +28772,7 @@ add_executable(simple_request_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -29181,6 +29699,7 @@ add_executable(streaming_error_response_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -29955,6 +30474,7 @@ add_executable(test_core_end2end_channelz_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -30448,6 +30968,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) 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/event_engine_test_utils.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 @@ -31215,6 +31736,7 @@ add_executable(timeout_before_request_call_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -31719,6 +32241,7 @@ add_executable(trailing_metadata_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -32961,6 +33484,7 @@ add_executable(write_buffering_at_end_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc @@ -33024,6 +33548,7 @@ add_executable(write_buffering_test src/core/ext/transport/chaotic_good/server_transport.cc src/core/ext/transport/chaotic_good/settings_metadata.cc src/core/lib/transport/promise_endpoint.cc + test/core/call/batch_builder.cc test/core/end2end/cq_verifier.cc test/core/end2end/end2end_test_main.cc test/core/end2end/end2end_test_suites.cc diff --git a/Makefile b/Makefile index 273bbf87d17..27c9f67b979 100644 --- a/Makefile +++ b/Makefile @@ -1326,22 +1326,24 @@ LIBGRPC_SRC = \ 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/call_utils.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/client_call.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/filter_stack_call.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_call.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_arena_allocator.cc \ src/core/lib/transport/call_filters.cc \ diff --git a/Package.swift b/Package.swift index ae298621153..333123a6fcd 100644 --- a/Package.swift +++ b/Package.swift @@ -1656,6 +1656,8 @@ let package = Package( "src/core/lib/surface/call_log_batch.cc", "src/core/lib/surface/call_test_only.h", "src/core/lib/surface/call_trace.h", + "src/core/lib/surface/call_utils.cc", + "src/core/lib/surface/call_utils.h", "src/core/lib/surface/channel.cc", "src/core/lib/surface/channel.h", "src/core/lib/surface/channel_create.cc", @@ -1664,12 +1666,16 @@ let package = Package( "src/core/lib/surface/channel_init.h", "src/core/lib/surface/channel_stack_type.cc", "src/core/lib/surface/channel_stack_type.h", + "src/core/lib/surface/client_call.cc", + "src/core/lib/surface/client_call.h", "src/core/lib/surface/completion_queue.cc", "src/core/lib/surface/completion_queue.h", "src/core/lib/surface/completion_queue_factory.cc", "src/core/lib/surface/completion_queue_factory.h", "src/core/lib/surface/event_string.cc", "src/core/lib/surface/event_string.h", + "src/core/lib/surface/filter_stack_call.cc", + "src/core/lib/surface/filter_stack_call.h", "src/core/lib/surface/init.cc", "src/core/lib/surface/init.h", "src/core/lib/surface/init_internally.cc", @@ -1679,13 +1685,11 @@ let package = Package( "src/core/lib/surface/legacy_channel.cc", "src/core/lib/surface/legacy_channel.h", "src/core/lib/surface/metadata_array.cc", + "src/core/lib/surface/server_call.cc", + "src/core/lib/surface/server_call.h", "src/core/lib/surface/validate_metadata.cc", "src/core/lib/surface/validate_metadata.h", "src/core/lib/surface/version.cc", - "src/core/lib/surface/wait_for_cq_end_op.cc", - "src/core/lib/surface/wait_for_cq_end_op.h", - "src/core/lib/transport/batch_builder.cc", - "src/core/lib/transport/batch_builder.h", "src/core/lib/transport/bdp_estimator.cc", "src/core/lib/transport/bdp_estimator.h", "src/core/lib/transport/call_arena_allocator.cc", diff --git a/bazel/experiments.bzl b/bazel/experiments.bzl index 8dffc68bf21..ff0dc8cef75 100644 --- a/bazel/experiments.bzl +++ b/bazel/experiments.bzl @@ -32,9 +32,7 @@ EXPERIMENT_ENABLES = { "multiping": "multiping", "peer_state_based_framing": "peer_state_based_framing", "pick_first_new": "pick_first_new", - "promise_based_client_call": "event_engine_client,event_engine_listener,promise_based_client_call", - "chaotic_good": "chaotic_good,event_engine_client,event_engine_listener,promise_based_client_call", - "promise_based_inproc_transport": "event_engine_client,event_engine_listener,promise_based_client_call,promise_based_inproc_transport", + "promise_based_inproc_transport": "promise_based_inproc_transport", "rstpit": "rstpit", "schedule_cancellation_over_write": "schedule_cancellation_over_write", "server_privacy": "server_privacy", @@ -44,7 +42,6 @@ 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 = [ @@ -141,9 +138,7 @@ EXPERIMENTS = { }, "off": { "core_end2end_test": [ - "chaotic_good", "event_engine_client", - "promise_based_client_call", ], "endpoint_test": [ "tcp_frame_size_tuning", @@ -159,9 +154,6 @@ EXPERIMENTS = { "tcp_frame_size_tuning", "tcp_rcv_lowat", ], - "lame_client_test": [ - "promise_based_client_call", - ], "resource_quota_test": [ "free_large_allocator", "unconstrained_max_quota_buffer_size", diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index 36fba504a47..792d48d015d 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -1078,20 +1078,22 @@ libs: - src/core/lib/surface/call.h - src/core/lib/surface/call_test_only.h - src/core/lib/surface/call_trace.h + - src/core/lib/surface/call_utils.h - src/core/lib/surface/channel.h - src/core/lib/surface/channel_create.h - src/core/lib/surface/channel_init.h - src/core/lib/surface/channel_stack_type.h + - src/core/lib/surface/client_call.h - src/core/lib/surface/completion_queue.h - src/core/lib/surface/completion_queue_factory.h - src/core/lib/surface/event_string.h + - src/core/lib/surface/filter_stack_call.h - src/core/lib/surface/init.h - src/core/lib/surface/init_internally.h - src/core/lib/surface/lame_client.h - src/core/lib/surface/legacy_channel.h + - src/core/lib/surface/server_call.h - src/core/lib/surface/validate_metadata.h - - src/core/lib/surface/wait_for_cq_end_op.h - - src/core/lib/transport/batch_builder.h - src/core/lib/transport/bdp_estimator.h - src/core/lib/transport/call_arena_allocator.h - src/core/lib/transport/call_destination.h @@ -1891,22 +1893,24 @@ libs: - 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/call_utils.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/client_call.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/filter_stack_call.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_call.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_arena_allocator.cc - src/core/lib/transport/call_filters.cc @@ -2588,20 +2592,22 @@ libs: - src/core/lib/surface/call.h - src/core/lib/surface/call_test_only.h - src/core/lib/surface/call_trace.h + - src/core/lib/surface/call_utils.h - src/core/lib/surface/channel.h - src/core/lib/surface/channel_create.h - src/core/lib/surface/channel_init.h - src/core/lib/surface/channel_stack_type.h + - src/core/lib/surface/client_call.h - src/core/lib/surface/completion_queue.h - src/core/lib/surface/completion_queue_factory.h - src/core/lib/surface/event_string.h + - src/core/lib/surface/filter_stack_call.h - src/core/lib/surface/init.h - src/core/lib/surface/init_internally.h - src/core/lib/surface/lame_client.h - src/core/lib/surface/legacy_channel.h + - src/core/lib/surface/server_call.h - src/core/lib/surface/validate_metadata.h - - src/core/lib/surface/wait_for_cq_end_op.h - - src/core/lib/transport/batch_builder.h - src/core/lib/transport/bdp_estimator.h - src/core/lib/transport/call_arena_allocator.h - src/core/lib/transport/call_destination.h @@ -3013,22 +3019,24 @@ libs: - 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/call_utils.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/client_call.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/filter_stack_call.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_call.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_arena_allocator.cc - src/core/lib/transport/call_filters.cc @@ -4532,6 +4540,7 @@ libs: - src/core/lib/gprpp/ref_counted.h - src/core/lib/gprpp/ref_counted_ptr.h - src/core/lib/gprpp/ref_counted_string.h + - src/core/lib/gprpp/single_set_ptr.h - src/core/lib/gprpp/sorted_pack.h - src/core/lib/gprpp/status_helper.h - src/core/lib/gprpp/table.h @@ -4680,18 +4689,20 @@ libs: - src/core/lib/surface/call.h - src/core/lib/surface/call_test_only.h - src/core/lib/surface/call_trace.h + - src/core/lib/surface/call_utils.h - src/core/lib/surface/channel.h - src/core/lib/surface/channel_init.h - src/core/lib/surface/channel_stack_type.h + - src/core/lib/surface/client_call.h - src/core/lib/surface/completion_queue.h - src/core/lib/surface/completion_queue_factory.h - src/core/lib/surface/event_string.h + - src/core/lib/surface/filter_stack_call.h - src/core/lib/surface/init.h - src/core/lib/surface/init_internally.h - src/core/lib/surface/lame_client.h + - src/core/lib/surface/server_call.h - src/core/lib/surface/validate_metadata.h - - src/core/lib/surface/wait_for_cq_end_op.h - - src/core/lib/transport/batch_builder.h - src/core/lib/transport/call_arena_allocator.h - src/core/lib/transport/call_destination.h - src/core/lib/transport/call_filters.h @@ -4983,19 +4994,21 @@ libs: - 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/call_utils.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/client_call.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/filter_stack_call.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/server_call.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_arena_allocator.cc - src/core/lib/transport/call_filters.cc - src/core/lib/transport/call_final_info.cc @@ -5837,6 +5850,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -5863,6 +5877,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -6063,6 +6078,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -6089,6 +6105,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -6326,6 +6343,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -6352,6 +6370,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -6519,7 +6538,691 @@ targets: - src/core/lib/transport/parsed_metadata.cc - src/core/lib/transport/status_conversion.cc - src/core/lib/transport/timeout_encoding.cc - - test/core/transport/call_filters_test.cc + - test/core/transport/call_filters_test.cc + - 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/encode.c + - third_party/upb/upb/wire/eps_copy_input_stream.c + - third_party/upb/upb/wire/internal/decode_fast.c + - third_party/upb/upb/wire/reader.c + deps: + - gtest + - utf8_range_lib + - upb_message_lib + - absl/base:config + - absl/base:no_destructor + - absl/container:inlined_vector + - absl/functional:function_ref + - absl/hash:hash + - absl/meta:type_traits + - absl/status:statusor + - absl/utility:utility + - gpr + uses_polling: false +- name: call_finalization_test + gtest: true + build: test + language: c++ + headers: + - test/core/promise/test_context.h + src: + - test/core/channel/call_finalization_test.cc + deps: + - gtest + - grpc_test_util +- name: call_host_override_test + gtest: true + build: test + language: c++ + headers: + - src/core/ext/transport/chaotic_good/chaotic_good_transport.h + - src/core/ext/transport/chaotic_good/client/chaotic_good_connector.h + - src/core/ext/transport/chaotic_good/client_transport.h + - src/core/ext/transport/chaotic_good/frame.h + - src/core/ext/transport/chaotic_good/frame_header.h + - src/core/ext/transport/chaotic_good/server/chaotic_good_server.h + - src/core/ext/transport/chaotic_good/server_transport.h + - src/core/ext/transport/chaotic_good/settings_metadata.h + - src/core/lib/promise/event_engine_wakeup_scheduler.h + - src/core/lib/promise/inter_activity_latch.h + - src/core/lib/promise/inter_activity_pipe.h + - src/core/lib/promise/mpsc.h + - src/core/lib/promise/switch.h + - src/core/lib/promise/wait_for_callback.h + - src/core/lib/promise/wait_set.h + - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h + - test/core/end2end/cq_verifier.h + - test/core/end2end/end2end_tests.h + - test/core/end2end/fixtures/h2_oauth2_common.h + - test/core/end2end/fixtures/h2_ssl_cred_reload_fixture.h + - test/core/end2end/fixtures/h2_ssl_tls_common.h + - test/core/end2end/fixtures/h2_tls_common.h + - test/core/end2end/fixtures/http_proxy_fixture.h + - test/core/end2end/fixtures/inproc_fixture.h + - test/core/end2end/fixtures/local_util.h + - test/core/end2end/fixtures/proxy.h + - test/core/end2end/fixtures/secure_fixture.h + - test/core/end2end/fixtures/sockpair_fixture.h + - test/core/end2end/tests/cancel_test_helpers.h + - test/core/event_engine/event_engine_test_utils.h + - test/core/test_util/fake_stats_plugin.h + - test/core/test_util/test_lb_policies.h + src: + - src/core/ext/transport/chaotic_good/chaotic_good_transport.cc + - src/core/ext/transport/chaotic_good/client/chaotic_good_connector.cc + - src/core/ext/transport/chaotic_good/client_transport.cc + - src/core/ext/transport/chaotic_good/frame.cc + - src/core/ext/transport/chaotic_good/frame_header.cc + - src/core/ext/transport/chaotic_good/server/chaotic_good_server.cc + - src/core/ext/transport/chaotic_good/server_transport.cc + - src/core/ext/transport/chaotic_good/settings_metadata.cc + - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc + - test/core/end2end/cq_verifier.cc + - test/core/end2end/end2end_test_main.cc + - test/core/end2end/end2end_test_suites.cc + - test/core/end2end/end2end_tests.cc + - test/core/end2end/fixtures/http_proxy_fixture.cc + - test/core/end2end/fixtures/local_util.cc + - test/core/end2end/fixtures/proxy.cc + - test/core/end2end/tests/call_host_override.cc + - test/core/event_engine/event_engine_test_utils.cc + - test/core/test_util/fake_stats_plugin.cc + - test/core/test_util/test_lb_policies.cc + deps: + - gtest + - grpc_authorization_provider + - grpc_unsecure + - grpc_test_util +- name: call_tracer_test + gtest: true + build: test + language: c++ + headers: + - test/core/test_util/fake_stats_plugin.h + src: + - test/core/telemetry/call_tracer_test.cc + - test/core/test_util/fake_stats_plugin.cc + deps: + - gtest + - grpc_test_util + uses_polling: false +- name: call_utils_test + gtest: true + build: test + language: c++ + headers: + - src/core/channelz/channel_trace.h + - src/core/channelz/channelz.h + - src/core/channelz/channelz_registry.h + - src/core/ext/upb-gen/google/protobuf/any.upb.h + - src/core/ext/upb-gen/google/protobuf/any.upb_minitable.h + - src/core/ext/upb-gen/google/rpc/status.upb.h + - src/core/ext/upb-gen/google/rpc/status.upb_minitable.h + - src/core/ext/upb-gen/src/proto/grpc/gcp/altscontext.upb.h + - src/core/ext/upb-gen/src/proto/grpc/gcp/altscontext.upb_minitable.h + - src/core/ext/upb-gen/src/proto/grpc/gcp/handshaker.upb.h + - src/core/ext/upb-gen/src/proto/grpc/gcp/handshaker.upb_minitable.h + - src/core/ext/upb-gen/src/proto/grpc/gcp/transport_security_common.upb.h + - src/core/ext/upb-gen/src/proto/grpc/gcp/transport_security_common.upb_minitable.h + - src/core/handshaker/handshaker_factory.h + - src/core/handshaker/handshaker_registry.h + - src/core/handshaker/proxy_mapper.h + - src/core/handshaker/proxy_mapper_registry.h + - src/core/lib/address_utils/parse_address.h + - src/core/lib/address_utils/sockaddr_utils.h + - src/core/lib/avl/avl.h + - src/core/lib/backoff/backoff.h + - src/core/lib/channel/call_finalization.h + - src/core/lib/channel/channel_args.h + - src/core/lib/channel/channel_args_preconditioning.h + - src/core/lib/channel/channel_fwd.h + - src/core/lib/channel/channel_stack.h + - src/core/lib/channel/channel_stack_builder.h + - src/core/lib/channel/channel_stack_builder_impl.h + - src/core/lib/channel/channel_stack_trace.h + - src/core/lib/channel/connected_channel.h + - src/core/lib/channel/promise_based_filter.h + - src/core/lib/channel/status_util.h + - src/core/lib/compression/compression_internal.h + - src/core/lib/compression/message_compress.h + - src/core/lib/config/core_configuration.h + - src/core/lib/debug/event_log.h + - src/core/lib/debug/trace.h + - src/core/lib/event_engine/ares_resolver.h + - src/core/lib/event_engine/cf_engine/cf_engine.h + - src/core/lib/event_engine/cf_engine/cfstream_endpoint.h + - src/core/lib/event_engine/cf_engine/cftype_unique_ref.h + - src/core/lib/event_engine/cf_engine/dns_service_resolver.h + - src/core/lib/event_engine/channel_args_endpoint_config.h + - src/core/lib/event_engine/common_closures.h + - src/core/lib/event_engine/default_event_engine.h + - src/core/lib/event_engine/default_event_engine_factory.h + - src/core/lib/event_engine/event_engine_context.h + - src/core/lib/event_engine/extensions/can_track_errors.h + - src/core/lib/event_engine/extensions/chaotic_good_extension.h + - src/core/lib/event_engine/extensions/supports_fd.h + - src/core/lib/event_engine/extensions/tcp_trace.h + - src/core/lib/event_engine/forkable.h + - src/core/lib/event_engine/grpc_polled_fd.h + - src/core/lib/event_engine/handle_containers.h + - src/core/lib/event_engine/memory_allocator_factory.h + - src/core/lib/event_engine/nameser.h + - src/core/lib/event_engine/poller.h + - src/core/lib/event_engine/posix.h + - src/core/lib/event_engine/posix_engine/ev_epoll1_linux.h + - src/core/lib/event_engine/posix_engine/ev_poll_posix.h + - src/core/lib/event_engine/posix_engine/event_poller.h + - src/core/lib/event_engine/posix_engine/event_poller_posix_default.h + - src/core/lib/event_engine/posix_engine/grpc_polled_fd_posix.h + - src/core/lib/event_engine/posix_engine/internal_errqueue.h + - src/core/lib/event_engine/posix_engine/lockfree_event.h + - src/core/lib/event_engine/posix_engine/native_posix_dns_resolver.h + - src/core/lib/event_engine/posix_engine/posix_endpoint.h + - src/core/lib/event_engine/posix_engine/posix_engine.h + - src/core/lib/event_engine/posix_engine/posix_engine_closure.h + - src/core/lib/event_engine/posix_engine/posix_engine_listener.h + - src/core/lib/event_engine/posix_engine/posix_engine_listener_utils.h + - src/core/lib/event_engine/posix_engine/tcp_socket_utils.h + - src/core/lib/event_engine/posix_engine/timer.h + - src/core/lib/event_engine/posix_engine/timer_heap.h + - src/core/lib/event_engine/posix_engine/timer_manager.h + - src/core/lib/event_engine/posix_engine/traced_buffer_list.h + - src/core/lib/event_engine/posix_engine/wakeup_fd_eventfd.h + - src/core/lib/event_engine/posix_engine/wakeup_fd_pipe.h + - src/core/lib/event_engine/posix_engine/wakeup_fd_posix.h + - src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.h + - src/core/lib/event_engine/query_extensions.h + - src/core/lib/event_engine/ref_counted_dns_resolver_interface.h + - src/core/lib/event_engine/resolved_address_internal.h + - src/core/lib/event_engine/shim.h + - src/core/lib/event_engine/tcp_socket_utils.h + - src/core/lib/event_engine/thread_pool/thread_count.h + - src/core/lib/event_engine/thread_pool/thread_pool.h + - src/core/lib/event_engine/thread_pool/work_stealing_thread_pool.h + - src/core/lib/event_engine/thready_event_engine/thready_event_engine.h + - src/core/lib/event_engine/time_util.h + - src/core/lib/event_engine/trace.h + - src/core/lib/event_engine/utils.h + - src/core/lib/event_engine/windows/grpc_polled_fd_windows.h + - src/core/lib/event_engine/windows/iocp.h + - src/core/lib/event_engine/windows/native_windows_dns_resolver.h + - src/core/lib/event_engine/windows/win_socket.h + - src/core/lib/event_engine/windows/windows_endpoint.h + - src/core/lib/event_engine/windows/windows_engine.h + - src/core/lib/event_engine/windows/windows_listener.h + - src/core/lib/event_engine/work_queue/basic_work_queue.h + - src/core/lib/event_engine/work_queue/work_queue.h + - src/core/lib/experiments/config.h + - src/core/lib/experiments/experiments.h + - 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/load_file.h + - src/core/lib/gprpp/manual_constructor.h + - src/core/lib/gprpp/match.h + - src/core/lib/gprpp/notification.h + - src/core/lib/gprpp/orphanable.h + - src/core/lib/gprpp/overload.h + - src/core/lib/gprpp/packed_table.h + - src/core/lib/gprpp/per_cpu.h + - src/core/lib/gprpp/ref_counted.h + - src/core/lib/gprpp/ref_counted_ptr.h + - src/core/lib/gprpp/ref_counted_string.h + - src/core/lib/gprpp/single_set_ptr.h + - src/core/lib/gprpp/sorted_pack.h + - src/core/lib/gprpp/status_helper.h + - src/core/lib/gprpp/table.h + - src/core/lib/gprpp/time.h + - src/core/lib/gprpp/time_averaged_stats.h + - src/core/lib/gprpp/type_list.h + - src/core/lib/gprpp/unique_type_name.h + - src/core/lib/gprpp/validation_errors.h + - src/core/lib/gprpp/work_serializer.h + - src/core/lib/iomgr/block_annotate.h + - src/core/lib/iomgr/buffer_list.h + - src/core/lib/iomgr/call_combiner.h + - src/core/lib/iomgr/cfstream_handle.h + - src/core/lib/iomgr/closure.h + - src/core/lib/iomgr/combiner.h + - src/core/lib/iomgr/dynamic_annotations.h + - src/core/lib/iomgr/endpoint.h + - src/core/lib/iomgr/endpoint_cfstream.h + - src/core/lib/iomgr/endpoint_pair.h + - src/core/lib/iomgr/error.h + - src/core/lib/iomgr/error_cfstream.h + - src/core/lib/iomgr/ev_apple.h + - src/core/lib/iomgr/ev_epoll1_linux.h + - src/core/lib/iomgr/ev_poll_posix.h + - src/core/lib/iomgr/ev_posix.h + - src/core/lib/iomgr/event_engine_shims/closure.h + - src/core/lib/iomgr/event_engine_shims/endpoint.h + - src/core/lib/iomgr/event_engine_shims/tcp_client.h + - src/core/lib/iomgr/exec_ctx.h + - src/core/lib/iomgr/executor.h + - src/core/lib/iomgr/gethostname.h + - src/core/lib/iomgr/grpc_if_nametoindex.h + - src/core/lib/iomgr/internal_errqueue.h + - src/core/lib/iomgr/iocp_windows.h + - src/core/lib/iomgr/iomgr.h + - src/core/lib/iomgr/iomgr_fwd.h + - src/core/lib/iomgr/iomgr_internal.h + - src/core/lib/iomgr/lockfree_event.h + - src/core/lib/iomgr/nameser.h + - src/core/lib/iomgr/polling_entity.h + - src/core/lib/iomgr/pollset.h + - src/core/lib/iomgr/pollset_set.h + - src/core/lib/iomgr/pollset_set_windows.h + - src/core/lib/iomgr/pollset_windows.h + - src/core/lib/iomgr/port.h + - src/core/lib/iomgr/python_util.h + - src/core/lib/iomgr/resolve_address.h + - src/core/lib/iomgr/resolve_address_impl.h + - src/core/lib/iomgr/resolve_address_posix.h + - src/core/lib/iomgr/resolve_address_windows.h + - src/core/lib/iomgr/resolved_address.h + - src/core/lib/iomgr/sockaddr.h + - src/core/lib/iomgr/sockaddr_posix.h + - src/core/lib/iomgr/sockaddr_windows.h + - src/core/lib/iomgr/socket_factory_posix.h + - src/core/lib/iomgr/socket_mutator.h + - src/core/lib/iomgr/socket_utils.h + - src/core/lib/iomgr/socket_utils_posix.h + - src/core/lib/iomgr/socket_windows.h + - src/core/lib/iomgr/systemd_utils.h + - src/core/lib/iomgr/tcp_client.h + - src/core/lib/iomgr/tcp_client_posix.h + - src/core/lib/iomgr/tcp_posix.h + - src/core/lib/iomgr/tcp_server.h + - src/core/lib/iomgr/tcp_server_utils_posix.h + - src/core/lib/iomgr/tcp_windows.h + - src/core/lib/iomgr/timer.h + - src/core/lib/iomgr/timer_generic.h + - src/core/lib/iomgr/timer_heap.h + - src/core/lib/iomgr/timer_manager.h + - src/core/lib/iomgr/unix_sockets_posix.h + - src/core/lib/iomgr/vsock.h + - src/core/lib/iomgr/wakeup_fd_pipe.h + - src/core/lib/iomgr/wakeup_fd_posix.h + - src/core/lib/promise/activity.h + - src/core/lib/promise/all_ok.h + - src/core/lib/promise/arena_promise.h + - src/core/lib/promise/cancel_callback.h + - src/core/lib/promise/context.h + - src/core/lib/promise/detail/basic_seq.h + - src/core/lib/promise/detail/join_state.h + - src/core/lib/promise/detail/promise_factory.h + - src/core/lib/promise/detail/promise_like.h + - src/core/lib/promise/detail/seq_state.h + - src/core/lib/promise/detail/status.h + - src/core/lib/promise/exec_ctx_wakeup_scheduler.h + - src/core/lib/promise/for_each.h + - src/core/lib/promise/if.h + - src/core/lib/promise/interceptor_list.h + - src/core/lib/promise/latch.h + - src/core/lib/promise/loop.h + - src/core/lib/promise/map.h + - 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 + - src/core/lib/promise/status_flag.h + - src/core/lib/promise/trace.h + - src/core/lib/promise/try_seq.h + - src/core/lib/resource_quota/api.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/security/certificate_provider/certificate_provider_factory.h + - src/core/lib/security/certificate_provider/certificate_provider_registry.h + - src/core/lib/security/credentials/alts/check_gcp_environment.h + - src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h + - src/core/lib/security/credentials/channel_creds_registry.h + - src/core/lib/slice/percent_encoding.h + - src/core/lib/slice/slice.h + - src/core/lib/slice/slice_buffer.h + - src/core/lib/slice/slice_internal.h + - src/core/lib/slice/slice_refcount.h + - src/core/lib/slice/slice_string_helpers.h + - src/core/lib/surface/api_trace.h + - src/core/lib/surface/call.h + - src/core/lib/surface/call_test_only.h + - src/core/lib/surface/call_trace.h + - src/core/lib/surface/call_utils.h + - src/core/lib/surface/channel.h + - src/core/lib/surface/channel_init.h + - src/core/lib/surface/channel_stack_type.h + - src/core/lib/surface/client_call.h + - src/core/lib/surface/completion_queue.h + - src/core/lib/surface/completion_queue_factory.h + - src/core/lib/surface/event_string.h + - src/core/lib/surface/filter_stack_call.h + - src/core/lib/surface/init.h + - src/core/lib/surface/init_internally.h + - src/core/lib/surface/lame_client.h + - src/core/lib/surface/server_call.h + - src/core/lib/surface/validate_metadata.h + - src/core/lib/transport/call_arena_allocator.h + - src/core/lib/transport/call_destination.h + - src/core/lib/transport/call_filters.h + - src/core/lib/transport/call_final_info.h + - src/core/lib/transport/call_spine.h + - src/core/lib/transport/connectivity_state.h + - src/core/lib/transport/custom_metadata.h + - src/core/lib/transport/error_utils.h + - src/core/lib/transport/http2_errors.h + - src/core/lib/transport/interception_chain.h + - src/core/lib/transport/message.h + - src/core/lib/transport/metadata.h + - src/core/lib/transport/metadata_batch.h + - src/core/lib/transport/metadata_compression_traits.h + - src/core/lib/transport/parsed_metadata.h + - src/core/lib/transport/simple_slice_based_metadata.h + - src/core/lib/transport/status_conversion.h + - src/core/lib/transport/timeout_encoding.h + - src/core/lib/transport/transport.h + - src/core/lib/transport/transport_fwd.h + - src/core/lib/uri/uri_parser.h + - src/core/load_balancing/backend_metric_data.h + - src/core/load_balancing/lb_policy.h + - src/core/load_balancing/lb_policy_factory.h + - src/core/load_balancing/lb_policy_registry.h + - src/core/load_balancing/subchannel_interface.h + - src/core/resolver/endpoint_addresses.h + - src/core/resolver/resolver.h + - src/core/resolver/resolver_factory.h + - src/core/resolver/resolver_registry.h + - src/core/resolver/server_address.h + - src/core/server/server_interface.h + - src/core/service_config/service_config.h + - src/core/service_config/service_config_call_data.h + - src/core/service_config/service_config_parser.h + - src/core/telemetry/call_tracer.h + - src/core/telemetry/histogram_view.h + - src/core/telemetry/metrics.h + - src/core/telemetry/stats.h + - src/core/telemetry/stats_data.h + - src/core/telemetry/tcp_tracer.h + - src/core/tsi/alts/handshaker/transport_security_common_api.h + - src/core/util/json/json.h + - src/core/util/json/json_args.h + - src/core/util/json/json_writer.h + - src/core/util/spinlock.h + - third_party/upb/upb/generated_code_support.h + - third_party/upb/upb/mini_descriptor/build_enum.h + - third_party/upb/upb/mini_descriptor/decode.h + - third_party/upb/upb/mini_descriptor/internal/base92.h + - third_party/upb/upb/mini_descriptor/internal/decoder.h + - third_party/upb/upb/mini_descriptor/internal/encode.h + - third_party/upb/upb/mini_descriptor/internal/encode.hpp + - third_party/upb/upb/mini_descriptor/internal/modifiers.h + - third_party/upb/upb/mini_descriptor/internal/wire_constants.h + - third_party/upb/upb/mini_descriptor/link.h + - third_party/upb/upb/wire/decode.h + - third_party/upb/upb/wire/encode.h + - third_party/upb/upb/wire/eps_copy_input_stream.h + - third_party/upb/upb/wire/internal/constants.h + - third_party/upb/upb/wire/internal/decode_fast.h + - third_party/upb/upb/wire/internal/decoder.h + - third_party/upb/upb/wire/internal/reader.h + - third_party/upb/upb/wire/reader.h + - third_party/upb/upb/wire/types.h + src: + - src/core/channelz/channel_trace.cc + - src/core/channelz/channelz.cc + - src/core/channelz/channelz_registry.cc + - src/core/ext/upb-gen/google/protobuf/any.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/handshaker/handshaker_registry.cc + - src/core/handshaker/proxy_mapper_registry.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/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/connected_channel.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/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/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 + - 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/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/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/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/security/certificate_provider/certificate_provider_registry.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/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/call_utils.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/client_call.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/filter_stack_call.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/server_call.cc + - src/core/lib/surface/validate_metadata.cc + - src/core/lib/surface/version.cc + - src/core/lib/transport/call_arena_allocator.cc + - src/core/lib/transport/call_filters.cc + - src/core/lib/transport/call_final_info.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/interception_chain.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/telemetry/call_tracer.cc + - src/core/telemetry/histogram_view.cc + - src/core/telemetry/metrics.cc + - src/core/telemetry/stats.cc + - src/core/telemetry/stats_data.cc + - src/core/tsi/alts/handshaker/transport_security_common_api.cc + - src/core/util/json/json_writer.cc + - test/core/call/call_utils_test.cc - 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 @@ -6534,103 +7237,21 @@ targets: - gtest - utf8_range_lib - upb_message_lib + - z - absl/base:config - absl/base:no_destructor + - absl/cleanup:cleanup + - absl/container:flat_hash_map - absl/container:inlined_vector - absl/functional:function_ref - absl/hash:hash - absl/meta:type_traits - absl/status:statusor + - absl/types:span - absl/utility:utility + - cares - gpr - uses_polling: false -- name: call_finalization_test - gtest: true - build: test - language: c++ - headers: - - test/core/promise/test_context.h - src: - - test/core/channel/call_finalization_test.cc - deps: - - gtest - - grpc_test_util -- name: call_host_override_test - gtest: true - build: test - language: c++ - headers: - - src/core/ext/transport/chaotic_good/chaotic_good_transport.h - - src/core/ext/transport/chaotic_good/client/chaotic_good_connector.h - - src/core/ext/transport/chaotic_good/client_transport.h - - src/core/ext/transport/chaotic_good/frame.h - - src/core/ext/transport/chaotic_good/frame_header.h - - src/core/ext/transport/chaotic_good/server/chaotic_good_server.h - - src/core/ext/transport/chaotic_good/server_transport.h - - src/core/ext/transport/chaotic_good/settings_metadata.h - - src/core/lib/promise/event_engine_wakeup_scheduler.h - - src/core/lib/promise/inter_activity_latch.h - - src/core/lib/promise/inter_activity_pipe.h - - src/core/lib/promise/mpsc.h - - src/core/lib/promise/switch.h - - src/core/lib/promise/wait_for_callback.h - - src/core/lib/promise/wait_set.h - - src/core/lib/transport/promise_endpoint.h - - test/core/end2end/cq_verifier.h - - test/core/end2end/end2end_tests.h - - test/core/end2end/fixtures/h2_oauth2_common.h - - test/core/end2end/fixtures/h2_ssl_cred_reload_fixture.h - - test/core/end2end/fixtures/h2_ssl_tls_common.h - - test/core/end2end/fixtures/h2_tls_common.h - - test/core/end2end/fixtures/http_proxy_fixture.h - - test/core/end2end/fixtures/inproc_fixture.h - - test/core/end2end/fixtures/local_util.h - - test/core/end2end/fixtures/proxy.h - - test/core/end2end/fixtures/secure_fixture.h - - test/core/end2end/fixtures/sockpair_fixture.h - - test/core/end2end/tests/cancel_test_helpers.h - - test/core/event_engine/event_engine_test_utils.h - - test/core/test_util/fake_stats_plugin.h - - test/core/test_util/test_lb_policies.h - src: - - src/core/ext/transport/chaotic_good/chaotic_good_transport.cc - - src/core/ext/transport/chaotic_good/client/chaotic_good_connector.cc - - src/core/ext/transport/chaotic_good/client_transport.cc - - src/core/ext/transport/chaotic_good/frame.cc - - src/core/ext/transport/chaotic_good/frame_header.cc - - src/core/ext/transport/chaotic_good/server/chaotic_good_server.cc - - src/core/ext/transport/chaotic_good/server_transport.cc - - src/core/ext/transport/chaotic_good/settings_metadata.cc - - src/core/lib/transport/promise_endpoint.cc - - test/core/end2end/cq_verifier.cc - - test/core/end2end/end2end_test_main.cc - - test/core/end2end/end2end_test_suites.cc - - test/core/end2end/end2end_tests.cc - - test/core/end2end/fixtures/http_proxy_fixture.cc - - test/core/end2end/fixtures/local_util.cc - - test/core/end2end/fixtures/proxy.cc - - test/core/end2end/tests/call_host_override.cc - - test/core/event_engine/event_engine_test_utils.cc - - test/core/test_util/fake_stats_plugin.cc - - test/core/test_util/test_lb_policies.cc - deps: - - gtest - - grpc_authorization_provider - - grpc_unsecure - - grpc_test_util -- name: call_tracer_test - gtest: true - build: test - language: c++ - headers: - - test/core/test_util/fake_stats_plugin.h - src: - - test/core/telemetry/call_tracer_test.cc - - test/core/test_util/fake_stats_plugin.cc - deps: - - gtest - - grpc_test_util - uses_polling: false + - address_sorting - name: cancel_after_accept_test gtest: true build: test @@ -6652,6 +7273,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -6678,6 +7300,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -6715,6 +7338,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -6741,6 +7365,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -6778,6 +7403,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -6804,6 +7430,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -6841,6 +7468,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -6867,6 +7495,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -6921,6 +7550,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -6947,6 +7577,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -7109,6 +7740,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -7135,6 +7767,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -7172,6 +7805,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -7198,6 +7832,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -7966,6 +8601,33 @@ targets: - protobuf - grpc_test_util uses_polling: false +- name: client_call_test + gtest: true + build: test + language: c++ + headers: + - test/core/call/batch_builder.h + - test/core/call/yodel/yodel_test.h + - test/core/end2end/cq_verifier.h + - test/core/event_engine/event_engine_test_utils.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/batch_builder.cc + - test/core/call/client_call_test.cc + - test/core/call/yodel/test_main.cc + - test/core/call/yodel/yodel_test.cc + - test/core/end2end/cq_verifier.cc + - test/core/event_engine/event_engine_test_utils.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_callback_end2end_test gtest: true build: test @@ -8001,12 +8663,14 @@ targets: language: c++ headers: - test/core/call/yodel/yodel_test.h + - test/core/event_engine/event_engine_test_utils.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/event_engine_test_utils.cc - test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc deps: - gtest @@ -8128,6 +8792,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -8154,6 +8819,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -8302,6 +8968,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -8328,6 +8995,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -8371,12 +9039,14 @@ targets: language: c++ headers: - test/core/call/yodel/yodel_test.h + - test/core/event_engine/event_engine_test_utils.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/event_engine_test_utils.cc - test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc deps: - gtest @@ -8462,6 +9132,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -8488,6 +9159,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -8631,6 +9303,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -8657,6 +9330,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -8731,6 +9405,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -8757,6 +9432,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -8881,6 +9557,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -8907,6 +9584,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -9664,6 +10342,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -9690,6 +10369,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -9727,6 +10407,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -9753,6 +10434,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -9808,6 +10490,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -9834,6 +10517,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -10341,6 +11025,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -10367,6 +11052,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -10536,6 +11222,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -10562,6 +11249,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -10947,6 +11635,7 @@ targets: build: test language: c++ headers: + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/data/ssl_test_data.h - test/core/end2end/end2end_tests.h @@ -10961,6 +11650,7 @@ targets: - test/core/end2end/tests/cancel_test_helpers.h - test/core/event_engine/event_engine_test_utils.h src: + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/data/client_certs.cc - test/core/end2end/data/server1_cert.cc @@ -11093,6 +11783,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -11119,6 +11810,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -11287,6 +11979,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -11313,6 +12006,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -11374,6 +12068,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -11400,6 +12095,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -11552,12 +12248,14 @@ targets: language: c++ headers: - test/core/call/yodel/yodel_test.h + - test/core/event_engine/event_engine_test_utils.h - test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.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/event_engine_test_utils.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 @@ -11780,6 +12478,7 @@ targets: - src/core/lib/gprpp/ref_counted.h - src/core/lib/gprpp/ref_counted_ptr.h - src/core/lib/gprpp/ref_counted_string.h + - src/core/lib/gprpp/single_set_ptr.h - src/core/lib/gprpp/sorted_pack.h - src/core/lib/gprpp/status_helper.h - src/core/lib/gprpp/table.h @@ -11905,18 +12604,20 @@ targets: - src/core/lib/surface/call.h - src/core/lib/surface/call_test_only.h - src/core/lib/surface/call_trace.h + - src/core/lib/surface/call_utils.h - src/core/lib/surface/channel.h - src/core/lib/surface/channel_init.h - src/core/lib/surface/channel_stack_type.h + - src/core/lib/surface/client_call.h - src/core/lib/surface/completion_queue.h - src/core/lib/surface/completion_queue_factory.h - src/core/lib/surface/event_string.h + - src/core/lib/surface/filter_stack_call.h - src/core/lib/surface/init.h - src/core/lib/surface/init_internally.h - src/core/lib/surface/lame_client.h + - src/core/lib/surface/server_call.h - src/core/lib/surface/validate_metadata.h - - src/core/lib/surface/wait_for_cq_end_op.h - - src/core/lib/transport/batch_builder.h - src/core/lib/transport/call_arena_allocator.h - src/core/lib/transport/call_destination.h - src/core/lib/transport/call_filters.h @@ -12177,19 +12878,21 @@ targets: - 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/call_utils.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/client_call.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/filter_stack_call.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/server_call.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_arena_allocator.cc - src/core/lib/transport/call_filters.cc - src/core/lib/transport/call_final_info.cc @@ -12447,6 +13150,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -12473,6 +13177,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -12647,6 +13352,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -12673,6 +13379,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -12722,6 +13429,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -12748,6 +13456,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -12840,12 +13549,14 @@ targets: language: c++ headers: - test/core/call/yodel/yodel_test.h + - test/core/event_engine/event_engine_test_utils.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/event_engine_test_utils.cc - test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc deps: - gtest @@ -13152,6 +13863,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -13178,6 +13890,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -13215,6 +13928,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -13241,6 +13955,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -13278,6 +13993,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -13304,6 +14020,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -13341,6 +14058,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -13367,6 +14085,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -13624,6 +14343,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -13650,6 +14370,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -13699,6 +14420,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -13725,6 +14447,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -13762,6 +14485,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -13788,6 +14512,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -14132,6 +14857,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -14158,6 +14884,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -14387,6 +15114,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -14413,6 +15141,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -14480,6 +15209,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -14506,6 +15236,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -14900,6 +15631,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -14926,6 +15658,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -15157,6 +15890,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -15183,6 +15917,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -15234,6 +15969,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -15260,6 +15996,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -15297,6 +16034,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -15323,6 +16061,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -15508,6 +16247,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -15534,6 +16274,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -15582,6 +16323,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -15608,6 +16350,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -15645,6 +16388,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -15671,6 +16415,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -15708,6 +16453,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -15734,6 +16480,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -15771,6 +16518,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -15797,6 +16545,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -15834,6 +16583,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -15860,6 +16610,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -15897,6 +16648,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -15923,6 +16675,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -15960,6 +16713,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -15986,6 +16740,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -16023,6 +16778,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -16049,6 +16805,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -16086,6 +16843,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -16112,6 +16870,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -16149,6 +16908,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -16175,6 +16935,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -16212,6 +16973,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -16238,6 +17000,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -16275,6 +17038,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -16301,6 +17065,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -16338,6 +17103,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -16364,6 +17130,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -16401,6 +17168,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -16427,6 +17195,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -16464,6 +17233,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -16490,6 +17260,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -16527,6 +17298,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -16553,6 +17325,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -16590,6 +17363,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -16616,6 +17390,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -16653,6 +17428,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -16679,6 +17455,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -16716,6 +17493,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -16742,6 +17520,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -16779,6 +17558,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -16805,6 +17585,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -16842,6 +17623,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -16868,6 +17650,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -16905,6 +17688,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -16931,6 +17715,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -16968,6 +17753,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -16994,6 +17780,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -17042,6 +17829,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -17068,6 +17856,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -17105,6 +17894,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -17131,6 +17921,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -17168,6 +17959,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -17194,6 +17986,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -17231,6 +18024,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -17257,6 +18051,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -17305,6 +18100,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -17331,6 +18127,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -17368,6 +18165,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -17394,6 +18192,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -17431,6 +18230,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -17457,6 +18257,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -17494,6 +18295,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -17520,6 +18322,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -17557,6 +18360,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -17583,6 +18387,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -17620,6 +18425,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -17646,6 +18452,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -17683,6 +18490,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -17709,6 +18517,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -18010,6 +18819,33 @@ targets: - linux - posix - mac +- name: server_call_test + gtest: true + build: test + language: c++ + headers: + - test/core/call/batch_builder.h + - test/core/call/yodel/yodel_test.h + - test/core/end2end/cq_verifier.h + - test/core/event_engine/event_engine_test_utils.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/batch_builder.cc + - test/core/call/server_call_test.cc + - test/core/call/yodel/test_main.cc + - test/core/call/yodel/yodel_test.cc + - test/core/end2end/cq_verifier.cc + - test/core/event_engine/event_engine_test_utils.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: server_call_tracer_factory_test gtest: true build: test @@ -18087,6 +18923,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -18113,6 +18950,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -18236,6 +19074,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -18262,6 +19101,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -18365,6 +19205,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -18391,6 +19232,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -18428,6 +19270,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -18454,6 +19297,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -18506,6 +19350,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -18532,6 +19377,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -18569,6 +19415,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -18595,6 +19442,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -18646,6 +19494,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -18672,6 +19521,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -19001,6 +19851,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -19027,6 +19878,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -19363,6 +20215,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -19389,6 +20242,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -19623,6 +20477,7 @@ targets: - 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/event_engine_test_utils.h - test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h - test/core/transport/test_suite/transport_test.h src: @@ -19635,6 +20490,7 @@ targets: - 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/event_engine_test_utils.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 @@ -19908,6 +20764,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -19934,6 +20791,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -20125,6 +20983,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -20151,6 +21010,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -20819,6 +21679,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -20845,6 +21706,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc @@ -20882,6 +21744,7 @@ targets: - src/core/lib/promise/wait_for_callback.h - src/core/lib/promise/wait_set.h - src/core/lib/transport/promise_endpoint.h + - test/core/call/batch_builder.h - test/core/end2end/cq_verifier.h - test/core/end2end/end2end_tests.h - test/core/end2end/fixtures/h2_oauth2_common.h @@ -20908,6 +21771,7 @@ targets: - src/core/ext/transport/chaotic_good/server_transport.cc - src/core/ext/transport/chaotic_good/settings_metadata.cc - src/core/lib/transport/promise_endpoint.cc + - test/core/call/batch_builder.cc - test/core/end2end/cq_verifier.cc - test/core/end2end/end2end_test_main.cc - test/core/end2end/end2end_test_suites.cc diff --git a/config.m4 b/config.m4 index 42a31912190..2b0ac51b569 100644 --- a/config.m4 +++ b/config.m4 @@ -701,22 +701,24 @@ if test "$PHP_GRPC" != "no"; then 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/call_utils.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/client_call.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/filter_stack_call.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_call.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_arena_allocator.cc \ src/core/lib/transport/call_filters.cc \ diff --git a/config.w32 b/config.w32 index 6007bd959b0..86e7fb6ddba 100644 --- a/config.w32 +++ b/config.w32 @@ -666,22 +666,24 @@ if (PHP_GRPC != "no") { "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\\call_utils.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\\client_call.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\\filter_stack_call.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_call.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_arena_allocator.cc " + "src\\core\\lib\\transport\\call_filters.cc " + diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index be82baae8c5..5a3f0443b4b 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -1176,20 +1176,22 @@ Pod::Spec.new do |s| 'src/core/lib/surface/call.h', 'src/core/lib/surface/call_test_only.h', 'src/core/lib/surface/call_trace.h', + 'src/core/lib/surface/call_utils.h', 'src/core/lib/surface/channel.h', 'src/core/lib/surface/channel_create.h', 'src/core/lib/surface/channel_init.h', 'src/core/lib/surface/channel_stack_type.h', + 'src/core/lib/surface/client_call.h', 'src/core/lib/surface/completion_queue.h', 'src/core/lib/surface/completion_queue_factory.h', 'src/core/lib/surface/event_string.h', + 'src/core/lib/surface/filter_stack_call.h', 'src/core/lib/surface/init.h', 'src/core/lib/surface/init_internally.h', 'src/core/lib/surface/lame_client.h', 'src/core/lib/surface/legacy_channel.h', + 'src/core/lib/surface/server_call.h', 'src/core/lib/surface/validate_metadata.h', - 'src/core/lib/surface/wait_for_cq_end_op.h', - 'src/core/lib/transport/batch_builder.h', 'src/core/lib/transport/bdp_estimator.h', 'src/core/lib/transport/call_arena_allocator.h', 'src/core/lib/transport/call_destination.h', @@ -2450,20 +2452,22 @@ Pod::Spec.new do |s| 'src/core/lib/surface/call.h', 'src/core/lib/surface/call_test_only.h', 'src/core/lib/surface/call_trace.h', + 'src/core/lib/surface/call_utils.h', 'src/core/lib/surface/channel.h', 'src/core/lib/surface/channel_create.h', 'src/core/lib/surface/channel_init.h', 'src/core/lib/surface/channel_stack_type.h', + 'src/core/lib/surface/client_call.h', 'src/core/lib/surface/completion_queue.h', 'src/core/lib/surface/completion_queue_factory.h', 'src/core/lib/surface/event_string.h', + 'src/core/lib/surface/filter_stack_call.h', 'src/core/lib/surface/init.h', 'src/core/lib/surface/init_internally.h', 'src/core/lib/surface/lame_client.h', 'src/core/lib/surface/legacy_channel.h', + 'src/core/lib/surface/server_call.h', 'src/core/lib/surface/validate_metadata.h', - 'src/core/lib/surface/wait_for_cq_end_op.h', - 'src/core/lib/transport/batch_builder.h', 'src/core/lib/transport/bdp_estimator.h', 'src/core/lib/transport/call_arena_allocator.h', 'src/core/lib/transport/call_destination.h', diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 274bcb13549..6e6c7a57244 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -1771,6 +1771,8 @@ Pod::Spec.new do |s| 'src/core/lib/surface/call_log_batch.cc', 'src/core/lib/surface/call_test_only.h', 'src/core/lib/surface/call_trace.h', + 'src/core/lib/surface/call_utils.cc', + 'src/core/lib/surface/call_utils.h', 'src/core/lib/surface/channel.cc', 'src/core/lib/surface/channel.h', 'src/core/lib/surface/channel_create.cc', @@ -1779,12 +1781,16 @@ Pod::Spec.new do |s| 'src/core/lib/surface/channel_init.h', 'src/core/lib/surface/channel_stack_type.cc', 'src/core/lib/surface/channel_stack_type.h', + 'src/core/lib/surface/client_call.cc', + 'src/core/lib/surface/client_call.h', 'src/core/lib/surface/completion_queue.cc', 'src/core/lib/surface/completion_queue.h', 'src/core/lib/surface/completion_queue_factory.cc', 'src/core/lib/surface/completion_queue_factory.h', 'src/core/lib/surface/event_string.cc', 'src/core/lib/surface/event_string.h', + 'src/core/lib/surface/filter_stack_call.cc', + 'src/core/lib/surface/filter_stack_call.h', 'src/core/lib/surface/init.cc', 'src/core/lib/surface/init.h', 'src/core/lib/surface/init_internally.cc', @@ -1794,13 +1800,11 @@ Pod::Spec.new do |s| 'src/core/lib/surface/legacy_channel.cc', 'src/core/lib/surface/legacy_channel.h', 'src/core/lib/surface/metadata_array.cc', + 'src/core/lib/surface/server_call.cc', + 'src/core/lib/surface/server_call.h', 'src/core/lib/surface/validate_metadata.cc', 'src/core/lib/surface/validate_metadata.h', 'src/core/lib/surface/version.cc', - 'src/core/lib/surface/wait_for_cq_end_op.cc', - 'src/core/lib/surface/wait_for_cq_end_op.h', - 'src/core/lib/transport/batch_builder.cc', - 'src/core/lib/transport/batch_builder.h', 'src/core/lib/transport/bdp_estimator.cc', 'src/core/lib/transport/bdp_estimator.h', 'src/core/lib/transport/call_arena_allocator.cc', @@ -3232,20 +3236,22 @@ Pod::Spec.new do |s| 'src/core/lib/surface/call.h', 'src/core/lib/surface/call_test_only.h', 'src/core/lib/surface/call_trace.h', + 'src/core/lib/surface/call_utils.h', 'src/core/lib/surface/channel.h', 'src/core/lib/surface/channel_create.h', 'src/core/lib/surface/channel_init.h', 'src/core/lib/surface/channel_stack_type.h', + 'src/core/lib/surface/client_call.h', 'src/core/lib/surface/completion_queue.h', 'src/core/lib/surface/completion_queue_factory.h', 'src/core/lib/surface/event_string.h', + 'src/core/lib/surface/filter_stack_call.h', 'src/core/lib/surface/init.h', 'src/core/lib/surface/init_internally.h', 'src/core/lib/surface/lame_client.h', 'src/core/lib/surface/legacy_channel.h', + 'src/core/lib/surface/server_call.h', 'src/core/lib/surface/validate_metadata.h', - 'src/core/lib/surface/wait_for_cq_end_op.h', - 'src/core/lib/transport/batch_builder.h', 'src/core/lib/transport/bdp_estimator.h', 'src/core/lib/transport/call_arena_allocator.h', 'src/core/lib/transport/call_destination.h', diff --git a/grpc.gemspec b/grpc.gemspec index 8fcf9cb1dd8..e5921c9ca75 100644 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -1658,6 +1658,8 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/surface/call_log_batch.cc ) s.files += %w( src/core/lib/surface/call_test_only.h ) s.files += %w( src/core/lib/surface/call_trace.h ) + s.files += %w( src/core/lib/surface/call_utils.cc ) + s.files += %w( src/core/lib/surface/call_utils.h ) s.files += %w( src/core/lib/surface/channel.cc ) s.files += %w( src/core/lib/surface/channel.h ) s.files += %w( src/core/lib/surface/channel_create.cc ) @@ -1666,12 +1668,16 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/surface/channel_init.h ) s.files += %w( src/core/lib/surface/channel_stack_type.cc ) s.files += %w( src/core/lib/surface/channel_stack_type.h ) + s.files += %w( src/core/lib/surface/client_call.cc ) + s.files += %w( src/core/lib/surface/client_call.h ) s.files += %w( src/core/lib/surface/completion_queue.cc ) s.files += %w( src/core/lib/surface/completion_queue.h ) s.files += %w( src/core/lib/surface/completion_queue_factory.cc ) s.files += %w( src/core/lib/surface/completion_queue_factory.h ) s.files += %w( src/core/lib/surface/event_string.cc ) s.files += %w( src/core/lib/surface/event_string.h ) + s.files += %w( src/core/lib/surface/filter_stack_call.cc ) + s.files += %w( src/core/lib/surface/filter_stack_call.h ) s.files += %w( src/core/lib/surface/init.cc ) s.files += %w( src/core/lib/surface/init.h ) s.files += %w( src/core/lib/surface/init_internally.cc ) @@ -1681,13 +1687,11 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/surface/legacy_channel.cc ) s.files += %w( src/core/lib/surface/legacy_channel.h ) s.files += %w( src/core/lib/surface/metadata_array.cc ) + s.files += %w( src/core/lib/surface/server_call.cc ) + s.files += %w( src/core/lib/surface/server_call.h ) s.files += %w( src/core/lib/surface/validate_metadata.cc ) s.files += %w( src/core/lib/surface/validate_metadata.h ) s.files += %w( src/core/lib/surface/version.cc ) - s.files += %w( src/core/lib/surface/wait_for_cq_end_op.cc ) - s.files += %w( src/core/lib/surface/wait_for_cq_end_op.h ) - s.files += %w( src/core/lib/transport/batch_builder.cc ) - s.files += %w( src/core/lib/transport/batch_builder.h ) s.files += %w( src/core/lib/transport/bdp_estimator.cc ) s.files += %w( src/core/lib/transport/bdp_estimator.h ) s.files += %w( src/core/lib/transport/call_arena_allocator.cc ) diff --git a/package.xml b/package.xml index 67b371367cd..00ea6281269 100644 --- a/package.xml +++ b/package.xml @@ -1640,6 +1640,8 @@ + + @@ -1648,12 +1650,16 @@ + + + + @@ -1663,13 +1669,11 @@ + + - - - - diff --git a/src/core/client_channel/client_channel.cc b/src/core/client_channel/client_channel.cc index 2fe8524c40e..1fadc90c226 100644 --- a/src/core/client_channel/client_channel.cc +++ b/src/core/client_channel/client_channel.cc @@ -48,64 +48,47 @@ #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/client_call.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" @@ -129,7 +112,8 @@ extern TraceFlag grpc_client_channel_lb_call_trace; class ClientChannel::ResolverResultHandler : public Resolver::ResultHandler { public: - explicit ResolverResultHandler(RefCountedPtr client_channel) + explicit ResolverResultHandler( + WeakRefCountedPtr client_channel) : client_channel_(std::move(client_channel)) {} ~ResolverResultHandler() override { @@ -145,7 +129,7 @@ class ClientChannel::ResolverResultHandler : public Resolver::ResultHandler { } private: - RefCountedPtr client_channel_; + WeakRefCountedPtr client_channel_; }; // @@ -163,7 +147,7 @@ class ClientChannel::ResolverResultHandler : public Resolver::ResultHandler { class ClientChannel::SubchannelWrapper : public SubchannelInterfaceWithCallDestination { public: - SubchannelWrapper(RefCountedPtr client_channel, + SubchannelWrapper(WeakRefCountedPtr client_channel, RefCountedPtr subchannel); ~SubchannelWrapper() override; @@ -210,7 +194,7 @@ class ClientChannel::SubchannelWrapper } }; - RefCountedPtr client_channel_; + WeakRefCountedPtr 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 @@ -333,7 +317,7 @@ class ClientChannel::SubchannelWrapper::WatcherWrapper }; ClientChannel::SubchannelWrapper::SubchannelWrapper( - RefCountedPtr client_channel, + WeakRefCountedPtr client_channel, RefCountedPtr subchannel) : SubchannelInterfaceWithCallDestination( GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace) @@ -450,7 +434,7 @@ class ClientChannel::ClientChannelControlHelper : public LoadBalancingPolicy::ChannelControlHelper { public: explicit ClientChannelControlHelper( - RefCountedPtr client_channel) + WeakRefCountedPtr client_channel) : client_channel_(std::move(client_channel)) {} ~ClientChannelControlHelper() override { @@ -552,7 +536,7 @@ class ClientChannel::ClientChannelControlHelper return channelz::ChannelTrace::Error; } - RefCountedPtr client_channel_; + WeakRefCountedPtr client_channel_; }; // @@ -571,9 +555,8 @@ RefCountedPtr GetSubchannelPool( } // namespace -absl::StatusOr> ClientChannel::Create( +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"); @@ -617,7 +600,7 @@ absl::StatusOr> ClientChannel::Create( "Missing event engine in args for client channel"); } // Success. Construct channel. - return MakeOrphanable( + return MakeRefCounted( std::move(target), std::move(channel_args), std::move(uri_to_resolve), std::move(*default_service_config), client_channel_factory, call_destination_factory); @@ -684,11 +667,14 @@ ClientChannel::~ClientChannel() { } } -void ClientChannel::Orphan() { +void ClientChannel::Orphaned() { if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_trace)) { gpr_log(GPR_INFO, "client_channel=%p: shutting down", this); } - auto self = RefAsSubclass(); + // Weird capture then copy needed to satisfy thread safety analysis, + // otherwise it seems to fail to recognize the correct lock is taken in the + // lambda. + auto self = WeakRefAsSubclass(); work_serializer_->Run( [self]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*self->work_serializer_) { self->DestroyResolverAndLbPolicyLocked(); @@ -698,7 +684,6 @@ void ClientChannel::Orphan() { // timer from being reset by other threads. idle_state_.IncreaseCallCount(); idle_activity_.Reset(); - Unref(); } grpc_connectivity_state ClientChannel::CheckConnectivityState( @@ -710,7 +695,7 @@ grpc_connectivity_state ClientChannel::CheckConnectivityState( 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. + auto self = WeakRefAsSubclass(); // Held by callback. work_serializer_->Run( [self]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*self->work_serializer_) { self->TryToConnectLocked(); @@ -801,34 +786,26 @@ void ClientChannel::Ping(grpc_completion_queue*, void*) { 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; +grpc_call* ClientChannel::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) { + return MakeClientCall(parent_call, propagation_mask, cq, std::move(path), + std::move(authority), false, deadline, + compression_options(), event_engine_.get(), + call_arena_allocator()->MakeArena(), Ref()); } -CallInitiator ClientChannel::CreateCall( - ClientMetadataHandle client_initial_metadata) { +void ClientChannel::StartCall(UnstartedCallHandler unstarted_handler) { // 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()); // Spawn a promise to wait for the resolver result. // This will eventually start the call. - call.initiator.SpawnGuardedUntilCallCompletes( + unstarted_handler.SpawnGuardedUntilCallCompletes( "wait-for-name-resolution", - [self = RefAsSubclass(), - unstarted_handler = std::move(call.handler)]() mutable { + [self = RefAsSubclass(), unstarted_handler]() mutable { const bool wait_for_ready = unstarted_handler.UnprocessedClientInitialMetadata() .GetOrCreatePointer(WaitForReady()) @@ -878,8 +855,6 @@ CallInitiator ClientChannel::CreateCall( return absl::OkStatus(); }); }); - // Return the initiator. - return std::move(call.initiator); } void ClientChannel::CreateResolverLocked() { @@ -889,7 +864,8 @@ void ClientChannel::CreateResolverLocked() { } resolver_ = CoreConfiguration::Get().resolver_registry().CreateResolver( uri_to_resolve_, channel_args_, nullptr, work_serializer_, - std::make_unique(RefAsSubclass())); + std::make_unique( + WeakRefAsSubclass())); // Since the validity of the args was checked when the channel was created, // CreateResolver() must return a non-null result. CHECK(resolver_ != nullptr); @@ -919,7 +895,8 @@ void ClientChannel::DestroyResolverAndLbPolicyLocked() { lb_policy_.get()); } lb_policy_.reset(); - picker_.Set(nullptr); + picker_.Set(MakeRefCounted( + absl::UnavailableError("Channel shutdown"))); } } } @@ -1165,8 +1142,8 @@ absl::Status ClientChannel::CreateOrUpdateLbPolicyLocked( 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. + // 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()) { @@ -1200,7 +1177,7 @@ OrphanablePtr ClientChannel::CreateLbPolicyLocked( lb_policy_args.work_serializer = work_serializer_; lb_policy_args.channel_control_helper = std::make_unique( - RefAsSubclass()); + WeakRefAsSubclass()); lb_policy_args.args = args; OrphanablePtr lb_policy = MakeOrphanable(std::move(lb_policy_args), @@ -1305,7 +1282,7 @@ 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 self = WeakRefAsSubclass(); auto promise = Loop([self]() { return TrySeq(Sleep(Timestamp::Now() + self->idle_timeout_), [self]() -> Poll> { @@ -1359,7 +1336,7 @@ absl::Status ClientChannel::ApplyServiceConfigToCall( return MaybeRewriteIllegalStatusCode(call_config_status, "ConfigSelector"); } // Apply our own method params to the call. - auto* method_params = static_cast( + auto* method_params = DownCast( service_config_call_data->GetMethodParsedConfig( service_config_parser_index_)); if (method_params != nullptr) { diff --git a/src/core/client_channel/client_channel.h b/src/core/client_channel/client_channel.h index abe53bbf689..13809c04471 100644 --- a/src/core/client_channel/client_channel.h +++ b/src/core/client_channel/client_channel.h @@ -57,7 +57,7 @@ class ClientChannel : public Channel { ~CallDestinationFactory() = default; }; - static absl::StatusOr> Create( + static absl::StatusOr> Create( std::string target, ChannelArgs channel_args); // Do not instantiate directly -- use Create() instead. @@ -69,7 +69,7 @@ class ClientChannel : public Channel { ~ClientChannel() override; - void Orphan() override; + void Orphaned() override; grpc_call* CreateCall(grpc_call* parent_call, uint32_t propagation_mask, grpc_completion_queue* cq, @@ -77,7 +77,7 @@ class ClientChannel : public Channel { Slice path, absl::optional authority, Timestamp deadline, bool registered_method) override; - CallInitiator CreateCall(ClientMetadataHandle client_initial_metadata); + void StartCall(UnstartedCallHandler unstarted_handler) override; grpc_event_engine::experimental::EventEngine* event_engine() const override { return event_engine_.get(); diff --git a/src/core/client_channel/client_channel_filter.cc b/src/core/client_channel/client_channel_filter.cc index e6564a61440..c9ada909d07 100644 --- a/src/core/client_channel/client_channel_filter.cc +++ b/src/core/client_channel/client_channel_filter.cc @@ -304,119 +304,12 @@ class ClientChannelFilter::FilterBasedCallData final grpc_error_handle cancel_error_; }; -class ClientChannelFilter::PromiseBasedCallData final - : public ClientChannelFilter::CallData { - public: - explicit PromiseBasedCallData(ClientChannelFilter* chand) : chand_(chand) {} - - ~PromiseBasedCallData() override { - if (was_queued_ && client_initial_metadata_ != nullptr) { - MutexLock lock(&chand_->resolution_mu_); - RemoveCallFromResolverQueuedCallsLocked(); - chand_->resolver_queued_calls_.erase(this); - } - } - - ArenaPromise> MakeNameResolutionPromise( - CallArgs call_args) { - pollent_ = NowOrNever(call_args.polling_entity->WaitAndCopy()).value(); - client_initial_metadata_ = std::move(call_args.client_initial_metadata); - // If we're still in IDLE, we need to start resolving. - if (GPR_UNLIKELY(chand_->CheckConnectivityState(false) == - GRPC_CHANNEL_IDLE)) { - if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { - gpr_log(GPR_INFO, "chand=%p calld=%p: %striggering exit idle", chand_, - this, GetContext()->DebugTag().c_str()); - } - // Bounce into the control plane work serializer to start resolving. - GRPC_CHANNEL_STACK_REF(chand_->owning_stack_, "ExitIdle"); - chand_->work_serializer_->Run( - [chand = chand_]() - ABSL_EXCLUSIVE_LOCKS_REQUIRED(*chand_->work_serializer_) { - chand->CheckConnectivityState(/*try_to_connect=*/true); - GRPC_CHANNEL_STACK_UNREF(chand->owning_stack_, "ExitIdle"); - }, - DEBUG_LOCATION); - } - return [this, call_args = std::move( - call_args)]() mutable -> Poll> { - auto result = CheckResolution(was_queued_); - if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { - gpr_log(GPR_INFO, "chand=%p calld=%p: %sCheckResolution returns %s", - chand_, this, GetContext()->DebugTag().c_str(), - result.has_value() ? result->ToString().c_str() : "Pending"); - } - if (!result.has_value()) return Pending{}; - if (!result->ok()) return *result; - call_args.client_initial_metadata = std::move(client_initial_metadata_); - return std::move(call_args); - }; - } - - private: - ClientChannelFilter* chand() const override { return chand_; } - Arena* arena() const override { return GetContext(); } - grpc_polling_entity* pollent() override { return &pollent_; } - grpc_metadata_batch* send_initial_metadata() override { - return client_initial_metadata_.get(); - } - - void OnAddToQueueLocked() override - ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ClientChannelFilter::resolution_mu_) { - waker_ = GetContext()->MakeNonOwningWaker(); - was_queued_ = true; - } - - void RetryCheckResolutionLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED( - &ClientChannelFilter::resolution_mu_) override { - if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { - gpr_log(GPR_INFO, "chand=%p calld=%p: RetryCheckResolutionLocked(): %s", - chand_, this, waker_.ActivityDebugTag().c_str()); - } - waker_.WakeupAsync(); - } - - void ResetDeadline(Duration timeout) override { - Call* call = GetContext(); - CallContext* call_context = GetContext(); - const Timestamp per_method_deadline = - Timestamp::FromCycleCounterRoundUp(call_context->call_start_time()) + - timeout; - call->UpdateDeadline(per_method_deadline); - } - - ClientChannelFilter* chand_; - grpc_polling_entity pollent_; - ClientMetadataHandle client_initial_metadata_; - bool was_queued_ = false; - Waker waker_ ABSL_GUARDED_BY(&ClientChannelFilter::resolution_mu_); -}; - // // Filter vtable // -const grpc_channel_filter ClientChannelFilter::kFilterVtableWithPromises = { +const grpc_channel_filter ClientChannelFilter::kFilter = { ClientChannelFilter::FilterBasedCallData::StartTransportStreamOpBatch, - ClientChannelFilter::MakeCallPromise, - /* init_call: */ nullptr, - ClientChannelFilter::StartTransportOp, - sizeof(ClientChannelFilter::FilterBasedCallData), - ClientChannelFilter::FilterBasedCallData::Init, - ClientChannelFilter::FilterBasedCallData::SetPollent, - ClientChannelFilter::FilterBasedCallData::Destroy, - sizeof(ClientChannelFilter), - ClientChannelFilter::Init, - grpc_channel_stack_no_post_init, - ClientChannelFilter::Destroy, - ClientChannelFilter::GetChannelInfo, - "client-channel", -}; - -const grpc_channel_filter ClientChannelFilter::kFilterVtableWithoutPromises = { - ClientChannelFilter::FilterBasedCallData::StartTransportStreamOpBatch, - nullptr, - /* init_call: */ nullptr, ClientChannelFilter::StartTransportOp, sizeof(ClientChannelFilter::FilterBasedCallData), ClientChannelFilter::FilterBasedCallData::Init, @@ -466,19 +359,6 @@ class DynamicTerminationFilter final { static void GetChannelInfo(grpc_channel_element* /*elem*/, const grpc_channel_info* /*info*/) {} - static ArenaPromise MakeCallPromise( - grpc_channel_element* elem, CallArgs call_args, NextPromiseFactory) { - auto* chand = static_cast(elem->channel_data); - return chand->chand_->CreateLoadBalancedCallPromise( - std::move(call_args), - []() { - auto* service_config_call_data = - GetServiceConfigCallData(GetContext()); - service_config_call_data->Commit(); - }, - /*is_transparent_retry=*/false); - } - private: explicit DynamicTerminationFilter(const ChannelArgs& args) : chand_(args.GetObject()) {} @@ -559,8 +439,6 @@ class DynamicTerminationFilter::CallData final { const grpc_channel_filter DynamicTerminationFilter::kFilterVtable = { DynamicTerminationFilter::CallData::StartTransportStreamOpBatch, - DynamicTerminationFilter::MakeCallPromise, - /* init_call: */ nullptr, DynamicTerminationFilter::StartTransportOp, sizeof(DynamicTerminationFilter::CallData), DynamicTerminationFilter::CallData::Init, @@ -1190,8 +1068,7 @@ class ClientChannelFilter::ClientChannelControlHelper final grpc_error_handle ClientChannelFilter::Init(grpc_channel_element* elem, grpc_channel_element_args* args) { CHECK(args->is_last); - CHECK(elem->filter == &kFilterVtableWithPromises || - elem->filter == &kFilterVtableWithoutPromises); + CHECK(elem->filter == &kFilter); grpc_error_handle error; new (elem->channel_data) ClientChannelFilter(args, &error); return error; @@ -1308,21 +1185,6 @@ ClientChannelFilter::~ClientChannelFilter() { grpc_pollset_set_destroy(interested_parties_); } -ArenaPromise ClientChannelFilter::MakeCallPromise( - grpc_channel_element* elem, CallArgs call_args, NextPromiseFactory) { - auto* chand = static_cast(elem->channel_data); - // TODO(roth): Is this the right lifetime story for calld? - auto* calld = GetContext()->ManagedNew(chand); - return TrySeq( - // Name resolution. - calld->MakeNameResolutionPromise(std::move(call_args)), - // Dynamic filter stack. - [calld](CallArgs call_args) mutable { - return calld->dynamic_filters()->channel_stack()->MakeClientCallPromise( - std::move(call_args)); - }); -} - OrphanablePtr ClientChannelFilter::CreateLoadBalancedCall( const grpc_call_element_args& args, grpc_polling_entity* pollent, @@ -1335,17 +1197,6 @@ ClientChannelFilter::CreateLoadBalancedCall( std::move(on_commit), is_transparent_retry)); } -ArenaPromise -ClientChannelFilter::CreateLoadBalancedCallPromise( - CallArgs call_args, absl::AnyInvocable on_commit, - bool is_transparent_retry) { - OrphanablePtr lb_call( - GetContext()->New( - this, std::move(on_commit), is_transparent_retry)); - auto* call_ptr = lb_call.get(); - return call_ptr->MakeCallPromise(std::move(call_args), std::move(lb_call)); -} - void ClientChannelFilter::ReprocessQueuedResolverCalls() { for (CallData* calld : resolver_queued_calls_) { calld->RemoveCallFromResolverQueuedCallsLocked(); @@ -3443,7 +3294,7 @@ void ClientChannelFilter::FilterBasedLoadBalancedCall::CreateSubchannelCall() { connected_subchannel()->Ref(), pollent_, path->Ref(), /*start_time=*/0, arena()->GetContext()->deadline(), // TODO(roth): When we implement hedging support, we will probably - // need to use a separate arena for each subchannel call. + // need to use a separate call arena for each subchannel call. arena(), call_combiner_}; grpc_error_handle error; subchannel_call_ = SubchannelCall::Create(std::move(call_args), &error); @@ -3463,146 +3314,4 @@ void ClientChannelFilter::FilterBasedLoadBalancedCall::CreateSubchannelCall() { } } -// -// ClientChannelFilter::PromiseBasedLoadBalancedCall -// - -ClientChannelFilter::PromiseBasedLoadBalancedCall::PromiseBasedLoadBalancedCall( - ClientChannelFilter* chand, absl::AnyInvocable on_commit, - bool is_transparent_retry) - : LoadBalancedCall(chand, GetContext(), std::move(on_commit), - is_transparent_retry) {} - -ArenaPromise -ClientChannelFilter::PromiseBasedLoadBalancedCall::MakeCallPromise( - CallArgs call_args, OrphanablePtr lb_call) { - pollent_ = NowOrNever(call_args.polling_entity->WaitAndCopy()).value(); - // Record ops in tracer. - if (call_attempt_tracer() != nullptr) { - call_attempt_tracer()->RecordSendInitialMetadata( - call_args.client_initial_metadata.get()); - // TODO(ctiller): Find a way to do this without registering a no-op mapper. - call_args.client_to_server_messages->InterceptAndMapWithHalfClose( - [](MessageHandle message) { return message; }, // No-op. - [this]() { - // TODO(roth): Change CallTracer API to not pass metadata - // batch to this method, since the batch is always empty. - grpc_metadata_batch metadata; - call_attempt_tracer()->RecordSendTrailingMetadata(&metadata); - }); - } - // Extract peer name from server initial metadata. - call_args.server_initial_metadata->InterceptAndMap( - [self = lb_call->RefAsSubclass()]( - ServerMetadataHandle metadata) { - if (self->call_attempt_tracer() != nullptr) { - self->call_attempt_tracer()->RecordReceivedInitialMetadata( - metadata.get()); - } - Slice* peer_string = metadata->get_pointer(PeerString()); - if (peer_string != nullptr) self->peer_string_ = peer_string->Ref(); - return metadata; - }); - client_initial_metadata_ = std::move(call_args.client_initial_metadata); - return OnCancel( - Map(TrySeq( - // LB pick. - [this]() -> Poll { - auto result = PickSubchannel(was_queued_); - if (GRPC_TRACE_FLAG_ENABLED( - grpc_client_channel_lb_call_trace)) { - gpr_log(GPR_INFO, - "chand=%p lb_call=%p: %sPickSubchannel() returns %s", - chand(), this, - GetContext()->DebugTag().c_str(), - result.has_value() ? result->ToString().c_str() - : "Pending"); - } - if (result == absl::nullopt) return Pending{}; - return std::move(*result); - }, - [this, call_args = std::move(call_args)]() mutable - -> ArenaPromise { - call_args.client_initial_metadata = - std::move(client_initial_metadata_); - return connected_subchannel()->MakeCallPromise( - std::move(call_args)); - }), - // Record call completion. - [this](ServerMetadataHandle metadata) { - if (call_attempt_tracer() != nullptr || - lb_subchannel_call_tracker() != nullptr) { - absl::Status status; - grpc_status_code code = metadata->get(GrpcStatusMetadata()) - .value_or(GRPC_STATUS_UNKNOWN); - if (code != GRPC_STATUS_OK) { - absl::string_view message; - if (const auto* grpc_message = - metadata->get_pointer(GrpcMessageMetadata())) { - message = grpc_message->as_string_view(); - } - status = - absl::Status(static_cast(code), message); - } - RecordCallCompletion(status, metadata.get(), - &GetContext() - ->call_stats() - ->transport_stream_stats, - peer_string_.as_string_view()); - } - RecordLatency(); - return metadata; - }), - [lb_call = std::move(lb_call)]() { - // If the waker is pending, then we need to remove ourself from - // the list of queued LB calls. - if (!lb_call->waker_.is_unwakeable()) { - MutexLock lock(&lb_call->chand()->lb_mu_); - lb_call->Commit(); - // Remove pick from list of queued picks. - lb_call->RemoveCallFromLbQueuedCallsLocked(); - // Remove from queued picks list. - lb_call->chand()->lb_queued_calls_.erase(lb_call.get()); - } - // TODO(ctiller): We don't have access to the call's actual status - // here, so we just assume CANCELLED. We could change this to use - // CallFinalization instead of OnCancel() so that we can get the - // actual status. But we should also have access to the trailing - // metadata, which we don't have in either case. Ultimately, we - // need a better story for code that needs to run at the end of a - // call in both cancellation and non-cancellation cases that needs - // access to server trailing metadata and the call's real status. - if (lb_call->call_attempt_tracer() != nullptr) { - lb_call->call_attempt_tracer()->RecordCancel( - absl::CancelledError("call cancelled")); - } - if (lb_call->call_attempt_tracer() != nullptr || - lb_call->lb_subchannel_call_tracker() != nullptr) { - // If we were cancelled without recording call completion, then - // record call completion here, as best we can. We assume status - // CANCELLED in this case. - lb_call->RecordCallCompletion(absl::CancelledError("call cancelled"), - nullptr, nullptr, ""); - } - }); -} - -grpc_metadata_batch* -ClientChannelFilter::PromiseBasedLoadBalancedCall::send_initial_metadata() - const { - return client_initial_metadata_.get(); -} - -void ClientChannelFilter::PromiseBasedLoadBalancedCall::OnAddToQueueLocked() { - waker_ = GetContext()->MakeNonOwningWaker(); - was_queued_ = true; -} - -void ClientChannelFilter::PromiseBasedLoadBalancedCall::RetryPickLocked() { - if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_lb_call_trace)) { - gpr_log(GPR_INFO, "chand=%p lb_call=%p: RetryPickLocked()", chand(), this); - } - waker_.WakeupAsync(); -} - } // namespace grpc_core diff --git a/src/core/client_channel/client_channel_filter.h b/src/core/client_channel/client_channel_filter.h index 602339074fd..9b119b4e021 100644 --- a/src/core/client_channel/client_channel_filter.h +++ b/src/core/client_channel/client_channel_filter.h @@ -57,8 +57,6 @@ #include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/iomgr_fwd.h" #include "src/core/lib/iomgr/polling_entity.h" -#include "src/core/lib/promise/activity.h" -#include "src/core/lib/promise/arena_promise.h" #include "src/core/lib/resource_quota/arena.h" #include "src/core/lib/slice/slice.h" #include "src/core/lib/transport/connectivity_state.h" @@ -99,12 +97,10 @@ namespace grpc_core { class ClientChannelFilter final { public: - static const grpc_channel_filter kFilterVtableWithPromises; - static const grpc_channel_filter kFilterVtableWithoutPromises; + static const grpc_channel_filter kFilter; class LoadBalancedCall; class FilterBasedLoadBalancedCall; - class PromiseBasedLoadBalancedCall; // Flag that this object gets stored in channel args as a raw pointer. struct RawPointerChannelArgTag {}; @@ -112,10 +108,6 @@ class ClientChannelFilter final { return "grpc.internal.client_channel_filter"; } - static ArenaPromise MakeCallPromise( - grpc_channel_element* elem, CallArgs call_args, - NextPromiseFactory next_promise_factory); - grpc_connectivity_state CheckConnectivityState(bool try_to_connect); // Starts a one-time connectivity state watch. When the channel's state @@ -160,14 +152,9 @@ class ClientChannelFilter final { grpc_closure* on_call_destruction_complete, absl::AnyInvocable on_commit, bool is_transparent_retry); - ArenaPromise CreateLoadBalancedCallPromise( - CallArgs call_args, absl::AnyInvocable on_commit, - bool is_transparent_retry); - private: class CallData; class FilterBasedCallData; - class PromiseBasedCallData; class ResolverResultHandler; class SubchannelWrapper; class ClientChannelControlHelper; @@ -581,32 +568,6 @@ class ClientChannelFilter::FilterBasedLoadBalancedCall final grpc_transport_stream_op_batch* pending_batches_[MAX_PENDING_BATCHES] = {}; }; -class ClientChannelFilter::PromiseBasedLoadBalancedCall final - : public ClientChannelFilter::LoadBalancedCall { - public: - PromiseBasedLoadBalancedCall(ClientChannelFilter* chand, - absl::AnyInvocable on_commit, - bool is_transparent_retry); - - ArenaPromise MakeCallPromise( - CallArgs call_args, OrphanablePtr lb_call); - - private: - grpc_polling_entity* pollent() override { return &pollent_; } - grpc_metadata_batch* send_initial_metadata() const override; - - void RetryPickLocked() override; - - void OnAddToQueueLocked() override - ABSL_EXCLUSIVE_LOCKS_REQUIRED(&ClientChannelFilter::lb_mu_); - - grpc_polling_entity pollent_; - ClientMetadataHandle client_initial_metadata_; - Waker waker_; - bool was_queued_ = false; - Slice peer_string_; -}; - } // namespace grpc_core #endif // GRPC_SRC_CORE_CLIENT_CHANNEL_CLIENT_CHANNEL_FILTER_H diff --git a/src/core/client_channel/client_channel_plugin.cc b/src/core/client_channel/client_channel_plugin.cc index 2aa115f579c..ccec049b6eb 100644 --- a/src/core/client_channel/client_channel_plugin.cc +++ b/src/core/client_channel/client_channel_plugin.cc @@ -31,24 +31,11 @@ namespace grpc_core { -namespace { -bool IsEverythingBelowClientChannelPromiseSafe(const ChannelArgs& args) { - return !args.GetBool(GRPC_ARG_ENABLE_RETRIES).value_or(true); -} -} // namespace - void BuildClientChannelConfiguration(CoreConfiguration::Builder* builder) { internal::ClientChannelServiceConfigParser::Register(builder); internal::RetryServiceConfigParser::Register(builder); builder->channel_init() - ->RegisterFilter(GRPC_CLIENT_CHANNEL, - &ClientChannelFilter::kFilterVtableWithPromises) - .If(IsEverythingBelowClientChannelPromiseSafe) - .Terminal(); - builder->channel_init() - ->RegisterFilter(GRPC_CLIENT_CHANNEL, - &ClientChannelFilter::kFilterVtableWithoutPromises) - .IfNot(IsEverythingBelowClientChannelPromiseSafe) + ->RegisterV2Filter(GRPC_CLIENT_CHANNEL) .Terminal(); } diff --git a/src/core/client_channel/load_balanced_call_destination.cc b/src/core/client_channel/load_balanced_call_destination.cc index 002a778e142..dfa2d62108b 100644 --- a/src/core/client_channel/load_balanced_call_destination.cc +++ b/src/core/client_channel/load_balanced_call_destination.cc @@ -18,6 +18,7 @@ #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/config/core_configuration.h" #include "src/core/lib/promise/loop.h" #include "src/core/telemetry/call_tracer.h" @@ -289,6 +290,7 @@ void LoadBalancedCallDestination::StartCall( [unstarted_handler, &last_picker]( RefCountedPtr picker) mutable { + CHECK_NE(picker.get(), nullptr); last_picker = std::move(picker); // Returns 3 possible things: // - Continue to queue the pick @@ -330,4 +332,20 @@ void LoadBalancedCallDestination::StartCall( }); } -} // namespace grpc_core \ No newline at end of file +void RegisterLoadBalancedCallDestination(CoreConfiguration::Builder* builder) { + class LoadBalancedCallDestinationFactory final + : public ClientChannel::CallDestinationFactory { + public: + RefCountedPtr CreateCallDestination( + ClientChannel::PickerObservable picker) override { + return MakeRefCounted(std::move(picker)); + } + }; + + builder->channel_args_preconditioning()->RegisterStage([](ChannelArgs args) { + return args.SetObject( + NoDestructSingleton::Get()); + }); +} + +} // namespace grpc_core diff --git a/src/core/client_channel/retry_filter.cc b/src/core/client_channel/retry_filter.cc index 1833ffa80d6..3a93872282c 100644 --- a/src/core/client_channel/retry_filter.cc +++ b/src/core/client_channel/retry_filter.cc @@ -139,8 +139,6 @@ const RetryMethodConfig* RetryFilter::GetRetryPolicy(Arena* arena) { const grpc_channel_filter RetryFilter::kVtable = { RetryFilter::LegacyCallData::StartTransportStreamOpBatch, - nullptr, - /* init_call: */ nullptr, RetryFilter::StartTransportOp, sizeof(RetryFilter::LegacyCallData), RetryFilter::LegacyCallData::Init, diff --git a/src/core/client_channel/subchannel.cc b/src/core/client_channel/subchannel.cc index 5c7fb150fca..82d97c56f47 100644 --- a/src/core/client_channel/subchannel.cc +++ b/src/core/client_channel/subchannel.cc @@ -157,36 +157,6 @@ class LegacyConnectedSubchannel : public ConnectedSubchannel { 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; @@ -252,10 +222,6 @@ class NewConnectedSubchannel : public ConnectedSubchannel { 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"); } @@ -869,8 +835,7 @@ void Subchannel::OnConnectingFinishedLocked(grpc_error_handle error) { bool Subchannel::PublishTransportLocked() { auto socket_node = std::move(connecting_result_.socket_node); - if (connecting_result_.transport->filter_stack_transport() != nullptr || - IsChaoticGoodEnabled()) { + if (connecting_result_.transport->filter_stack_transport() != nullptr) { // Construct channel stack. // Builder takes ownership of transport. ChannelStackBuilderImpl builder( diff --git a/src/core/client_channel/subchannel.h b/src/core/client_channel/subchannel.h index cb54070a794..78c78958686 100644 --- a/src/core/client_channel/subchannel.h +++ b/src/core/client_channel/subchannel.h @@ -82,8 +82,6 @@ class ConnectedSubchannel : public RefCounted { // 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: 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 63a886bc991..59a0b66776f 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 @@ -303,15 +303,13 @@ void RegisterLegacyChannelIdleFilters(CoreConfiguration::Builder* builder) { .If([](const ChannelArgs& channel_args) { return GetClientIdleTimeout(channel_args) != Duration::Infinity(); }); - if (!IsChaoticGoodEnabled()) { - builder->channel_init() - ->RegisterV2Filter(GRPC_SERVER_CHANNEL) - .ExcludeFromMinimalStack() - .If([](const ChannelArgs& channel_args) { - return LegacyMaxAgeFilter::Config::FromChannelArgs(channel_args) - .enable(); - }); - } + builder->channel_init() + ->RegisterV2Filter(GRPC_SERVER_CHANNEL) + .ExcludeFromMinimalStack() + .If([](const ChannelArgs& channel_args) { + return LegacyMaxAgeFilter::Config::FromChannelArgs(channel_args) + .enable(); + }); } LegacyMaxAgeFilter::LegacyMaxAgeFilter(grpc_channel_stack* channel_stack, 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 c528a3da12e..9c681703b1a 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 @@ -376,13 +376,14 @@ grpc_channel* grpc_chaotic_good_channel_create(const char* target, grpc_core::CoreConfiguration::Get() .channel_args_preconditioning() .PreconditionChannelArgs(args) - .SetObject( - grpc_core::NoDestructSingleton< - grpc_core::chaotic_good::ChaoticGoodChannelFactory>::Get()), + .SetObject(grpc_core::NoDestructSingleton< + grpc_core::chaotic_good::ChaoticGoodChannelFactory>::Get()) + .Set(GRPC_ARG_USE_V3_STACK, true), GRPC_CLIENT_CHANNEL, nullptr); if (r.ok()) { return r->release()->c_ptr(); } + LOG(ERROR) << "Failed to create chaotic good client channel: " << r.status(); error = absl_status_to_grpc_error(r.status()); intptr_t integer; grpc_status_code status = GRPC_STATUS_INTERNAL; @@ -391,6 +392,6 @@ grpc_channel* grpc_chaotic_good_channel_create(const char* target, status = static_cast(integer); } channel = grpc_lame_client_channel_create( - target, status, "Failed to create secure client channel"); + target, status, "Failed to create chaotic good client channel"); return channel; } 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 524d9e68349..98885e3bfc7 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 @@ -483,20 +483,21 @@ int grpc_server_add_chaotic_good_port(grpc_server* server, const char* addr) { return 0; } int port_num = 0; + std::vector> error_list; for (const auto& resolved_addr : resolved_or.value()) { auto listener = grpc_core::MakeOrphanable< grpc_core::chaotic_good::ChaoticGoodServerListener>( core_server, core_server->channel_args()); const auto ee_addr = grpc_event_engine::experimental::CreateResolvedAddress(resolved_addr); - gpr_log(GPR_INFO, "BIND: %s", - grpc_event_engine::experimental::ResolvedAddressToString(ee_addr) - ->c_str()); + std::string addr_str = + *grpc_event_engine::experimental::ResolvedAddressToString(ee_addr); + LOG(INFO) << "BIND: " << addr_str; auto bind_result = listener->Bind(ee_addr); if (!bind_result.ok()) { - LOG(ERROR) << "Failed to bind to " << addr << ": " - << bind_result.status().ToString(); - return 0; + error_list.push_back( + std::make_pair(std::move(addr_str), bind_result.status())); + continue; } if (port_num == 0) { port_num = bind_result.value(); @@ -505,5 +506,16 @@ int grpc_server_add_chaotic_good_port(grpc_server* server, const char* addr) { } core_server->AddListener(std::move(listener)); } + if (error_list.size() == resolved_or->size()) { + LOG(ERROR) << "Failed to bind any address for " << addr; + for (const auto& error : error_list) { + LOG(ERROR) << " " << error.first << ": " << error.second; + } + } else if (!error_list.empty()) { + LOG(INFO) << "Failed to bind some addresses for " << addr; + for (const auto& error : error_list) { + LOG(INFO) << " " << error.first << ": " << error.second; + } + } return port_num; } diff --git a/src/core/ext/transport/chaotic_good/server_transport.cc b/src/core/ext/transport/chaotic_good/server_transport.cc index bff440234ad..cd8371c3a61 100644 --- a/src/core/ext/transport/chaotic_good/server_transport.cc +++ b/src/core/ext/transport/chaotic_good/server_transport.cc @@ -78,24 +78,27 @@ auto ChaoticGoodServerTransport::PushFragmentIntoCall( gpr_log(GPR_INFO, "CHAOTIC_GOOD: PushFragmentIntoCall: frame=%s", frame.ToString().c_str()); } - return TrySeq(If( - frame.message.has_value(), - [&call_initiator, &frame]() mutable { - return call_initiator.PushMessage( - std::move(frame.message->message)); - }, - []() -> StatusFlag { return Success{}; }), - [this, call_initiator, end_of_stream = frame.end_of_stream, - stream_id]() mutable -> StatusFlag { - if (end_of_stream) { - call_initiator.FinishSends(); - // We have received end_of_stream. It is now safe to remove - // the call from the stream map. - MutexLock lock(&mu_); - stream_map_.erase(stream_id); - } - return Success{}; - }); + return Seq(If( + frame.message.has_value(), + [&call_initiator, &frame]() mutable { + return call_initiator.PushMessage( + std::move(frame.message->message)); + }, + []() -> StatusFlag { return Success{}; }), + [this, call_initiator, end_of_stream = frame.end_of_stream, + stream_id](StatusFlag status) mutable -> StatusFlag { + if (!status.ok() && grpc_chaotic_good_trace.enabled()) { + gpr_log(GPR_INFO, "CHAOTIC_GOOD: Failed PushFragmentIntoCall"); + } + if (end_of_stream || !status.ok()) { + call_initiator.FinishSends(); + // We have received end_of_stream. It is now safe to remove + // the call from the stream map. + MutexLock lock(&mu_); + stream_map_.erase(stream_id); + } + return Success{}; + }); } auto ChaoticGoodServerTransport::MaybePushFragmentIntoCall( @@ -340,13 +343,14 @@ auto ChaoticGoodServerTransport::TransportReadLoop( auto ChaoticGoodServerTransport::OnTransportActivityDone( absl::string_view activity) { - return [this, activity](absl::Status status) { + return [self = RefAsSubclass(), + activity](absl::Status status) { if (grpc_chaotic_good_trace.enabled()) { gpr_log(GPR_INFO, "CHAOTIC_GOOD: OnTransportActivityDone: activity=%s status=%s", std::string(activity).c_str(), status.ToString().c_str()); } - AbortWithError(); + self->AbortWithError(); }; } diff --git a/src/core/ext/transport/chttp2/client/chttp2_connector.cc b/src/core/ext/transport/chttp2/client/chttp2_connector.cc index a53b3374532..8711eece3bf 100644 --- a/src/core/ext/transport/chttp2/client/chttp2_connector.cc +++ b/src/core/ext/transport/chttp2/client/chttp2_connector.cc @@ -290,7 +290,7 @@ class Chttp2SecureClientChannelFactory : public ClientChannelFactory { } }; -absl::StatusOr> CreateChannel(const char* target, +absl::StatusOr> CreateChannel(const char* target, const ChannelArgs& args) { if (target == nullptr) { LOG(ERROR) << "cannot create channel with NULL target name"; diff --git a/src/core/ext/transport/inproc/inproc_transport.cc b/src/core/ext/transport/inproc/inproc_transport.cc index a6fb7d2498d..5d4d13abab5 100644 --- a/src/core/ext/transport/inproc/inproc_transport.cc +++ b/src/core/ext/transport/inproc/inproc_transport.cc @@ -171,9 +171,7 @@ class InprocClientTransport final : public ClientTransport { }; bool UsePromiseBasedTransport() { - if (!IsPromiseBasedInprocTransportEnabled()) return false; - CHECK(IsPromiseBasedClientCallEnabled()); - return true; + return IsPromiseBasedInprocTransportEnabled(); } OrphanablePtr @@ -182,7 +180,7 @@ InprocServerTransport::MakeClientTransport() { RefAsSubclass()); } -OrphanablePtr MakeLameChannel(absl::string_view why, +RefCountedPtr MakeLameChannel(absl::string_view why, absl::Status error) { gpr_log(GPR_ERROR, "%s: %s", std::string(why).c_str(), std::string(error.message()).c_str()); @@ -191,11 +189,11 @@ OrphanablePtr MakeLameChannel(absl::string_view why, if (grpc_error_get_int(error, StatusIntProperty::kRpcStatus, &integer)) { status = static_cast(integer); } - return OrphanablePtr(Channel::FromC(grpc_lame_client_channel_create( + return RefCountedPtr(Channel::FromC(grpc_lame_client_channel_create( nullptr, status, std::string(why).c_str()))); } -OrphanablePtr MakeInprocChannel(Server* server, +RefCountedPtr MakeInprocChannel(Server* server, ChannelArgs client_channel_args) { auto transports = MakeInProcessTransportPair(server->channel_args()); auto client_transport = std::move(transports.first); diff --git a/src/core/lib/channel/channel_stack.cc b/src/core/lib/channel/channel_stack.cc index 59c80a2d42d..837c90a445a 100644 --- a/src/core/lib/channel/channel_stack.cc +++ b/src/core/lib/channel/channel_stack.cc @@ -124,8 +124,7 @@ grpc_error_handle grpc_channel_stack_init( if (grpc_trace_channel_stack.enabled()) { LOG(INFO) << "CHANNEL_STACK: init " << name; for (size_t i = 0; i < filter_count; i++) { - gpr_log(GPR_INFO, "CHANNEL_STACK: filter %s%s", filters[i]->name, - filters[i]->make_call_promise ? " [promise-capable]" : ""); + LOG(INFO) << "CHANNEL_STACK: filter " << filters[i]->name; } } @@ -297,35 +296,6 @@ grpc_call_stack* grpc_call_stack_from_top_element(grpc_call_element* elem) { void grpc_channel_stack_no_post_init(grpc_channel_stack*, grpc_channel_element*) {} -namespace { - -grpc_core::NextPromiseFactory ClientNext(grpc_channel_element* elem) { - return [elem](grpc_core::CallArgs args) { - return elem->filter->make_call_promise(elem, std::move(args), - ClientNext(elem + 1)); - }; -} - -} // namespace - -grpc_core::ArenaPromise -grpc_channel_stack::MakeClientCallPromise(grpc_core::CallArgs call_args) { - return ClientNext(grpc_channel_stack_element(this, 0))(std::move(call_args)); -} - -void grpc_channel_stack::InitClientCallSpine( - grpc_core::CallSpineInterface* call) { - for (size_t i = 0; i < count; i++) { - auto* elem = grpc_channel_stack_element(this, i); - if (elem->filter->init_call == nullptr) { - grpc_core::Crash( - absl::StrCat("Filter '", elem->filter->name, - "' does not support the call-v3 interface")); - } - elem->filter->init_call(elem, call); - } -} - void grpc_call_log_op(const char* file, int line, gpr_log_severity severity, grpc_call_element* elem, grpc_transport_stream_op_batch* op) { diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h index bf6dd00412b..ce9d2dfab0a 100644 --- a/src/core/lib/channel/channel_stack.h +++ b/src/core/lib/channel/channel_stack.h @@ -105,24 +105,6 @@ struct grpc_channel_filter { // See grpc_call_next_op on how to call the next element in the stack void (*start_transport_stream_op_batch)(grpc_call_element* elem, grpc_transport_stream_op_batch* op); - // Create a promise to execute one call. - // If this is non-null, it may be used in preference to - // start_transport_stream_op_batch. - // If this is used in preference to start_transport_stream_op_batch, the - // following can be omitted also: - // - calling init_call_elem, destroy_call_elem, set_pollset_or_pollset_set - // - allocation of memory for call data - // There is an on-going migration to move all filters to providing this, and - // then to drop start_transport_stream_op_batch. - grpc_core::ArenaPromise (*make_call_promise)( - grpc_channel_element* elem, grpc_core::CallArgs call_args, - grpc_core::NextPromiseFactory next_promise_factory); - // Register interceptors into a call. - // If this is non-null it may be used in preference to make_call_promise. - // There is an on-going migration to move all filters to providing this, and - // then to drop start_transport_stream_op_batch. - void (*init_call)(grpc_channel_element* elem, - grpc_core::CallSpineInterface* call_spine); // Called to handle channel level operations - e.g. new calls, or transport // closure. // See grpc_channel_next_op on how to call the next element in the stack @@ -233,13 +215,6 @@ struct grpc_channel_stack { IncrementRefCount(); return grpc_core::RefCountedPtr(this); } - - grpc_core::ArenaPromise - MakeClientCallPromise(grpc_core::CallArgs call_args); - grpc_core::ArenaPromise - MakeServerCallPromise(grpc_core::CallArgs call_args); - - void InitClientCallSpine(grpc_core::CallSpineInterface* call); }; // A call stack tracks a set of related filters for one call, and guarantees diff --git a/src/core/lib/channel/channel_stack_builder.h b/src/core/lib/channel/channel_stack_builder.h index b7c0f840d0f..82a0592bc4f 100644 --- a/src/core/lib/channel/channel_stack_builder.h +++ b/src/core/lib/channel/channel_stack_builder.h @@ -74,11 +74,6 @@ class ChannelStackBuilder { // Helper to add a filter to the end of the stack. void AppendFilter(const grpc_channel_filter* filter); - // Determine whether a promise-based call stack is able to be built. - // Iterates each filter and ensures that there's a promise factory there. - // This will go away once the promise conversion is completed. - virtual bool IsPromising() const = 0; - // Build the channel stack. // After success, *result holds the new channel stack, // prefix_bytes are allocated before the channel stack, diff --git a/src/core/lib/channel/channel_stack_builder_impl.cc b/src/core/lib/channel/channel_stack_builder_impl.cc index 62c527ffe61..935eb222f35 100644 --- a/src/core/lib/channel/channel_stack_builder_impl.cc +++ b/src/core/lib/channel/channel_stack_builder_impl.cc @@ -54,153 +54,12 @@ namespace grpc_core { -namespace { - -const grpc_channel_filter* PromiseTracingFilterFor( - const grpc_channel_filter* filter) { - struct DerivedFilter : public grpc_channel_filter { - explicit DerivedFilter(const grpc_channel_filter* filter) - : grpc_channel_filter{ - // start_transport_stream_op_batch: - grpc_call_next_op, - // make_call_promise: - [](grpc_channel_element* elem, CallArgs call_args, - NextPromiseFactory next_promise_factory) - -> ArenaPromise { - auto* source_filter = - static_cast(elem->filter)->filter; - gpr_log( - GPR_DEBUG, - "%s[%s] CreateCallPromise: client_initial_metadata=%s", - GetContext()->DebugTag().c_str(), - source_filter->name, - call_args.client_initial_metadata->DebugString().c_str()); - return [source_filter, child = next_promise_factory( - std::move(call_args))]() mutable { - gpr_log(GPR_DEBUG, "%s[%s] PollCallPromise: begin", - GetContext()->DebugTag().c_str(), - source_filter->name); - auto r = child(); - if (auto* p = r.value_if_ready()) { - gpr_log(GPR_DEBUG, "%s[%s] PollCallPromise: done: %s", - GetContext()->DebugTag().c_str(), - source_filter->name, (*p)->DebugString().c_str()); - } else { - gpr_log(GPR_DEBUG, "%s[%s] PollCallPromise: <>", - GetContext()->DebugTag().c_str(), - source_filter->name); - } - return r; - }; - }, - /* init_call: */ - [](grpc_channel_element* elem, CallSpineInterface* call) { - auto* c = DownCast(call); - auto* source_filter = - static_cast(elem->filter)->filter; - c->client_initial_metadata().receiver.InterceptAndMap( - [source_filter](ClientMetadataHandle md) { - gpr_log(GPR_DEBUG, "%s[%s] OnClientInitialMetadata: %s", - GetContext()->DebugTag().c_str(), - source_filter->name, md->DebugString().c_str()); - return md; - }); - c->client_to_server_messages().receiver.InterceptAndMap( - [source_filter](MessageHandle msg) { - gpr_log(GPR_DEBUG, "%s[%s] OnClientToServerMessage: %s", - GetContext()->DebugTag().c_str(), - source_filter->name, msg->DebugString().c_str()); - return msg; - }); - c->server_initial_metadata().sender.InterceptAndMap( - [source_filter](ServerMetadataHandle md) { - gpr_log(GPR_DEBUG, "%s[%s] OnServerInitialMetadata: %s", - GetContext()->DebugTag().c_str(), - source_filter->name, md->DebugString().c_str()); - return md; - }); - c->server_to_client_messages().sender.InterceptAndMap( - [source_filter](MessageHandle msg) { - gpr_log(GPR_DEBUG, "%s[%s] OnServerToClientMessage: %s", - GetContext()->DebugTag().c_str(), - source_filter->name, msg->DebugString().c_str()); - return msg; - }); - }, - grpc_channel_next_op, - /* sizeof_call_data: */ 0, - // init_call_elem: - [](grpc_call_element*, const grpc_call_element_args*) { - return absl::OkStatus(); - }, - grpc_call_stack_ignore_set_pollset_or_pollset_set, - // destroy_call_elem: - [](grpc_call_element*, const grpc_call_final_info*, - grpc_closure*) {}, - // sizeof_channel_data: - 0, - // init_channel_elem: - [](grpc_channel_element*, grpc_channel_element_args*) { - return absl::OkStatus(); - }, - // post_init_channel_elem: - [](grpc_channel_stack*, grpc_channel_element*) {}, - // destroy_channel_elem: - [](grpc_channel_element*) {}, grpc_channel_next_get_info, - // name: - nullptr}, - filter(filter), - name_str(absl::StrCat(filter->name, ".trace")) { - this->name = name_str.c_str(); - } - const grpc_channel_filter* const filter; - const std::string name_str; - }; - struct Globals { - Mutex mu; - absl::flat_hash_map> - map ABSL_GUARDED_BY(mu); - }; - auto* globals = NoDestructSingleton::Get(); - MutexLock lock(&globals->mu); - auto it = globals->map.find(filter); - if (it != globals->map.end()) return it->second.get(); - return globals->map.emplace(filter, std::make_unique(filter)) - .first->second.get(); -} - -} // namespace - -bool ChannelStackBuilderImpl::IsPromising() const { - for (const auto* filter : stack()) { - if (filter->make_call_promise == nullptr) return false; - } - return true; -} - absl::StatusOr> ChannelStackBuilderImpl::Build() { std::vector stack; - const bool is_promising = IsPromising(); - const bool is_client = - grpc_channel_stack_type_is_client(channel_stack_type()); - const bool client_promise_tracing = - is_client && is_promising && grpc_call_trace.enabled(); - const bool server_promise_tracing = - !is_client && is_promising && grpc_call_trace.enabled(); for (const auto* filter : this->stack()) { - if (client_promise_tracing) { - stack.push_back(PromiseTracingFilterFor(filter)); - } stack.push_back(filter); - if (server_promise_tracing) { - stack.push_back(PromiseTracingFilterFor(filter)); - } - } - if (server_promise_tracing) { - stack.pop_back(); // connected_channel must be last => can't be traced } // calculate the size of the channel stack diff --git a/src/core/lib/channel/channel_stack_builder_impl.h b/src/core/lib/channel/channel_stack_builder_impl.h index 6f298b7c287..a76e322b71b 100644 --- a/src/core/lib/channel/channel_stack_builder_impl.h +++ b/src/core/lib/channel/channel_stack_builder_impl.h @@ -34,8 +34,6 @@ class ChannelStackBuilderImpl final : public ChannelStackBuilder { public: using ChannelStackBuilder::ChannelStackBuilder; - bool IsPromising() const override; - // Build the channel stack. // After success, *result holds the new channel stack, // prefix_bytes are allocated before the channel stack, diff --git a/src/core/lib/channel/connected_channel.cc b/src/core/lib/channel/connected_channel.cc index bf6fe94471b..692a3ae68c8 100644 --- a/src/core/lib/channel/connected_channel.cc +++ b/src/core/lib/channel/connected_channel.cc @@ -74,7 +74,6 @@ #include "src/core/lib/surface/call.h" #include "src/core/lib/surface/call_trace.h" #include "src/core/lib/surface/channel_stack_type.h" -#include "src/core/lib/transport/batch_builder.h" #include "src/core/lib/transport/error_utils.h" #include "src/core/lib/transport/metadata_batch.h" #include "src/core/lib/transport/transport.h" @@ -245,683 +244,48 @@ static void connected_channel_get_channel_info( namespace grpc_core { namespace { - -#if defined(GRPC_EXPERIMENT_IS_INCLUDED_PROMISE_BASED_CLIENT_CALL) || \ - defined(GRPC_EXPERIMENT_IS_INCLUDED_PROMISE_BASED_SERVER_CALL) -class ConnectedChannelStream : public Orphanable { - public: - explicit ConnectedChannelStream(Transport* transport) - : transport_(transport), stream_(nullptr, StreamDeleter(this)) { - GRPC_STREAM_REF_INIT( - &stream_refcount_, 1, - [](void* p, grpc_error_handle) { - static_cast(p)->BeginDestroy(); - }, - this, "ConnectedChannelStream"); - } - - Transport* transport() { return transport_; } - grpc_closure* stream_destroyed_closure() { return &stream_destroyed_; } - - BatchBuilder::Target batch_target() { - return BatchBuilder::Target{transport_, stream_.get(), &stream_refcount_}; - } - - void IncrementRefCount(const char* reason = "smartptr") { -#ifndef NDEBUG - grpc_stream_ref(&stream_refcount_, reason); -#else - (void)reason; - grpc_stream_ref(&stream_refcount_); -#endif - } - - void Unref(const char* reason = "smartptr") { -#ifndef NDEBUG - grpc_stream_unref(&stream_refcount_, reason); -#else - (void)reason; - grpc_stream_unref(&stream_refcount_); -#endif - } - - RefCountedPtr InternalRef() { - IncrementRefCount("smartptr"); - return RefCountedPtr(this); - } - - void Orphan() final { - bool finished = finished_.IsSet(); - if (grpc_call_trace.enabled()) { - gpr_log(GPR_DEBUG, "%s[connected] Orphan stream, finished: %d", - party_->DebugTag().c_str(), finished); - } - // If we hadn't already observed the stream to be finished, we need to - // cancel it at the transport. - if (!finished) { - party_->Spawn( - "finish", - [self = InternalRef()]() { - if (!self->finished_.IsSet()) { - self->finished_.Set(); - } - return Empty{}; - }, - [](Empty) {}); - GetContext()->Cancel(batch_target(), - absl::CancelledError()); - } - Unref("orphan connected stream"); - } - - // Returns a promise that implements the receive message loop. - auto RecvMessages(PipeSender* incoming_messages, - bool cancel_on_error); - // Returns a promise that implements the send message loop. - auto SendMessages(PipeReceiver* outgoing_messages); - - void SetStream(grpc_stream* stream) { stream_.reset(stream); } - grpc_stream* stream() { return stream_.get(); } - grpc_stream_refcount* stream_refcount() { return &stream_refcount_; } - - void set_finished() { finished_.Set(); } - auto WaitFinished() { return finished_.Wait(); } - - private: - class StreamDeleter { - public: - explicit StreamDeleter(ConnectedChannelStream* impl) : impl_(impl) {} - void operator()(grpc_stream* stream) const { - if (stream == nullptr) return; - impl_->transport()->filter_stack_transport()->DestroyStream( - stream, impl_->stream_destroyed_closure()); - } - - private: - ConnectedChannelStream* impl_; - }; - using StreamPtr = std::unique_ptr; - - void StreamDestroyed() { - call_context_->RunInContext([this] { this->~ConnectedChannelStream(); }); - } - - void BeginDestroy() { - if (stream_ != nullptr) { - stream_.reset(); - } else { - StreamDestroyed(); - } - } - - Transport* const transport_; - RefCountedPtr const call_context_{ - GetContext()->Ref()}; - grpc_closure stream_destroyed_ = - MakeMemberClosure( - this, DEBUG_LOCATION); - grpc_stream_refcount stream_refcount_; - StreamPtr stream_; - Arena* arena_ = GetContext(); - Party* const party_ = GetContext(); - ExternallyObservableLatch finished_; +const grpc_channel_filter kConnectedFilter{ + connected_channel_start_transport_stream_op_batch, + connected_channel_start_transport_op, + sizeof(call_data), + connected_channel_init_call_elem, + set_pollset_or_pollset_set, + connected_channel_destroy_call_elem, + sizeof(channel_data), + connected_channel_init_channel_elem, + +[](grpc_channel_stack* channel_stack, grpc_channel_element* elem) { + // HACK(ctiller): increase call stack size for the channel to make + // space for channel data. We need a cleaner (but performant) way to + // do this, and I'm not sure what that is yet. This is only "safe" + // because call stacks place no additional data after the last call + // element, and the last call element MUST be the connected channel. + auto* transport = + static_cast(elem->channel_data)->transport; + if (transport->filter_stack_transport() != nullptr) { + channel_stack->call_stack_size += + transport->filter_stack_transport()->SizeOfStream(); + } + }, + connected_channel_destroy_channel_elem, + connected_channel_get_channel_info, + "connected", }; -auto ConnectedChannelStream::RecvMessages( - PipeSender* incoming_messages, bool cancel_on_error) { - return Loop([self = InternalRef(), cancel_on_error, - incoming_messages = std::move(*incoming_messages)]() mutable { - return Seq( - GetContext()->ReceiveMessage(self->batch_target()), - [cancel_on_error, &incoming_messages]( - absl::StatusOr> status) mutable { - bool has_message = status.ok() && status->has_value(); - auto publish_message = [&incoming_messages, &status]() { - auto pending_message = std::move(**status); - if (grpc_call_trace.enabled()) { - gpr_log(GPR_INFO, - "%s[connected] RecvMessage: received payload of %" PRIdPTR - " bytes", - GetContext()->DebugTag().c_str(), - pending_message->payload()->Length()); - } - return Map(incoming_messages.Push(std::move(pending_message)), - [](bool ok) -> LoopCtl { - if (!ok) { - if (grpc_call_trace.enabled()) { - gpr_log( - GPR_INFO, - "%s[connected] RecvMessage: failed to " - "push message towards the application", - GetContext()->DebugTag().c_str()); - } - return absl::OkStatus(); - } - return Continue{}; - }); - }; - auto publish_close = [cancel_on_error, &incoming_messages, - &status]() mutable { - if (grpc_call_trace.enabled()) { - gpr_log(GPR_INFO, - "%s[connected] RecvMessage: reached end of stream with " - "status:%s", - GetContext()->DebugTag().c_str(), - status.status().ToString().c_str()); - } - if (cancel_on_error && !status.ok()) { - incoming_messages.CloseWithError(); - } else { - incoming_messages.Close(); - } - return Immediate(LoopCtl(status.status())); - }; - return If(has_message, std::move(publish_message), - std::move(publish_close)); - }); - }); -} - -auto ConnectedChannelStream::SendMessages( - PipeReceiver* outgoing_messages) { - return ForEach(std::move(*outgoing_messages), - [self = InternalRef()](MessageHandle message) { - return GetContext()->SendMessage( - self->batch_target(), std::move(message)); - }); -} -#endif // defined(GRPC_EXPERIMENT_IS_INCLUDED_PROMISE_BASED_CLIENT_CALL) || - // defined(GRPC_EXPERIMENT_IS_INCLUDED_PROMISE_BASED_SERVER_CALL) - -#ifdef GRPC_EXPERIMENT_IS_INCLUDED_PROMISE_BASED_CLIENT_CALL -ArenaPromise MakeClientCallPromise(Transport* transport, - CallArgs call_args, - NextPromiseFactory) { - OrphanablePtr stream( - GetContext()->New(transport)); - stream->SetStream(static_cast(GetContext()->Alloc( - transport->filter_stack_transport()->SizeOfStream()))); - transport->filter_stack_transport()->InitStream(stream->stream(), - stream->stream_refcount(), - nullptr, GetContext()); - auto* party = GetContext(); - party->Spawn("set_polling_entity", call_args.polling_entity->Wait(), - [transport, stream = stream->InternalRef()]( - grpc_polling_entity polling_entity) { - transport->SetPollingEntity(stream->stream(), &polling_entity); - }); - // Start a loop to send messages from client_to_server_messages to the - // transport. When the pipe closes and the loop completes, send a trailing - // metadata batch to close the stream. - party->Spawn( - "send_messages", - TrySeq(stream->SendMessages(call_args.client_to_server_messages), - [stream = stream->InternalRef()]() { - return GetContext()->SendClientTrailingMetadata( - stream->batch_target()); - }), - [](absl::Status) {}); - // Start a promise to receive server initial metadata and then forward it up - // through the receiving pipe. - auto server_initial_metadata = Arena::MakePooled(); - party->Spawn( - "recv_initial_metadata", - TrySeq(GetContext()->ReceiveServerInitialMetadata( - stream->batch_target()), - [pipe = call_args.server_initial_metadata]( - ServerMetadataHandle server_initial_metadata) { - if (grpc_call_trace.enabled()) { - gpr_log(GPR_DEBUG, - "%s[connected] Publish client initial metadata: %s", - GetContext()->DebugTag().c_str(), - server_initial_metadata->DebugString().c_str()); - } - return Map(pipe->Push(std::move(server_initial_metadata)), - [](bool r) { - if (r) return absl::OkStatus(); - return absl::CancelledError(); - }); - }), - [](absl::Status) {}); - - // Build up the rest of the main call promise: - - // Create a promise that will send initial metadata and then signal completion - // of that via the token. - auto send_initial_metadata = Seq( - GetContext()->SendClientInitialMetadata( - stream->batch_target(), std::move(call_args.client_initial_metadata)), - [sent_initial_metadata_token = - std::move(call_args.client_initial_metadata_outstanding)]( - absl::Status status) mutable { - sent_initial_metadata_token.Complete(status.ok()); - return status; - }); - // Create a promise that will receive server trailing metadata. - // If this fails, we massage the error into metadata that we can report - // upwards. - auto server_trailing_metadata = Arena::MakePooled(); - auto recv_trailing_metadata = Map( - GetContext()->ReceiveServerTrailingMetadata( - stream->batch_target()), - [](absl::StatusOr status) mutable { - if (!status.ok()) { - auto server_trailing_metadata = Arena::MakePooled(); - grpc_status_code status_code = GRPC_STATUS_UNKNOWN; - std::string message; - grpc_error_get_status(status.status(), Timestamp::InfFuture(), - &status_code, &message, nullptr, nullptr); - server_trailing_metadata->Set(GrpcStatusMetadata(), status_code); - server_trailing_metadata->Set(GrpcMessageMetadata(), - Slice::FromCopiedString(message)); - return server_trailing_metadata; - } else { - return std::move(*status); - } - }); - // Finally the main call promise. - // Concurrently: send initial metadata and receive messages, until BOTH - // complete (or one fails). - // Next: receive trailing metadata, and return that up the stack. - auto recv_messages = - stream->RecvMessages(call_args.server_to_client_messages, false); - return Map( - [send_initial_metadata = std::move(send_initial_metadata), - recv_messages = std::move(recv_messages), - recv_trailing_metadata = std::move(recv_trailing_metadata), - done_send_initial_metadata = false, done_recv_messages = false, - done_recv_trailing_metadata = - false]() mutable -> Poll { - if (!done_send_initial_metadata) { - auto p = send_initial_metadata(); - if (auto* r = p.value_if_ready()) { - done_send_initial_metadata = true; - if (!r->ok()) return StatusCast(*r); - } - } - if (!done_recv_messages) { - auto p = recv_messages(); - if (p.ready()) { - // NOTE: ignore errors here, they'll be collected in the - // recv_trailing_metadata. - done_recv_messages = true; - } else { - return Pending{}; - } - } - if (!done_recv_trailing_metadata) { - auto p = recv_trailing_metadata(); - if (auto* r = p.value_if_ready()) { - done_recv_trailing_metadata = true; - return std::move(*r); - } - } - return Pending{}; - }, - [stream = std::move(stream)](ServerMetadataHandle result) { - stream->set_finished(); - return result; - }); -} -#endif - -#ifdef GRPC_EXPERIMENT_IS_INCLUDED_PROMISE_BASED_SERVER_CALL -ArenaPromise MakeServerCallPromise( - Transport* transport, CallArgs, NextPromiseFactory next_promise_factory) { - OrphanablePtr stream( - GetContext()->New(transport)); - - stream->SetStream(static_cast(GetContext()->Alloc( - transport->filter_stack_transport()->SizeOfStream()))); - transport->filter_stack_transport()->InitStream( - stream->stream(), stream->stream_refcount(), - GetContext()->server_call_context()->server_stream_data(), - GetContext()); - auto* party = GetContext(); - - // Arifacts we need for the lifetime of the call. - struct CallData { - Pipe server_to_client; - Pipe client_to_server; - Pipe server_initial_metadata; - Latch failure_latch; - Latch polling_entity_latch; - bool sent_initial_metadata = false; - bool sent_trailing_metadata = false; - }; - auto* call_data = GetContext()->New(); - GetContext()->Add( - [call_data](const grpc_call_final_info*) { call_data->~CallData(); }); - - party->Spawn("set_polling_entity", call_data->polling_entity_latch.Wait(), - [transport, stream = stream->InternalRef()]( - grpc_polling_entity polling_entity) { - transport->SetPollingEntity(stream->stream(), &polling_entity); - }); - - auto server_to_client_empty = - call_data->server_to_client.receiver.AwaitEmpty(); - - // Create a promise that will receive client initial metadata, and then run - // the main stem of the call (calling next_promise_factory up through the - // filters). - // Race the main call with failure_latch, allowing us to forcefully complete - // the call in the case of a failure. - auto recv_initial_metadata_then_run_promise = - TrySeq(GetContext()->ReceiveClientInitialMetadata( - stream->batch_target()), - [next_promise_factory = std::move(next_promise_factory), - server_to_client_empty = std::move(server_to_client_empty), - call_data](ClientMetadataHandle client_initial_metadata) { - auto call_promise = next_promise_factory(CallArgs{ - std::move(client_initial_metadata), - ClientInitialMetadataOutstandingToken::Empty(), - &call_data->polling_entity_latch, - &call_data->server_initial_metadata.sender, - &call_data->client_to_server.receiver, - &call_data->server_to_client.sender, - }); - return Race(call_data->failure_latch.Wait(), - [call_promise = std::move(call_promise), - server_to_client_empty = - std::move(server_to_client_empty)]() mutable - -> Poll { - // TODO(ctiller): this is deeply weird and we need - // to clean this up. - // - // The following few lines check to ensure that - // there's no message currently pending in the - // outgoing message queue, and if (and only if) - // that's true decides to poll the main promise to - // see if there's a result. - // - // This essentially introduces a polling priority - // scheme that makes the current promise structure - // work out the way we want when talking to - // transports. - // - // The problem is that transports are going to need - // to replicate this structure when they convert to - // promises, and that becomes troubling as we'll be - // replicating weird throughout the stack. - // - // Instead we likely need to change the way we're - // composing promises through the stack. - // - // Proposed is to change filters from a promise - // that takes ClientInitialMetadata and returns - // ServerTrailingMetadata with three pipes for - // ServerInitialMetadata and - // ClientToServerMessages, ServerToClientMessages. - // Instead we'll have five pipes, moving - // ClientInitialMetadata and ServerTrailingMetadata - // to pipes that can be intercepted. - // - // The effect of this change will be to cripple the - // things that can be done in a filter (but cripple - // in line with what most filters actually do). - // We'll likely need to add a `CallContext::Cancel` - // to allow filters to cancel a request, but this - // would also have the advantage of centralizing - // our cancellation machinery which seems like an - // additional win - with the net effect that the - // shape of the call gets made explicit at the top - // & bottom of the stack. - // - // There's a small set of filters (retry, this one, - // lame client, clinet channel) that terminate - // stacks and need a richer set of semantics, but - // that ends up being fine because we can spawn - // tasks in parties to handle those edge cases, and - // keep the majority of filters simple: they just - // call InterceptAndMap on a handful of filters at - // call initialization time and then proceed to - // actually filter. - // - // So that's the plan, why isn't it enacted here? - // - // Well, the plan ends up being easy to implement - // in the promise based world (I did a prototype on - // a branch in an afternoon). It's heinous to - // implement in promise_based_filter, and that code - // is load bearing for us at the time of writing. - // It's not worth delaying promises for a further N - // months (N ~ 6) to make that change. - // - // Instead, we'll move forward with this, get - // promise_based_filter out of the picture, and - // then during the mop-up phase for promises tweak - // the compute structure to move to the magical - // five pipes (I'm reminded of an old Onion - // article), and end up in a good happy place. - if (server_to_client_empty().pending()) { - return Pending{}; - } - return call_promise(); - }); - }); - - // Promise factory that accepts a ServerMetadataHandle, and sends it as the - // trailing metadata for this call. - auto send_trailing_metadata = [call_data, stream = stream->InternalRef()]( - ServerMetadataHandle - server_trailing_metadata) { - bool is_cancellation = - server_trailing_metadata->get(GrpcCallWasCancelled()).value_or(false); - return GetContext()->SendServerTrailingMetadata( - stream->batch_target(), std::move(server_trailing_metadata), - is_cancellation || - !std::exchange(call_data->sent_initial_metadata, true)); - }; - - // Runs the receive message loop, either until all the messages - // are received or the server call is complete. - party->Spawn( - "recv_messages", - Race( - Map(stream->WaitFinished(), [](Empty) { return absl::OkStatus(); }), - Map(stream->RecvMessages(&call_data->client_to_server.sender, true), - [failure_latch = &call_data->failure_latch](absl::Status status) { - if (!status.ok() && !failure_latch->is_set()) { - failure_latch->Set(ServerMetadataFromStatus(status)); - } - return status; - })), - [](absl::Status) {}); - - // Run a promise that will send initial metadata (if that pipe sends some). - // And then run the send message loop until that completes. - - auto send_initial_metadata = Seq( - Race(Map(stream->WaitFinished(), - [](Empty) { return NextResult(true); }), - call_data->server_initial_metadata.receiver.Next()), - [call_data, stream = stream->InternalRef()]( - NextResult next_result) mutable { - auto md = !call_data->sent_initial_metadata && next_result.has_value() - ? std::move(next_result.value()) - : nullptr; - if (md != nullptr) { - call_data->sent_initial_metadata = true; - auto* party = GetContext(); - party->Spawn("connected/send_initial_metadata", - GetContext()->SendServerInitialMetadata( - stream->batch_target(), std::move(md)), - [](absl::Status) {}); - return Immediate(absl::OkStatus()); - } - return Immediate(absl::CancelledError()); - }); - party->Spawn( - "send_initial_metadata_then_messages", - Race(Map(stream->WaitFinished(), [](Empty) { return absl::OkStatus(); }), - TrySeq(std::move(send_initial_metadata), - stream->SendMessages(&call_data->server_to_client.receiver))), - [](absl::Status) {}); - - // Spawn a job to fetch the "client trailing metadata" - if this is OK then - // it's client done, otherwise it's a signal of cancellation from the client - // which we'll use failure_latch to signal. - - party->Spawn( - "recv_trailing_metadata", - Seq(GetContext()->ReceiveClientTrailingMetadata( - stream->batch_target()), - [failure_latch = &call_data->failure_latch]( - absl::StatusOr status) mutable { - if (grpc_call_trace.enabled()) { - gpr_log( - GPR_DEBUG, - "%s[connected] Got trailing metadata; status=%s metadata=%s", - GetContext()->DebugTag().c_str(), - status.status().ToString().c_str(), - status.ok() ? (*status)->DebugString().c_str() : ""); - } - ClientMetadataHandle trailing_metadata; - if (status.ok()) { - trailing_metadata = std::move(*status); - } else { - trailing_metadata = Arena::MakePooled(); - grpc_status_code status_code = GRPC_STATUS_UNKNOWN; - std::string message; - grpc_error_get_status(status.status(), Timestamp::InfFuture(), - &status_code, &message, nullptr, nullptr); - trailing_metadata->Set(GrpcStatusMetadata(), status_code); - trailing_metadata->Set(GrpcMessageMetadata(), - Slice::FromCopiedString(message)); - } - if (trailing_metadata->get(GrpcStatusMetadata()) - .value_or(GRPC_STATUS_UNKNOWN) != GRPC_STATUS_OK) { - if (!failure_latch->is_set()) { - failure_latch->Set(std::move(trailing_metadata)); - } - } - return Empty{}; - }), - [](Empty) {}); - - // Finally assemble the main call promise: - // Receive initial metadata from the client and start the promise up the - // filter stack. - // Upon completion, send trailing metadata to the client and then return it - // (allowing the call code to decide on what signalling to give the - // application). - - struct CleanupPollingEntityLatch { - void operator()(Latch* latch) { - if (!latch->is_set()) latch->Set(grpc_polling_entity()); - } - }; - auto cleanup_polling_entity_latch = - std::unique_ptr, CleanupPollingEntityLatch>( - &call_data->polling_entity_latch); - struct CleanupSendInitialMetadata { - void operator()(CallData* call_data) { - call_data->server_initial_metadata.receiver.CloseWithError(); - } - }; - auto cleanup_send_initial_metadata = - std::unique_ptr(call_data); - - return Map( - Seq(std::move(recv_initial_metadata_then_run_promise), - std::move(send_trailing_metadata)), - [cleanup_polling_entity_latch = std::move(cleanup_polling_entity_latch), - cleanup_send_initial_metadata = std::move(cleanup_send_initial_metadata), - stream = std::move(stream)](ServerMetadataHandle md) { - stream->set_finished(); - return md; - }); -} -#endif - -template (*make_call_promise)( - Transport*, CallArgs, NextPromiseFactory)> -grpc_channel_filter MakeConnectedFilter() { - // Create a vtable that contains both the legacy call methods (for filter - // stack based calls) and the new promise based method for creating - // promise based calls (the latter iff make_call_promise != nullptr). In - // this way the filter can be inserted into either kind of channel stack, - // and only if all the filters in the stack are promise based will the - // call be promise based. - auto make_call_wrapper = +[](grpc_channel_element* elem, CallArgs call_args, - NextPromiseFactory next) { - Transport* transport = - static_cast(elem->channel_data)->transport; - return make_call_promise(transport, std::move(call_args), std::move(next)); - }; - return { - connected_channel_start_transport_stream_op_batch, - make_call_promise != nullptr ? make_call_wrapper : nullptr, - /* init_call: */ nullptr, - connected_channel_start_transport_op, - sizeof(call_data), - connected_channel_init_call_elem, - set_pollset_or_pollset_set, - connected_channel_destroy_call_elem, - sizeof(channel_data), - connected_channel_init_channel_elem, - +[](grpc_channel_stack* channel_stack, grpc_channel_element* elem) { - // HACK(ctiller): increase call stack size for the channel to make - // space for channel data. We need a cleaner (but performant) way to - // do this, and I'm not sure what that is yet. This is only "safe" - // because call stacks place no additional data after the last call - // element, and the last call element MUST be the connected channel. - auto* transport = - static_cast(elem->channel_data)->transport; - if (transport->filter_stack_transport() != nullptr) { - channel_stack->call_stack_size += - transport->filter_stack_transport()->SizeOfStream(); - } - }, - connected_channel_destroy_channel_elem, - connected_channel_get_channel_info, - "connected", - }; -} - -ArenaPromise MakeClientTransportCallPromise( - Transport* transport, CallArgs call_args, NextPromiseFactory) { - auto spine = GetContext()->MakeCallSpine(std::move(call_args)); - transport->client_transport()->StartCall(CallHandler{spine}); - return spine->PullServerTrailingMetadata(); -} - -const grpc_channel_filter kClientPromiseBasedTransportFilter = - MakeConnectedFilter(); - -#ifdef GRPC_EXPERIMENT_IS_INCLUDED_PROMISE_BASED_CLIENT_CALL -const grpc_channel_filter kClientEmulatedFilter = - MakeConnectedFilter(); -#else -const grpc_channel_filter kClientEmulatedFilter = - MakeConnectedFilter(); -#endif - -#ifdef GRPC_EXPERIMENT_IS_INCLUDED_PROMISE_BASED_SERVER_CALL -const grpc_channel_filter kServerEmulatedFilter = - MakeConnectedFilter(); -#else -const grpc_channel_filter kServerEmulatedFilter = - MakeConnectedFilter(); -#endif - // noop filter for the v3 stack: placeholder for now because other code requires // we have a terminator. // TODO(ctiller): delete when v3 transition is complete. -const grpc_channel_filter kServerPromiseBasedTransportFilter = { +const grpc_channel_filter kPromiseBasedTransportFilter = { nullptr, - [](grpc_channel_element*, CallArgs, NextPromiseFactory) - -> ArenaPromise { Crash("not implemented"); }, - /* init_call: */ [](grpc_channel_element*, CallSpineInterface*) {}, connected_channel_start_transport_op, 0, nullptr, set_pollset_or_pollset_set, nullptr, sizeof(channel_data), - connected_channel_init_channel_elem, + +[](grpc_channel_element*, grpc_channel_element_args*) { + return absl::InternalError( + "Cannot use filter based stack with promise based transports"); + }, +[](grpc_channel_stack*, grpc_channel_element*) {}, connected_channel_destroy_channel_elem, connected_channel_get_channel_info, @@ -937,7 +301,6 @@ bool TransportSupportsServerPromiseBasedCalls(const ChannelArgs& args) { auto* transport = args.GetObject(); return transport->server_transport() != nullptr; } - } // namespace void RegisterConnectedChannel(CoreConfiguration::Builder* builder) { @@ -950,31 +313,30 @@ void RegisterConnectedChannel(CoreConfiguration::Builder* builder) { // Option 1, and our ideal: the transport supports promise based calls, // and so we simply use the transport directly. builder->channel_init() - ->RegisterFilter(GRPC_CLIENT_SUBCHANNEL, - &kClientPromiseBasedTransportFilter) + ->RegisterFilter(GRPC_CLIENT_SUBCHANNEL, &kPromiseBasedTransportFilter) .Terminal() .If(TransportSupportsClientPromiseBasedCalls); builder->channel_init() ->RegisterFilter(GRPC_CLIENT_DIRECT_CHANNEL, - &kClientPromiseBasedTransportFilter) + &kPromiseBasedTransportFilter) .Terminal() .If(TransportSupportsClientPromiseBasedCalls); builder->channel_init() - ->RegisterFilter(GRPC_SERVER_CHANNEL, &kServerPromiseBasedTransportFilter) + ->RegisterFilter(GRPC_SERVER_CHANNEL, &kPromiseBasedTransportFilter) .Terminal() .If(TransportSupportsServerPromiseBasedCalls); // Option 2: the transport does not support promise based calls. builder->channel_init() - ->RegisterFilter(GRPC_CLIENT_SUBCHANNEL, &kClientEmulatedFilter) + ->RegisterFilter(GRPC_CLIENT_SUBCHANNEL, &kConnectedFilter) .Terminal() .IfNot(TransportSupportsClientPromiseBasedCalls); builder->channel_init() - ->RegisterFilter(GRPC_CLIENT_DIRECT_CHANNEL, &kClientEmulatedFilter) + ->RegisterFilter(GRPC_CLIENT_DIRECT_CHANNEL, &kConnectedFilter) .Terminal() .IfNot(TransportSupportsClientPromiseBasedCalls); builder->channel_init() - ->RegisterFilter(GRPC_SERVER_CHANNEL, &kServerEmulatedFilter) + ->RegisterFilter(GRPC_SERVER_CHANNEL, &kConnectedFilter) .Terminal() .IfNot(TransportSupportsServerPromiseBasedCalls); } diff --git a/src/core/lib/channel/promise_based_filter.cc b/src/core/lib/channel/promise_based_filter.cc index 997d4e53c4e..e0b6e054c96 100644 --- a/src/core/lib/channel/promise_based_filter.cc +++ b/src/core/lib/channel/promise_based_filter.cc @@ -90,9 +90,6 @@ BaseCallData::BaseCallData( arena_(args->arena), call_combiner_(args->call_combiner), deadline_(args->deadline), - call_context_(flags & kFilterExaminesCallContext - ? arena_->New(nullptr) - : nullptr), server_initial_metadata_pipe_( flags & kFilterExaminesServerInitialMetadata ? arena_->New>(arena_) @@ -280,7 +277,7 @@ BaseCallData::Flusher::~Flusher() { }; for (size_t i = 1; i < release_.size(); i++) { auto* batch = release_[i]; - if (call_->call_context_ != nullptr && call_->call_context_->traced()) { + if (call_->call() != nullptr && call_->call()->traced()) { batch->is_traced = true; } if (grpc_trace_channel.enabled()) { @@ -300,7 +297,7 @@ BaseCallData::Flusher::~Flusher() { gpr_log(GPR_INFO, "FLUSHER:forward batch: %s", grpc_transport_stream_op_batch_string(release_[0], false).c_str()); } - if (call_->call_context_ != nullptr && call_->call_context_->traced()) { + if (call_->call() != nullptr && call_->call()->traced()) { release_[0]->is_traced = true; } grpc_call_next_op(call_->elem(), release_[0]); diff --git a/src/core/lib/channel/promise_based_filter.h b/src/core/lib/channel/promise_based_filter.h index a5325c32479..a95b643e9b2 100644 --- a/src/core/lib/channel/promise_based_filter.h +++ b/src/core/lib/channel/promise_based_filter.h @@ -75,12 +75,6 @@ namespace grpc_core { -// HACK: If a filter has this type as a base class it will be skipped in -// v3 filter stacks. This is a temporary measure to allow the v3 filter stack -// to be bought up whilst some tests inadvertently rely on hard to convert -// filters. -class HackyHackyHackySkipInV3FilterStacks {}; - class ChannelFilter { public: class Args { @@ -608,220 +602,6 @@ inline void InterceptClientToServerMessage(const NoInterceptor*, FilterCallData*, const CallArgs&) {} -template -inline auto InterceptClientToServerMessageHandler( - ServerMetadataHandle (Derived::Call::*fn)(const Message&), - typename Derived::Call* call, Derived*, PipeBasedCallSpine* call_spine) { - DCHECK(fn == &Derived::Call::OnClientToServerMessage); - return - [call, call_spine](MessageHandle msg) -> absl::optional { - auto return_md = call->OnClientToServerMessage(*msg); - if (return_md == nullptr) return std::move(msg); - call_spine->PushServerTrailingMetadata(std::move(return_md)); - return absl::nullopt; - }; -} - -template -inline auto InterceptClientToServerMessageHandler( - void (Derived::Call::*fn)(const Message&), typename Derived::Call* call, - Derived*, PipeBasedCallSpine*) { - DCHECK(fn == &Derived::Call::OnClientToServerMessage); - return [call](MessageHandle msg) -> absl::optional { - call->OnClientToServerMessage(*msg); - return std::move(msg); - }; -} - -template -inline auto InterceptClientToServerMessageHandler( - ServerMetadataHandle (Derived::Call::*fn)(const Message&, Derived*), - typename Derived::Call* call, Derived* channel, - PipeBasedCallSpine* call_spine) { - DCHECK(fn == &Derived::Call::OnClientToServerMessage); - return [call, call_spine, - channel](MessageHandle msg) -> absl::optional { - auto return_md = call->OnClientToServerMessage(*msg, channel); - if (return_md == nullptr) return std::move(msg); - call_spine->PushServerTrailingMetadata(std::move(return_md)); - return absl::nullopt; - }; -} - -template -inline auto InterceptClientToServerMessageHandler( - MessageHandle (Derived::Call::*fn)(MessageHandle, Derived*), - typename Derived::Call* call, Derived* channel, PipeBasedCallSpine*) { - DCHECK(fn == &Derived::Call::OnClientToServerMessage); - return [call, channel](MessageHandle msg) { - return call->OnClientToServerMessage(std::move(msg), channel); - }; -} - -template -inline auto InterceptClientToServerMessageHandler( - absl::StatusOr (Derived::Call::*fn)(MessageHandle, Derived*), - typename Derived::Call* call, Derived* channel, - PipeBasedCallSpine* call_spine) { - DCHECK(fn == &Derived::Call::OnClientToServerMessage); - return [call, call_spine, - channel](MessageHandle msg) -> absl::optional { - auto r = call->OnClientToServerMessage(std::move(msg), channel); - if (r.ok()) return std::move(*r); - call_spine->PushServerTrailingMetadata( - ServerMetadataFromStatus(r.status())); - return absl::nullopt; - }; -} - -template -inline void InterceptClientToServerMessage(HookFunction fn, - const NoInterceptor*, - typename Derived::Call* call, - Derived* channel, - PipeBasedCallSpine* call_spine) { - DCHECK(fn == &Derived::Call::OnClientToServerMessage); - call_spine->client_to_server_messages().receiver.InterceptAndMap( - InterceptClientToServerMessageHandler(fn, call, channel, call_spine)); -} - -template -inline void InterceptClientToServerMessage(HookFunction fn, - void (Derived::Call::*half_close)(), - typename Derived::Call* call, - Derived* channel, - PipeBasedCallSpine* call_spine) { - DCHECK(fn == &Derived::Call::OnClientToServerMessage); - DCHECK(half_close == &Derived::Call::OnClientToServerHalfClose); - call_spine->client_to_server_messages().receiver.InterceptAndMapWithHalfClose( - InterceptClientToServerMessageHandler(fn, call, channel, call_spine), - [call]() { call->OnClientToServerHalfClose(); }); -} - -template -inline void InterceptClientToServerMessage(const NoInterceptor*, - const NoInterceptor*, - typename Derived::Call*, Derived*, - PipeBasedCallSpine*) {} - -inline void InterceptClientInitialMetadata(const NoInterceptor*, void*, void*, - PipeBasedCallSpine*) {} - -template -inline void InterceptClientInitialMetadata( - void (Derived::Call::*fn)(ClientMetadata& md), typename Derived::Call* call, - Derived*, PipeBasedCallSpine* call_spine) { - DCHECK(fn == &Derived::Call::OnClientInitialMetadata); - call_spine->client_initial_metadata().receiver.InterceptAndMap( - [call](ClientMetadataHandle md) { - call->OnClientInitialMetadata(*md); - return md; - }); -} - -template -inline void InterceptClientInitialMetadata( - void (Derived::Call::*fn)(ClientMetadata& md, Derived* channel), - typename Derived::Call* call, Derived* channel, - PipeBasedCallSpine* call_spine) { - DCHECK(fn == &Derived::Call::OnClientInitialMetadata); - call_spine->client_initial_metadata().receiver.InterceptAndMap( - [call, channel](ClientMetadataHandle md) { - call->OnClientInitialMetadata(*md, channel); - return md; - }); -} - -template -inline void InterceptClientInitialMetadata( - ServerMetadataHandle (Derived::Call::*fn)(ClientMetadata& md), - typename Derived::Call* call, Derived*, PipeBasedCallSpine* call_spine) { - DCHECK(fn == &Derived::Call::OnClientInitialMetadata); - call_spine->client_initial_metadata().receiver.InterceptAndMap( - [call_spine, - call](ClientMetadataHandle md) -> absl::optional { - auto return_md = call->OnClientInitialMetadata(*md); - if (return_md == nullptr) return std::move(md); - call_spine->PushServerTrailingMetadata(std::move(return_md)); - return absl::nullopt; - }); -} - -template -inline void InterceptClientInitialMetadata( - ServerMetadataHandle (Derived::Call::*fn)(ClientMetadata& md, - Derived* channel), - typename Derived::Call* call, Derived* channel, - PipeBasedCallSpine* call_spine) { - DCHECK(fn == &Derived::Call::OnClientInitialMetadata); - call_spine->client_initial_metadata().receiver.InterceptAndMap( - [call_spine, call, channel]( - ClientMetadataHandle md) -> absl::optional { - auto return_md = call->OnClientInitialMetadata(*md, channel); - if (return_md == nullptr) return std::move(md); - call_spine->PushServerTrailingMetadata(std::move(return_md)); - return absl::nullopt; - }); -} - -template -inline void InterceptClientInitialMetadata( - absl::Status (Derived::Call::*fn)(ClientMetadata& md), - typename Derived::Call* call, Derived*, PipeBasedCallSpine* call_spine) { - DCHECK(fn == &Derived::Call::OnClientInitialMetadata); - call_spine->client_initial_metadata().receiver.InterceptAndMap( - [call_spine, - call](ClientMetadataHandle md) -> absl::optional { - auto status = call->OnClientInitialMetadata(*md); - if (status.ok()) return std::move(md); - call_spine->PushServerTrailingMetadata( - ServerMetadataFromStatus(status)); - return absl::nullopt; - }); -} - -template -inline void InterceptClientInitialMetadata( - absl::Status (Derived::Call::*fn)(ClientMetadata& md, Derived* channel), - typename Derived::Call* call, Derived* channel, - PipeBasedCallSpine* call_spine) { - DCHECK(fn == &Derived::Call::OnClientInitialMetadata); - call_spine->client_initial_metadata().receiver.InterceptAndMap( - [call_spine, call, channel]( - ClientMetadataHandle md) -> absl::optional { - auto status = call->OnClientInitialMetadata(*md, channel); - if (status.ok()) return std::move(md); - call_spine->PushServerTrailingMetadata( - ServerMetadataFromStatus(status)); - return absl::nullopt; - }); -} - -// Returning a promise that resolves to something that can be cast to -// ServerMetadataHandle also counts -template -absl::void_t( - std::declval>))> -InterceptClientInitialMetadata(Promise (Derived::Call::*promise_factory)( - ClientMetadata& md, Derived* channel), - typename Derived::Call* call, Derived* channel, - PipeBasedCallSpine* call_spine) { - DCHECK(promise_factory == &Derived::Call::OnClientInitialMetadata); - call_spine->client_initial_metadata().receiver.InterceptAndMap( - [call, call_spine, channel](ClientMetadataHandle md) { - ClientMetadata& md_ref = *md; - return Map(call->OnClientInitialMetadata(md_ref, channel), - [md = std::move(md), - call_spine](PromiseResult status) mutable - -> absl::optional { - if (IsStatusOk(status)) return std::move(md); - call_spine->PushServerTrailingMetadata( - StatusCast(std::move(status))); - return absl::nullopt; - }); - }); -} - template inline void InterceptServerInitialMetadata(const NoInterceptor*, void*, const CallArgs&) {} @@ -885,67 +665,6 @@ inline void InterceptServerInitialMetadata( }); } -inline void InterceptServerInitialMetadata(const NoInterceptor*, void*, void*, - CallSpineInterface*) {} - -template -inline void InterceptServerInitialMetadata( - void (Derived::Call::*fn)(ServerMetadata&), typename Derived::Call* call, - Derived*, PipeBasedCallSpine* call_spine) { - DCHECK(fn == &Derived::Call::OnServerInitialMetadata); - call_spine->server_initial_metadata().sender.InterceptAndMap( - [call](ServerMetadataHandle md) { - call->OnServerInitialMetadata(*md); - return md; - }); -} - -template -inline void InterceptServerInitialMetadata( - absl::Status (Derived::Call::*fn)(ServerMetadata&), - typename Derived::Call* call, Derived*, PipeBasedCallSpine* call_spine) { - DCHECK(fn == &Derived::Call::OnServerInitialMetadata); - call_spine->server_initial_metadata().sender.InterceptAndMap( - [call, call_spine]( - ServerMetadataHandle md) -> absl::optional { - auto status = call->OnServerInitialMetadata(*md); - if (status.ok()) return std::move(md); - call_spine->PushServerTrailingMetadata( - ServerMetadataFromStatus(status)); - return absl::nullopt; - }); -} - -template -inline void InterceptServerInitialMetadata( - void (Derived::Call::*fn)(ServerMetadata&, Derived*), - typename Derived::Call* call, Derived* channel, - PipeBasedCallSpine* call_spine) { - DCHECK(fn == &Derived::Call::OnServerInitialMetadata); - call_spine->server_initial_metadata().sender.InterceptAndMap( - [call, channel](ServerMetadataHandle md) { - call->OnServerInitialMetadata(*md, channel); - return md; - }); -} - -template -inline void InterceptServerInitialMetadata( - absl::Status (Derived::Call::*fn)(ServerMetadata&, Derived*), - typename Derived::Call* call, Derived* channel, - PipeBasedCallSpine* call_spine) { - DCHECK(fn == &Derived::Call::OnServerInitialMetadata); - call_spine->server_initial_metadata().sender.InterceptAndMap( - [call, call_spine, channel]( - ServerMetadataHandle md) -> absl::optional { - auto status = call->OnServerInitialMetadata(*md, channel); - if (status.ok()) return std::move(md); - call_spine->PullServerTrailingMetadata( - ServerMetadataFromStatus(status)); - return absl::nullopt; - }); -} - inline void InterceptServerToClientMessage(const NoInterceptor*, void*, const CallArgs&) {} @@ -1020,106 +739,6 @@ inline void InterceptServerToClientMessage( }); } -inline void InterceptServerToClientMessage(const NoInterceptor*, void*, void*, - CallSpineInterface*) {} - -template -inline void InterceptServerToClientMessage( - void (Derived::Call::*fn)(const Message&), typename Derived::Call* call, - Derived*, PipeBasedCallSpine* call_spine) { - DCHECK(fn == &Derived::Call::OnServerToClientMessage); - call_spine->server_to_client_messages().sender.InterceptAndMap( - [call](MessageHandle msg) -> absl::optional { - call->OnServerToClientMessage(*msg); - return std::move(msg); - }); -} - -template -inline void InterceptServerToClientMessage( - ServerMetadataHandle (Derived::Call::*fn)(const Message&), - typename Derived::Call* call, Derived*, PipeBasedCallSpine* call_spine) { - DCHECK(fn == &Derived::Call::OnServerToClientMessage); - call_spine->server_to_client_messages().sender.InterceptAndMap( - [call, call_spine](MessageHandle msg) -> absl::optional { - auto return_md = call->OnServerToClientMessage(*msg); - if (return_md == nullptr) return std::move(msg); - call_spine->PushServerTrailingMetadata(std::move(return_md)); - return absl::nullopt; - }); -} - -template -inline void InterceptServerToClientMessage( - ServerMetadataHandle (Derived::Call::*fn)(const Message&, Derived*), - typename Derived::Call* call, Derived* channel, - PipeBasedCallSpine* call_spine) { - DCHECK(fn == &Derived::Call::OnServerToClientMessage); - call_spine->server_to_client_messages().sender.InterceptAndMap( - [call, call_spine, - channel](MessageHandle msg) -> absl::optional { - auto return_md = call->OnServerToClientMessage(*msg, channel); - if (return_md == nullptr) return std::move(msg); - call_spine->PushServerTrailingMetadata(std::move(return_md)); - return absl::nullopt; - }); -} - -template -inline void InterceptServerToClientMessage( - MessageHandle (Derived::Call::*fn)(MessageHandle, Derived*), - typename Derived::Call* call, Derived* channel, - PipeBasedCallSpine* call_spine) { - DCHECK(fn == &Derived::Call::OnServerToClientMessage); - call_spine->server_to_client_messages().sender.InterceptAndMap( - [call, channel](MessageHandle msg) { - return call->OnServerToClientMessage(std::move(msg), channel); - }); -} - -template -inline void InterceptServerToClientMessage( - absl::StatusOr (Derived::Call::*fn)(MessageHandle, Derived*), - typename Derived::Call* call, Derived* channel, - PipeBasedCallSpine* call_spine) { - DCHECK(fn == &Derived::Call::OnServerToClientMessage); - call_spine->server_to_client_messages().sender.InterceptAndMap( - [call, call_spine, - channel](MessageHandle msg) -> absl::optional { - auto r = call->OnServerToClientMessage(std::move(msg), channel); - if (r.ok()) return std::move(*r); - call_spine->PushServerTrailingMetadata( - ServerMetadataFromStatus(r.status())); - return absl::nullopt; - }); -} - -inline void InterceptServerTrailingMetadata(const NoInterceptor*, void*, void*, - CallSpineInterface*) {} - -template -inline void InterceptServerTrailingMetadata( - void (Derived::Call::*)(ServerMetadata&), typename Derived::Call*, Derived*, - PipeBasedCallSpine*) { - gpr_log(GPR_ERROR, - "InterceptServerTrailingMetadata not available for call v2.5"); -} -template -inline void InterceptServerTrailingMetadata( - void (Derived::Call::*)(ServerMetadata&, Derived*), typename Derived::Call*, - Derived*, PipeBasedCallSpine*) { - gpr_log(GPR_ERROR, - "InterceptServerTrailingMetadata not available for call v2.5"); -} - -template -inline void InterceptServerTrailingMetadata( - absl::Status (Derived::Call::*)(ServerMetadata&), typename Derived::Call*, - Derived*, PipeBasedCallSpine*) { - gpr_log(GPR_ERROR, - "InterceptServerTrailingMetadata not available for call v2.5"); -} - inline void InterceptFinalize(const NoInterceptor*, void*, void*) {} template @@ -1221,29 +840,6 @@ template class ImplementChannelFilter : public ChannelFilter, public ImplementChannelFilterTag { public: - // Natively construct a v3 call. - void InitCall(CallSpineInterface* call_spine) { - typename Derived::Call* call = - GetContext() - ->ManagedNew>( - static_cast(this)); - auto* c = DownCast(call_spine); - auto* d = static_cast(this); - promise_filter_detail::InterceptClientInitialMetadata( - &Derived::Call::OnClientInitialMetadata, call, d, c); - promise_filter_detail::InterceptClientToServerMessage( - &Derived::Call::OnClientToServerMessage, - &Derived::Call::OnClientToServerHalfClose, call, d, c); - promise_filter_detail::InterceptServerInitialMetadata( - &Derived::Call::OnServerInitialMetadata, call, d, c); - promise_filter_detail::InterceptServerToClientMessage( - &Derived::Call::OnServerToClientMessage, call, d, c); - promise_filter_detail::InterceptServerTrailingMetadata( - &Derived::Call::OnServerTrailingMetadata, call, d, c); - promise_filter_detail::InterceptFinalize(&Derived::Call::OnFinalize, d, - call); - } - // Polyfill for the original promise scheme. // Allows writing v3 filters that work with v2 stacks. // (and consequently also v1 stacks since we can polyfill back to that too). @@ -1344,13 +940,14 @@ class BaseCallData : public Activity, private Wakeable { virtual void StartBatch(grpc_transport_stream_op_batch* batch) = 0; + Call* call() { return arena_->GetContext(); } + protected: class ScopedContext : public promise_detail::Context, public promise_detail::Context, public promise_detail::Context, public promise_detail::Context< - grpc_event_engine::experimental::EventEngine>, - public promise_detail::Context { + grpc_event_engine::experimental::EventEngine> { public: explicit ScopedContext(BaseCallData* call_data) : promise_detail::Context(call_data->arena_), @@ -1358,8 +955,7 @@ class BaseCallData : public Activity, private Wakeable { call_data->pollent_.load(std::memory_order_acquire)), promise_detail::Context(&call_data->finalization_), promise_detail::Context( - call_data->event_engine_), - promise_detail::Context(call_data->call_context_) {} + call_data->event_engine_) {} }; class Flusher { @@ -1705,7 +1301,6 @@ class BaseCallData : public Activity, private Wakeable { CallCombiner* const call_combiner_; const Timestamp deadline_; CallFinalization finalization_; - CallContext* call_context_ = nullptr; std::atomic pollent_{nullptr}; Pipe* const server_initial_metadata_pipe_; SendMessage* const send_message_; @@ -2061,67 +1656,15 @@ struct ChannelFilterWithFlagsMethods { // ChannelArgs channel_args, ChannelFilter::Args filter_args); // }; template -absl::enable_if_t< - std::is_base_of::value && - !std::is_base_of::value && - !std::is_base_of::value, - grpc_channel_filter> -MakePromiseBasedFilter(const char* name) { - using CallData = promise_filter_detail::CallData; - - return grpc_channel_filter{ - // start_transport_stream_op_batch - promise_filter_detail::BaseCallDataMethods::StartTransportStreamOpBatch, - // make_call_promise - promise_filter_detail::ChannelFilterMethods::MakeCallPromise, - nullptr, - // start_transport_op - promise_filter_detail::ChannelFilterMethods::StartTransportOp, - // sizeof_call_data - sizeof(CallData), - // init_call_elem - promise_filter_detail::CallDataFilterWithFlagsMethods< - CallData, kFlags>::InitCallElem, - // set_pollset_or_pollset_set - promise_filter_detail::BaseCallDataMethods::SetPollsetOrPollsetSet, - // destroy_call_elem - promise_filter_detail::CallDataFilterWithFlagsMethods< - CallData, kFlags>::DestroyCallElem, - // sizeof_channel_data - sizeof(F), - // init_channel_elem - promise_filter_detail::ChannelFilterWithFlagsMethods< - F, kFlags>::InitChannelElem, - // post_init_channel_elem - promise_filter_detail::ChannelFilterMethods::PostInitChannelElem, - // destroy_channel_elem - promise_filter_detail::ChannelFilterWithFlagsMethods< - F, kFlags>::DestroyChannelElem, - // get_channel_info - promise_filter_detail::ChannelFilterMethods::GetChannelInfo, - // name - name, - }; -} - -template -absl::enable_if_t< - std::is_base_of::value, - grpc_channel_filter> +absl::enable_if_t::value && + !std::is_base_of::value, + grpc_channel_filter> MakePromiseBasedFilter(const char* name) { using CallData = promise_filter_detail::CallData; return grpc_channel_filter{ // start_transport_stream_op_batch promise_filter_detail::BaseCallDataMethods::StartTransportStreamOpBatch, - // make_call_promise - promise_filter_detail::ChannelFilterMethods::MakeCallPromise, - [](grpc_channel_element* elem, CallSpineInterface*) { - GRPC_LOG_EVERY_N_SEC( - 1, GPR_ERROR, - "gRPC V3 call stack in use, with a filter ('%s') that is not V3.", - elem->filter->name); - }, // start_transport_op promise_filter_detail::ChannelFilterMethods::StartTransportOp, // sizeof_call_data @@ -2160,11 +1703,6 @@ MakePromiseBasedFilter(const char* name) { return grpc_channel_filter{ // start_transport_stream_op_batch promise_filter_detail::BaseCallDataMethods::StartTransportStreamOpBatch, - // make_call_promise - promise_filter_detail::ChannelFilterMethods::MakeCallPromise, - [](grpc_channel_element* elem, CallSpineInterface* args) { - static_cast(elem->channel_data)->InitCall(args); - }, // start_transport_op promise_filter_detail::ChannelFilterMethods::StartTransportOp, // sizeof_call_data diff --git a/src/core/lib/experiments/experiments.cc b/src/core/lib/experiments/experiments.cc index 8fc435e0f24..de736b7674c 100644 --- a/src/core/lib/experiments/experiments.cc +++ b/src/core/lib/experiments/experiments.cc @@ -76,24 +76,9 @@ const char* const additional_constraints_peer_state_based_framing = "{}"; const char* const description_pick_first_new = "New pick_first impl with memory reduction."; const char* const additional_constraints_pick_first_new = "{}"; -const char* const description_promise_based_client_call = - "If set, use the new gRPC promise based call code when it's appropriate " - "(ie when all filters in a stack are promise based)"; -const char* const additional_constraints_promise_based_client_call = "{}"; -const uint8_t required_experiments_promise_based_client_call[] = { - static_cast(grpc_core::kExperimentIdEventEngineClient), - static_cast(grpc_core::kExperimentIdEventEngineListener)}; -const char* const description_chaotic_good = - "If set, enable the chaotic good load transport (this is mostly here for " - "testing)"; -const char* const additional_constraints_chaotic_good = "{}"; -const uint8_t required_experiments_chaotic_good[] = { - static_cast(grpc_core::kExperimentIdPromiseBasedClientCall)}; const char* const description_promise_based_inproc_transport = "Use promises for the in-process transport."; const char* const additional_constraints_promise_based_inproc_transport = "{}"; -const uint8_t required_experiments_promise_based_inproc_transport[] = { - static_cast(grpc_core::kExperimentIdPromiseBasedClientCall)}; const char* const description_rstpit = "On RST_STREAM on a server, reduce MAX_CONCURRENT_STREAMS for a short " "duration"; @@ -131,12 +116,6 @@ 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 { @@ -175,16 +154,10 @@ const ExperimentMetadata g_experiment_metadata[] = { additional_constraints_peer_state_based_framing, nullptr, 0, false, true}, {"pick_first_new", description_pick_first_new, additional_constraints_pick_first_new, nullptr, 0, true, true}, - {"promise_based_client_call", description_promise_based_client_call, - additional_constraints_promise_based_client_call, - required_experiments_promise_based_client_call, 2, false, true}, - {"chaotic_good", description_chaotic_good, - additional_constraints_chaotic_good, required_experiments_chaotic_good, 1, - false, true}, {"promise_based_inproc_transport", description_promise_based_inproc_transport, - additional_constraints_promise_based_inproc_transport, - required_experiments_promise_based_inproc_transport, 1, false, false}, + additional_constraints_promise_based_inproc_transport, nullptr, 0, false, + false}, {"rstpit", description_rstpit, additional_constraints_rstpit, nullptr, 0, false, true}, {"schedule_cancellation_over_write", @@ -210,8 +183,6 @@ 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 @@ -270,24 +241,9 @@ const char* const additional_constraints_peer_state_based_framing = "{}"; const char* const description_pick_first_new = "New pick_first impl with memory reduction."; const char* const additional_constraints_pick_first_new = "{}"; -const char* const description_promise_based_client_call = - "If set, use the new gRPC promise based call code when it's appropriate " - "(ie when all filters in a stack are promise based)"; -const char* const additional_constraints_promise_based_client_call = "{}"; -const uint8_t required_experiments_promise_based_client_call[] = { - static_cast(grpc_core::kExperimentIdEventEngineClient), - static_cast(grpc_core::kExperimentIdEventEngineListener)}; -const char* const description_chaotic_good = - "If set, enable the chaotic good load transport (this is mostly here for " - "testing)"; -const char* const additional_constraints_chaotic_good = "{}"; -const uint8_t required_experiments_chaotic_good[] = { - static_cast(grpc_core::kExperimentIdPromiseBasedClientCall)}; const char* const description_promise_based_inproc_transport = "Use promises for the in-process transport."; const char* const additional_constraints_promise_based_inproc_transport = "{}"; -const uint8_t required_experiments_promise_based_inproc_transport[] = { - static_cast(grpc_core::kExperimentIdPromiseBasedClientCall)}; const char* const description_rstpit = "On RST_STREAM on a server, reduce MAX_CONCURRENT_STREAMS for a short " "duration"; @@ -325,12 +281,6 @@ 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 { @@ -369,16 +319,10 @@ const ExperimentMetadata g_experiment_metadata[] = { additional_constraints_peer_state_based_framing, nullptr, 0, false, true}, {"pick_first_new", description_pick_first_new, additional_constraints_pick_first_new, nullptr, 0, true, true}, - {"promise_based_client_call", description_promise_based_client_call, - additional_constraints_promise_based_client_call, - required_experiments_promise_based_client_call, 2, false, true}, - {"chaotic_good", description_chaotic_good, - additional_constraints_chaotic_good, required_experiments_chaotic_good, 1, - false, true}, {"promise_based_inproc_transport", description_promise_based_inproc_transport, - additional_constraints_promise_based_inproc_transport, - required_experiments_promise_based_inproc_transport, 1, false, false}, + additional_constraints_promise_based_inproc_transport, nullptr, 0, false, + false}, {"rstpit", description_rstpit, additional_constraints_rstpit, nullptr, 0, false, true}, {"schedule_cancellation_over_write", @@ -404,8 +348,6 @@ 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 @@ -464,24 +406,9 @@ const char* const additional_constraints_peer_state_based_framing = "{}"; const char* const description_pick_first_new = "New pick_first impl with memory reduction."; const char* const additional_constraints_pick_first_new = "{}"; -const char* const description_promise_based_client_call = - "If set, use the new gRPC promise based call code when it's appropriate " - "(ie when all filters in a stack are promise based)"; -const char* const additional_constraints_promise_based_client_call = "{}"; -const uint8_t required_experiments_promise_based_client_call[] = { - static_cast(grpc_core::kExperimentIdEventEngineClient), - static_cast(grpc_core::kExperimentIdEventEngineListener)}; -const char* const description_chaotic_good = - "If set, enable the chaotic good load transport (this is mostly here for " - "testing)"; -const char* const additional_constraints_chaotic_good = "{}"; -const uint8_t required_experiments_chaotic_good[] = { - static_cast(grpc_core::kExperimentIdPromiseBasedClientCall)}; const char* const description_promise_based_inproc_transport = "Use promises for the in-process transport."; const char* const additional_constraints_promise_based_inproc_transport = "{}"; -const uint8_t required_experiments_promise_based_inproc_transport[] = { - static_cast(grpc_core::kExperimentIdPromiseBasedClientCall)}; const char* const description_rstpit = "On RST_STREAM on a server, reduce MAX_CONCURRENT_STREAMS for a short " "duration"; @@ -519,12 +446,6 @@ 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 { @@ -563,16 +484,10 @@ const ExperimentMetadata g_experiment_metadata[] = { additional_constraints_peer_state_based_framing, nullptr, 0, false, true}, {"pick_first_new", description_pick_first_new, additional_constraints_pick_first_new, nullptr, 0, true, true}, - {"promise_based_client_call", description_promise_based_client_call, - additional_constraints_promise_based_client_call, - required_experiments_promise_based_client_call, 2, false, true}, - {"chaotic_good", description_chaotic_good, - additional_constraints_chaotic_good, required_experiments_chaotic_good, 1, - false, true}, {"promise_based_inproc_transport", description_promise_based_inproc_transport, - additional_constraints_promise_based_inproc_transport, - required_experiments_promise_based_inproc_transport, 1, false, false}, + additional_constraints_promise_based_inproc_transport, nullptr, 0, false, + false}, {"rstpit", description_rstpit, additional_constraints_rstpit, nullptr, 0, false, true}, {"schedule_cancellation_over_write", @@ -598,8 +513,6 @@ 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 eebbfe2afde..d5a42419fb8 100644 --- a/src/core/lib/experiments/experiments.h +++ b/src/core/lib/experiments/experiments.h @@ -76,8 +76,6 @@ inline bool IsMultipingEnabled() { return false; } inline bool IsPeerStateBasedFramingEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_PICK_FIRST_NEW inline bool IsPickFirstNewEnabled() { return true; } -inline bool IsPromiseBasedClientCallEnabled() { return false; } -inline bool IsChaoticGoodEnabled() { return false; } inline bool IsPromiseBasedInprocTransportEnabled() { return false; } inline bool IsRstpitEnabled() { return false; } inline bool IsScheduleCancellationOverWriteEnabled() { return false; } @@ -90,7 +88,6 @@ 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 @@ -114,8 +111,6 @@ inline bool IsMultipingEnabled() { return false; } inline bool IsPeerStateBasedFramingEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_PICK_FIRST_NEW inline bool IsPickFirstNewEnabled() { return true; } -inline bool IsPromiseBasedClientCallEnabled() { return false; } -inline bool IsChaoticGoodEnabled() { return false; } inline bool IsPromiseBasedInprocTransportEnabled() { return false; } inline bool IsRstpitEnabled() { return false; } inline bool IsScheduleCancellationOverWriteEnabled() { return false; } @@ -128,7 +123,6 @@ 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 @@ -152,8 +146,6 @@ inline bool IsMultipingEnabled() { return false; } inline bool IsPeerStateBasedFramingEnabled() { return false; } #define GRPC_EXPERIMENT_IS_INCLUDED_PICK_FIRST_NEW inline bool IsPickFirstNewEnabled() { return true; } -inline bool IsPromiseBasedClientCallEnabled() { return false; } -inline bool IsChaoticGoodEnabled() { return false; } inline bool IsPromiseBasedInprocTransportEnabled() { return false; } inline bool IsRstpitEnabled() { return false; } inline bool IsScheduleCancellationOverWriteEnabled() { return false; } @@ -167,7 +159,6 @@ 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 @@ -187,8 +178,6 @@ enum ExperimentIds { kExperimentIdMultiping, kExperimentIdPeerStateBasedFraming, kExperimentIdPickFirstNew, - kExperimentIdPromiseBasedClientCall, - kExperimentIdChaoticGood, kExperimentIdPromiseBasedInprocTransport, kExperimentIdRstpit, kExperimentIdScheduleCancellationOverWrite, @@ -199,7 +188,6 @@ enum ExperimentIds { kExperimentIdUnconstrainedMaxQuotaBufferSize, kExperimentIdWorkSerializerClearsTimeCache, kExperimentIdWorkSerializerDispatch, - kExperimentIdCallV3, kNumExperiments }; #define GRPC_EXPERIMENT_IS_INCLUDED_CALL_STATUS_OVERRIDE_ON_CANCELLATION @@ -262,14 +250,6 @@ inline bool IsPeerStateBasedFramingEnabled() { inline bool IsPickFirstNewEnabled() { return IsExperimentEnabled(kExperimentIdPickFirstNew); } -#define GRPC_EXPERIMENT_IS_INCLUDED_PROMISE_BASED_CLIENT_CALL -inline bool IsPromiseBasedClientCallEnabled() { - return IsExperimentEnabled(kExperimentIdPromiseBasedClientCall); -} -#define GRPC_EXPERIMENT_IS_INCLUDED_CHAOTIC_GOOD -inline bool IsChaoticGoodEnabled() { - return IsExperimentEnabled(kExperimentIdChaoticGood); -} #define GRPC_EXPERIMENT_IS_INCLUDED_PROMISE_BASED_INPROC_TRANSPORT inline bool IsPromiseBasedInprocTransportEnabled() { return IsExperimentEnabled(kExperimentIdPromiseBasedInprocTransport); @@ -310,10 +290,6 @@ 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 5d2678f99d2..638e9a9571c 100644 --- a/src/core/lib/experiments/experiments.yaml +++ b/src/core/lib/experiments/experiments.yaml @@ -47,13 +47,6 @@ expiry: 2024/08/01 owner: vigneshbabu@google.com test_tags: [] -- name: call_v3 - description: Promise-based call version 3. - 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 @@ -61,13 +54,6 @@ owner: alishananda@google.com test_tags: [] allow_in_fuzzing_config: false -- name: chaotic_good - description: - If set, enable the chaotic good load transport (this is mostly here for testing) - expiry: 2024/09/09 - owner: ctiller@google.com - requires: [promise_based_client_call] - test_tags: [core_end2end_test] - name: client_privacy description: If set, client privacy @@ -154,14 +140,6 @@ expiry: 2024/07/30 owner: roth@google.com test_tags: ["lb_unit_test", "cpp_lb_end2end_test", "xds_end2end_test"] -- name: promise_based_client_call - description: - If set, use the new gRPC promise based call code when it's appropriate - (ie when all filters in a stack are promise based) - expiry: 2024/06/14 - owner: ctiller@google.com - test_tags: ["core_end2end_test", "lame_client_test"] - requires: ["event_engine_listener", "event_engine_client"] - name: promise_based_inproc_transport description: Use promises for the in-process transport. @@ -169,7 +147,6 @@ owner: ctiller@google.com test_tags: [] allow_in_fuzzing_config: false # experiment currently crashes if enabled - requires: [promise_based_client_call] - name: rstpit description: On RST_STREAM on a server, reduce MAX_CONCURRENT_STREAMS for a short duration diff --git a/src/core/lib/gprpp/dual_ref_counted.h b/src/core/lib/gprpp/dual_ref_counted.h index 38365db381b..a7482577eff 100644 --- a/src/core/lib/gprpp/dual_ref_counted.h +++ b/src/core/lib/gprpp/dual_ref_counted.h @@ -335,6 +335,7 @@ class DualRefCounted : public Impl { gpr_log(GPR_INFO, "%s:%p weak_ref %d -> %d; (refs=%d)", trace_, this, weak_refs, weak_refs + 1, strong_refs); } + if (strong_refs == 0) CHECK_NE(weak_refs, 0u); #else refs_.fetch_add(MakeRefPair(0, 1), std::memory_order_relaxed); #endif @@ -351,6 +352,7 @@ class DualRefCounted : public Impl { this, location.file(), location.line(), weak_refs, weak_refs + 1, strong_refs, reason); } + if (strong_refs == 0) CHECK_NE(weak_refs, 0u); #else // Use conditionally-important parameters (void)location; diff --git a/src/core/lib/gprpp/ref_counted.h b/src/core/lib/gprpp/ref_counted.h index 7d9f8c4d11d..8e85d3448d8 100644 --- a/src/core/lib/gprpp/ref_counted.h +++ b/src/core/lib/gprpp/ref_counted.h @@ -246,6 +246,15 @@ struct UnrefCallDtor { } }; +// Call the Destroy method on the object. This is useful when the object +// needs precise control of how it's deallocated. +struct UnrefCallDestroy { + template + void operator()(T* p) const { + p->Destroy(); + } +}; + // A base class for reference-counted objects. // New objects should be created via new and start with a refcount of 1. // When the refcount reaches 0, executes the specified UnrefBehavior. diff --git a/src/core/lib/gprpp/single_set_ptr.h b/src/core/lib/gprpp/single_set_ptr.h index 369e777bd23..a8e1f278ba4 100644 --- a/src/core/lib/gprpp/single_set_ptr.h +++ b/src/core/lib/gprpp/single_set_ptr.h @@ -63,17 +63,19 @@ class SingleSetPtr { void Reset() { Delete(p_.exchange(nullptr, std::memory_order_acq_rel)); } bool is_set() const { - T* p = p_.load(std::memory_order_acquire); + T* p = Get(); return p != nullptr; } + T* Get() const { return p_.load(std::memory_order_acquire); } + T* operator->() const { - T* p = p_.load(std::memory_order_acquire); + T* p = Get(); DCHECK_NE(p, nullptr); return p; } - T& operator*() const { return *operator->(); } + T& operator*() const { return *Get(); } private: static void Delete(T* p) { diff --git a/src/core/lib/promise/cancel_callback.h b/src/core/lib/promise/cancel_callback.h index 92ac2019d4f..b02b2a45ff2 100644 --- a/src/core/lib/promise/cancel_callback.h +++ b/src/core/lib/promise/cancel_callback.h @@ -80,6 +80,20 @@ auto OnCancel(MainFn main_fn, CancelFn cancel_fn) { }; } +// Similar to OnCancel, but returns a factory that uses main_fn to construct the +// resulting promise. If the factory is dropped without being called, cancel_fn +// is called. +template +auto OnCancelFactory(MainFn main_fn, CancelFn cancel_fn) { + return [on_cancel = + cancel_callback_detail::Handler(std::move(cancel_fn)), + main_fn = std::move(main_fn)]() mutable { + auto r = main_fn(); + on_cancel.Done(); + return r; + }; +}; + } // namespace grpc_core #endif // GRPC_SRC_CORE_LIB_PROMISE_CANCEL_CALLBACK_H diff --git a/src/core/lib/promise/party.h b/src/core/lib/promise/party.h index d2467168c26..9b0aedd2fe9 100644 --- a/src/core/lib/promise/party.h +++ b/src/core/lib/promise/party.h @@ -647,8 +647,9 @@ template void Party::BulkSpawner::Spawn(absl::string_view name, Factory promise_factory, OnComplete on_complete) { if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_DEBUG, "%s[bulk_spawn] On %p queue %s", - party_->DebugTag().c_str(), this, std::string(name).c_str()); + gpr_log(GPR_INFO, "%s[bulk_spawn] On %p queue %s (%" PRIdPTR " bytes)", + party_->DebugTag().c_str(), this, std::string(name).c_str(), + sizeof(ParticipantImpl)); } participants_[num_participants_++] = new ParticipantImpl( name, std::move(promise_factory), std::move(on_complete)); diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc index 8d76a32460c..bd62362559c 100644 --- a/src/core/lib/surface/call.cc +++ b/src/core/lib/surface/call.cc @@ -25,8 +25,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -66,6 +68,7 @@ #include "src/core/lib/gprpp/cpp_impl_of.h" #include "src/core/lib/gprpp/crash.h" #include "src/core/lib/gprpp/debug_location.h" +#include "src/core/lib/gprpp/match.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" @@ -76,10 +79,10 @@ #include "src/core/lib/promise/activity.h" #include "src/core/lib/promise/all_ok.h" #include "src/core/lib/promise/arena_promise.h" +#include "src/core/lib/promise/cancel_callback.h" #include "src/core/lib/promise/context.h" #include "src/core/lib/promise/latch.h" #include "src/core/lib/promise/map.h" -#include "src/core/lib/promise/party.h" #include "src/core/lib/promise/pipe.h" #include "src/core/lib/promise/poll.h" #include "src/core/lib/promise/race.h" @@ -94,9 +97,8 @@ #include "src/core/lib/surface/channel.h" #include "src/core/lib/surface/completion_queue.h" #include "src/core/lib/surface/validate_metadata.h" -#include "src/core/lib/surface/wait_for_cq_end_op.h" -#include "src/core/lib/transport/batch_builder.h" #include "src/core/lib/transport/error_utils.h" +#include "src/core/lib/transport/metadata.h" #include "src/core/lib/transport/metadata_batch.h" #include "src/core/lib/transport/transport.h" #include "src/core/server/server_interface.h" @@ -121,6 +123,15 @@ using GrpcClosure = Closure; /////////////////////////////////////////////////////////////////////////////// // Call +Call::Call(bool is_client, Timestamp send_deadline, RefCountedPtr arena, + grpc_event_engine::experimental::EventEngine* event_engine) + : arena_(std::move(arena)), + send_deadline_(send_deadline), + is_client_(is_client), + event_engine_(event_engine) { + arena_->SetContext(this); +} + Call::ParentCall* Call::GetOrCreateParentCall() { ParentCall* p = parent_call_.load(std::memory_order_acquire); if (p == nullptr) { @@ -283,15 +294,15 @@ void Call::ProcessIncomingInitialMetadata(grpc_metadata_batch& md) { Slice* peer_string = md.get_pointer(PeerString()); if (peer_string != nullptr) SetPeerString(peer_string->Ref()); - incoming_compression_algorithm_ = - md.Take(GrpcEncodingMetadata()).value_or(GRPC_COMPRESS_NONE); + SetIncomingCompressionAlgorithm( + md.Take(GrpcEncodingMetadata()).value_or(GRPC_COMPRESS_NONE)); encodings_accepted_by_peer_ = md.Take(GrpcAcceptEncodingMetadata()) .value_or(CompressionAlgorithmSet{GRPC_COMPRESS_NONE}); const grpc_compression_options copts = compression_options(); const grpc_compression_algorithm compression_algorithm = - incoming_compression_algorithm_; + incoming_compression_algorithm(); if (GPR_UNLIKELY( !CompressionAlgorithmSet::FromUint32(copts.enabled_algorithms_bitset) .IsSet(compression_algorithm))) { @@ -366,3249 +377,42 @@ void Call::ResetDeadline() { void Call::Run() { ApplicationCallbackExecCtx callback_exec_ctx; ExecCtx exec_ctx; + if (grpc_call_trace.enabled()) { + LOG(INFO) << "call deadline expired " + << GRPC_DUMP_ARGS(Timestamp::Now(), send_deadline_); + } CancelWithError(grpc_error_set_int( absl::DeadlineExceededError("Deadline Exceeded"), StatusIntProperty::kRpcStatus, GRPC_STATUS_DEADLINE_EXCEEDED)); InternalUnref("deadline[run]"); } -/////////////////////////////////////////////////////////////////////////////// -// ChannelBasedCall -// TODO(ctiller): once we remove the v2 client code this can be folded into -// FilterStackCall - -class ChannelBasedCall : public Call { - protected: - ChannelBasedCall(RefCountedPtr arena, bool is_client, - Timestamp send_deadline, RefCountedPtr channel) - : Call(is_client, send_deadline, channel->event_engine()), - arena_(std::move(arena)), - channel_(std::move(channel)) { - DCHECK_NE(arena_.get(), nullptr); - } - - Arena* arena() final { return arena_.get(); } - - char* GetPeer() final { - Slice peer_slice = GetPeerString(); - if (!peer_slice.empty()) { - absl::string_view peer_string_view = peer_slice.as_string_view(); - char* peer_string = - static_cast(gpr_malloc(peer_string_view.size() + 1)); - memcpy(peer_string, peer_string_view.data(), peer_string_view.size()); - peer_string[peer_string_view.size()] = '\0'; - return peer_string; - } - char* peer_string = grpc_channel_get_target(channel_->c_ptr()); - if (peer_string != nullptr) return peer_string; - return gpr_strdup("unknown"); - } - - grpc_event_engine::experimental::EventEngine* event_engine() const override { - return channel_->event_engine(); - } - - grpc_compression_options compression_options() override { - return channel_->compression_options(); - } - - void DeleteThis() { - RefCountedPtr channel = std::move(channel_); - RefCountedPtr arena = arena_; - this->~ChannelBasedCall(); - } - - Channel* channel() const { return channel_.get(); } - - // Non-virtual arena accessor -- needed by PipeBasedCall - Arena* GetArena() { return arena_.get(); } - - private: - const RefCountedPtr arena_; - RefCountedPtr channel_; -}; +} // namespace grpc_core /////////////////////////////////////////////////////////////////////////////// -// FilterStackCall -// To be removed once promise conversion is complete - -class FilterStackCall final : public ChannelBasedCall { - public: - ~FilterStackCall() override { - gpr_free(static_cast(const_cast(final_info_.error_string))); - } - - bool Completed() override { - return gpr_atm_acq_load(&received_final_op_atm_) != 0; - } - - // TODO(ctiller): return absl::StatusOr>? - static grpc_error_handle Create(grpc_call_create_args* args, - grpc_call** out_call); - - static Call* FromTopElem(grpc_call_element* elem) { - return FromCallStack(grpc_call_stack_from_top_element(elem)); - } - - grpc_call_stack* call_stack() override { - return reinterpret_cast( - reinterpret_cast(this) + - GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(*this))); - } - - grpc_call_element* call_elem(size_t idx) { - return grpc_call_stack_element(call_stack(), idx); - } - - CallCombiner* call_combiner() { return &call_combiner_; } - - void CancelWithError(grpc_error_handle error) override; - void SetCompletionQueue(grpc_completion_queue* cq) override; - grpc_call_error StartBatch(const grpc_op* ops, size_t nops, void* notify_tag, - bool is_notify_tag_closure) override; - void ExternalRef() override { ext_ref_.Ref(); } - void ExternalUnref() override; - void InternalRef(const char* reason) override { - GRPC_CALL_STACK_REF(call_stack(), reason); - } - void InternalUnref(const char* reason) override { - GRPC_CALL_STACK_UNREF(call_stack(), reason); - } - - bool is_trailers_only() const override { - bool result = is_trailers_only_; - DCHECK(!result || recv_initial_metadata_.TransportSize() == 0); - return result; - } - - bool failed_before_recv_message() const override { - return call_failed_before_recv_message_; - } - - absl::string_view GetServerAuthority() const override { - const Slice* authority_metadata = - recv_initial_metadata_.get_pointer(HttpAuthorityMetadata()); - if (authority_metadata == nullptr) return ""; - return authority_metadata->as_string_view(); - } - - static size_t InitialSizeEstimate() { - return sizeof(FilterStackCall) + - sizeof(BatchControl) * kMaxConcurrentBatches; - } - - private: - class ScopedContext : public promise_detail::Context { - public: - explicit ScopedContext(FilterStackCall* call) - : promise_detail::Context(call->arena()) {} - }; - - static constexpr gpr_atm kRecvNone = 0; - static constexpr gpr_atm kRecvInitialMetadataFirst = 1; - - enum class PendingOp { - kRecvMessage, - kRecvInitialMetadata, - kRecvTrailingMetadata, - kSends - }; - static intptr_t PendingOpMask(PendingOp op) { - return static_cast(1) << static_cast(op); - } - static std::string PendingOpString(intptr_t pending_ops) { - std::vector pending_op_strings; - if (pending_ops & PendingOpMask(PendingOp::kRecvMessage)) { - pending_op_strings.push_back("kRecvMessage"); - } - if (pending_ops & PendingOpMask(PendingOp::kRecvInitialMetadata)) { - pending_op_strings.push_back("kRecvInitialMetadata"); - } - if (pending_ops & PendingOpMask(PendingOp::kRecvTrailingMetadata)) { - pending_op_strings.push_back("kRecvTrailingMetadata"); - } - if (pending_ops & PendingOpMask(PendingOp::kSends)) { - pending_op_strings.push_back("kSends"); - } - return absl::StrCat("{", absl::StrJoin(pending_op_strings, ","), "}"); - } - struct BatchControl { - FilterStackCall* call_ = nullptr; - CallTracerAnnotationInterface* call_tracer_ = nullptr; - grpc_transport_stream_op_batch op_; - // Share memory for cq_completion and notify_tag as they are never needed - // simultaneously. Each byte used in this data structure count as six bytes - // per call, so any savings we can make are worthwhile, - - // We use notify_tag to determine whether or not to send notification to the - // completion queue. Once we've made that determination, we can reuse the - // memory for cq_completion. - union { - grpc_cq_completion cq_completion; - struct { - // Any given op indicates completion by either (a) calling a closure or - // (b) sending a notification on the call's completion queue. If - // \a is_closure is true, \a tag indicates a closure to be invoked; - // otherwise, \a tag indicates the tag to be used in the notification to - // be sent to the completion queue. - void* tag; - bool is_closure; - } notify_tag; - } completion_data_; - grpc_closure start_batch_; - grpc_closure finish_batch_; - std::atomic ops_pending_{0}; - AtomicError batch_error_; - void set_pending_ops(uintptr_t ops) { - ops_pending_.store(ops, std::memory_order_release); - } - bool completed_batch_step(PendingOp op) { - auto mask = PendingOpMask(op); - auto r = ops_pending_.fetch_sub(mask, std::memory_order_acq_rel); - if (grpc_call_trace.enabled()) { - gpr_log(GPR_DEBUG, "BATCH:%p COMPLETE:%s REMAINING:%s (tag:%p)", this, - PendingOpString(mask).c_str(), - PendingOpString(r & ~mask).c_str(), - completion_data_.notify_tag.tag); - } - CHECK_NE((r & mask), 0); - return r == mask; - } - - void PostCompletion(); - void FinishStep(PendingOp op); - void ProcessDataAfterMetadata(); - void ReceivingStreamReady(grpc_error_handle error); - void ReceivingInitialMetadataReady(grpc_error_handle error); - void ReceivingTrailingMetadataReady(grpc_error_handle error); - void FinishBatch(grpc_error_handle error); - }; - - 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) { - GetArena()->SetContext(this); - } - - static void ReleaseCall(void* call, grpc_error_handle); - static void DestroyCall(void* call, grpc_error_handle); - - static FilterStackCall* FromCallStack(grpc_call_stack* call_stack) { - return reinterpret_cast( - reinterpret_cast(call_stack) - - GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(FilterStackCall))); - } - - void ExecuteBatch(grpc_transport_stream_op_batch* batch, - grpc_closure* start_batch_closure); - void SetFinalStatus(grpc_error_handle error); - BatchControl* ReuseOrAllocateBatchControl(const grpc_op* ops); - bool PrepareApplicationMetadata(size_t count, grpc_metadata* metadata, - bool is_trailing); - void PublishAppMetadata(grpc_metadata_batch* b, bool is_trailing); - void RecvInitialFilter(grpc_metadata_batch* b); - void RecvTrailingFilter(grpc_metadata_batch* b, - grpc_error_handle batch_error); - - RefCount ext_ref_; - CallCombiner call_combiner_; - grpc_completion_queue* cq_; - grpc_polling_entity pollent_; - - /// has grpc_call_unref been called - bool destroy_called_ = false; - // Trailers-only response status - bool is_trailers_only_ = false; - /// which ops are in-flight - bool sent_initial_metadata_ = false; - bool sending_message_ = false; - bool sent_final_op_ = false; - bool received_initial_metadata_ = false; - bool receiving_message_ = false; - bool requested_final_op_ = false; - gpr_atm received_final_op_atm_ = 0; - - BatchControl* active_batches_[kMaxConcurrentBatches] = {}; - grpc_transport_stream_op_batch_payload stream_op_payload_; - - // first idx: is_receiving, second idx: is_trailing - grpc_metadata_batch send_initial_metadata_; - grpc_metadata_batch send_trailing_metadata_; - grpc_metadata_batch recv_initial_metadata_; - grpc_metadata_batch recv_trailing_metadata_; - - // Buffered read metadata waiting to be returned to the application. - // Element 0 is initial metadata, element 1 is trailing metadata. - grpc_metadata_array* buffered_metadata_[2] = {}; - - // Call data useful used for reporting. Only valid after the call has - // completed - grpc_call_final_info final_info_; - - SliceBuffer send_slice_buffer_; - absl::optional receiving_slice_buffer_; - uint32_t receiving_stream_flags_; - - bool call_failed_before_recv_message_ = false; - grpc_byte_buffer** receiving_buffer_ = nullptr; - grpc_slice receiving_slice_ = grpc_empty_slice(); - grpc_closure receiving_stream_ready_; - grpc_closure receiving_initial_metadata_ready_; - grpc_closure receiving_trailing_metadata_ready_; - // Status about operation of call - bool sent_server_trailing_metadata_ = false; - gpr_atm cancelled_with_error_ = 0; - - grpc_closure release_call_; - - union { - struct { - grpc_status_code* status; - grpc_slice* status_details; - const char** error_string; - } client; - struct { - int* cancelled; - // backpointer to owning server if this is a server side call. - ServerInterface* core_server; - } server; - } final_op_; - AtomicError status_error_; - - // recv_state can contain one of the following values: - // RECV_NONE : : no initial metadata and messages received - // RECV_INITIAL_METADATA_FIRST : received initial metadata first - // a batch_control* : received messages first - - // +------1------RECV_NONE------3-----+ - // | | - // | | - // v v - // RECV_INITIAL_METADATA_FIRST receiving_stream_ready_bctlp - // | ^ | ^ - // | | | | - // +-----2-----+ +-----4-----+ - - // For 1, 4: See receiving_initial_metadata_ready() function - // For 2, 3: See receiving_stream_ready() function - gpr_atm recv_state_ = 0; -}; - -grpc_error_handle FilterStackCall::Create(grpc_call_create_args* args, - grpc_call** out_call) { - Channel* channel = args->channel.get(); - - auto add_init_error = [](grpc_error_handle* composite, - grpc_error_handle new_err) { - if (new_err.ok()) return; - if (composite->ok()) { - *composite = GRPC_ERROR_CREATE("Call creation failed"); - } - *composite = grpc_error_add_child(*composite, new_err); - }; - - FilterStackCall* call; - grpc_error_handle error; - grpc_channel_stack* channel_stack = channel->channel_stack(); - size_t call_alloc_size = - GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(FilterStackCall)) + - channel_stack->call_stack_size; - - 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); - *out_call = call->c_ptr(); - grpc_slice path = grpc_empty_slice(); - ScopedContext ctx(call); - if (call->is_client()) { - call->final_op_.client.status_details = nullptr; - call->final_op_.client.status = nullptr; - call->final_op_.client.error_string = nullptr; - global_stats().IncrementClientCallsCreated(); - path = CSliceRef(args->path->c_slice()); - call->send_initial_metadata_.Set(HttpPathMetadata(), - std::move(*args->path)); - if (args->authority.has_value()) { - call->send_initial_metadata_.Set(HttpAuthorityMetadata(), - std::move(*args->authority)); - } - call->send_initial_metadata_.Set( - GrpcRegisteredMethod(), reinterpret_cast(static_cast( - args->registered_method))); - channel_stack->stats_plugin_group->AddClientCallTracers( - Slice(CSliceRef(path)), args->registered_method, call->GetArena()); - } else { - global_stats().IncrementServerCallsCreated(); - call->final_op_.server.cancelled = nullptr; - call->final_op_.server.core_server = args->server; - // TODO(yashykt): In the future, we want to also enable stats and trace - // collecting from when the call is created at the transport. The idea is - // that the transport would create the call tracer and pass it in as part of - // the metadata. - // TODO(yijiem): OpenCensus and internal Census is still using this way to - // set server call tracer. We need to refactor them to stats plugins - // (including removing the client channel filters). - if (args->server != nullptr && - args->server->server_call_tracer_factory() != nullptr) { - auto* server_call_tracer = - args->server->server_call_tracer_factory()->CreateNewServerCallTracer( - arena.get(), args->server->channel_args()); - if (server_call_tracer != nullptr) { - // Note that we are setting both - // GRPC_CONTEXT_CALL_TRACER_ANNOTATION_INTERFACE and - // GRPC_CONTEXT_CALL_TRACER as a matter of convenience. In the future - // promise-based world, we would just a single tracer object for each - // stack (call, subchannel_call, server_call.) - arena->SetContext(server_call_tracer); - arena->SetContext(server_call_tracer); - } - } - channel_stack->stats_plugin_group->AddServerCallTracers(arena.get()); - } - - Call* parent = Call::FromC(args->parent); - if (parent != nullptr) { - add_init_error(&error, absl_status_to_grpc_error(call->InitParent( - parent, args->propagation_mask))); - } - // initial refcount dropped by grpc_call_unref - grpc_call_element_args call_args = { - call->call_stack(), args->server_transport_data, path, - call->start_time(), call->send_deadline(), call->arena(), - &call->call_combiner_}; - add_init_error(&error, grpc_call_stack_init(channel_stack, 1, DestroyCall, - call, &call_args)); - // Publish this call to parent only after the call stack has been initialized. - if (parent != nullptr) { - call->PublishToParent(parent); - } - - if (!error.ok()) { - call->CancelWithError(error); - } - if (args->cq != nullptr) { - CHECK(args->pollset_set_alternative == nullptr) - << "Only one of 'cq' and 'pollset_set_alternative' should be " - "non-nullptr."; - GRPC_CQ_INTERNAL_REF(args->cq, "bind"); - call->pollent_ = - grpc_polling_entity_create_from_pollset(grpc_cq_pollset(args->cq)); - } - if (args->pollset_set_alternative != nullptr) { - call->pollent_ = grpc_polling_entity_create_from_pollset_set( - args->pollset_set_alternative); - } - if (!grpc_polling_entity_is_empty(&call->pollent_)) { - grpc_call_stack_set_pollset_or_pollset_set(call->call_stack(), - &call->pollent_); - } - - if (call->is_client()) { - channelz::ChannelNode* channelz_channel = channel->channelz_node(); - if (channelz_channel != nullptr) { - channelz_channel->RecordCallStarted(); - } - } else if (call->final_op_.server.core_server != nullptr) { - channelz::ServerNode* channelz_node = - call->final_op_.server.core_server->channelz_node(); - if (channelz_node != nullptr) { - channelz_node->RecordCallStarted(); - } - } - - if (args->send_deadline != Timestamp::InfFuture()) { - call->UpdateDeadline(args->send_deadline); - } - - CSliceUnref(path); - - return error; -} - -void FilterStackCall::SetCompletionQueue(grpc_completion_queue* cq) { - CHECK(cq); - - if (grpc_polling_entity_pollset_set(&pollent_) != nullptr) { - Crash("A pollset_set is already registered for this call."); - } - cq_ = cq; - GRPC_CQ_INTERNAL_REF(cq, "bind"); - pollent_ = grpc_polling_entity_create_from_pollset(grpc_cq_pollset(cq)); - grpc_call_stack_set_pollset_or_pollset_set(call_stack(), &pollent_); -} - -void FilterStackCall::ReleaseCall(void* call, grpc_error_handle /*error*/) { - static_cast(call)->DeleteThis(); -} - -void FilterStackCall::DestroyCall(void* call, grpc_error_handle /*error*/) { - auto* c = static_cast(call); - c->recv_initial_metadata_.Clear(); - c->recv_trailing_metadata_.Clear(); - c->receiving_slice_buffer_.reset(); - ParentCall* pc = c->parent_call(); - if (pc != nullptr) { - pc->~ParentCall(); - } - if (c->cq_) { - GRPC_CQ_INTERNAL_UNREF(c->cq_, "bind"); - } - - grpc_error_handle status_error = c->status_error_.get(); - grpc_error_get_status(status_error, c->send_deadline(), - &c->final_info_.final_status, nullptr, nullptr, - &(c->final_info_.error_string)); - c->status_error_.set(absl::OkStatus()); - c->final_info_.stats.latency = - gpr_cycle_counter_sub(gpr_get_cycle_counter(), c->start_time()); - grpc_call_stack_destroy(c->call_stack(), &c->final_info_, - GRPC_CLOSURE_INIT(&c->release_call_, ReleaseCall, c, - grpc_schedule_on_exec_ctx)); -} - -void FilterStackCall::ExternalUnref() { - if (GPR_LIKELY(!ext_ref_.Unref())) return; - - ApplicationCallbackExecCtx callback_exec_ctx; - ExecCtx exec_ctx; - - GRPC_API_TRACE("grpc_call_unref(c=%p)", 1, (this)); - - MaybeUnpublishFromParent(); - - CHECK(!destroy_called_); - destroy_called_ = true; - bool cancel = gpr_atm_acq_load(&received_final_op_atm_) == 0; - if (cancel) { - CancelWithError(absl::CancelledError()); - } else { - // Unset the call combiner cancellation closure. This has the - // effect of scheduling the previously set cancellation closure, if - // any, so that it can release any internal references it may be - // holding to the call stack. - call_combiner_.SetNotifyOnCancel(nullptr); - } - InternalUnref("destroy"); -} - -// start_batch_closure points to a caller-allocated closure to be used -// for entering the call combiner. -void FilterStackCall::ExecuteBatch(grpc_transport_stream_op_batch* batch, - grpc_closure* start_batch_closure) { - // This is called via the call combiner to start sending a batch down - // the filter stack. - auto execute_batch_in_call_combiner = [](void* arg, grpc_error_handle) { - grpc_transport_stream_op_batch* batch = - static_cast(arg); - auto* call = - static_cast(batch->handler_private.extra_arg); - grpc_call_element* elem = call->call_elem(0); - GRPC_CALL_LOG_OP(GPR_INFO, elem, batch); - elem->filter->start_transport_stream_op_batch(elem, batch); - }; - batch->handler_private.extra_arg = this; - GRPC_CLOSURE_INIT(start_batch_closure, execute_batch_in_call_combiner, batch, - grpc_schedule_on_exec_ctx); - GRPC_CALL_COMBINER_START(call_combiner(), start_batch_closure, - absl::OkStatus(), "executing batch"); -} - -namespace { -struct CancelState { - FilterStackCall* call; - grpc_closure start_batch; - grpc_closure finish_batch; -}; -} // namespace - -// The on_complete callback used when sending a cancel_stream batch down -// the filter stack. Yields the call combiner when the batch is done. -static void done_termination(void* arg, grpc_error_handle /*error*/) { - CancelState* state = static_cast(arg); - GRPC_CALL_COMBINER_STOP(state->call->call_combiner(), - "on_complete for cancel_stream op"); - state->call->InternalUnref("termination"); - delete state; -} - -void FilterStackCall::CancelWithError(grpc_error_handle error) { - if (!gpr_atm_rel_cas(&cancelled_with_error_, 0, 1)) { - return; - } - if (GRPC_TRACE_FLAG_ENABLED(grpc_call_error_trace)) { - gpr_log(GPR_INFO, "CancelWithError %s %s", is_client() ? "CLI" : "SVR", - StatusToString(error).c_str()); - } - ClearPeerString(); - InternalRef("termination"); - ResetDeadline(); - // Inform the call combiner of the cancellation, so that it can cancel - // any in-flight asynchronous actions that may be holding the call - // combiner. This ensures that the cancel_stream batch can be sent - // down the filter stack in a timely manner. - call_combiner_.Cancel(error); - CancelState* state = new CancelState; - state->call = this; - GRPC_CLOSURE_INIT(&state->finish_batch, done_termination, state, - grpc_schedule_on_exec_ctx); - grpc_transport_stream_op_batch* op = - grpc_make_transport_stream_op(&state->finish_batch); - op->cancel_stream = true; - op->payload->cancel_stream.cancel_error = error; - ExecuteBatch(op, &state->start_batch); -} - -void FilterStackCall::SetFinalStatus(grpc_error_handle error) { - if (GRPC_TRACE_FLAG_ENABLED(grpc_call_error_trace)) { - gpr_log(GPR_INFO, "set_final_status %s %s", is_client() ? "CLI" : "SVR", - StatusToString(error).c_str()); - } - ResetDeadline(); - if (is_client()) { - std::string status_details; - grpc_error_get_status(error, send_deadline(), final_op_.client.status, - &status_details, nullptr, - final_op_.client.error_string); - *final_op_.client.status_details = - grpc_slice_from_cpp_string(std::move(status_details)); - status_error_.set(error); - channelz::ChannelNode* channelz_channel = channel()->channelz_node(); - if (channelz_channel != nullptr) { - if (*final_op_.client.status != GRPC_STATUS_OK) { - channelz_channel->RecordCallFailed(); - } else { - channelz_channel->RecordCallSucceeded(); - } - } - } else { - *final_op_.server.cancelled = - !error.ok() || !sent_server_trailing_metadata_; - channelz::ServerNode* channelz_node = - final_op_.server.core_server->channelz_node(); - if (channelz_node != nullptr) { - if (*final_op_.server.cancelled || !status_error_.ok()) { - channelz_node->RecordCallFailed(); - } else { - channelz_node->RecordCallSucceeded(); - } - } - } -} - -bool FilterStackCall::PrepareApplicationMetadata(size_t count, - grpc_metadata* metadata, - bool is_trailing) { - grpc_metadata_batch* batch = - is_trailing ? &send_trailing_metadata_ : &send_initial_metadata_; - for (size_t i = 0; i < count; i++) { - grpc_metadata* md = &metadata[i]; - if (!GRPC_LOG_IF_ERROR("validate_metadata", - grpc_validate_header_key_is_legal(md->key))) { - return false; - } else if (!grpc_is_binary_header_internal(md->key) && - !GRPC_LOG_IF_ERROR( - "validate_metadata", - grpc_validate_header_nonbin_value_is_legal(md->value))) { - return false; - } else if (GRPC_SLICE_LENGTH(md->value) >= UINT32_MAX) { - // HTTP2 hpack encoding has a maximum limit. - return false; - } else if (grpc_slice_str_cmp(md->key, "content-length") == 0) { - // Filter "content-length metadata" - continue; - } - batch->Append(StringViewFromSlice(md->key), Slice(CSliceRef(md->value)), - [md](absl::string_view error, const Slice& value) { - gpr_log(GPR_DEBUG, "Append error: %s", - absl::StrCat("key=", StringViewFromSlice(md->key), - " error=", error, - " value=", value.as_string_view()) - .c_str()); - }); - } - - return true; -} - -namespace { -class PublishToAppEncoder { - public: - explicit PublishToAppEncoder(grpc_metadata_array* dest, - const grpc_metadata_batch* encoding, - bool is_client) - : dest_(dest), encoding_(encoding), is_client_(is_client) {} - - void Encode(const Slice& key, const Slice& value) { - Append(key.c_slice(), value.c_slice()); - } - - // Catch anything that is not explicitly handled, and do not publish it to the - // application. If new metadata is added to a batch that needs to be - // published, it should be called out here. - template - void Encode(Which, const typename Which::ValueType&) {} - - void Encode(UserAgentMetadata, const Slice& slice) { - Append(UserAgentMetadata::key(), slice); - } - - void Encode(HostMetadata, const Slice& slice) { - Append(HostMetadata::key(), slice); - } - - void Encode(GrpcPreviousRpcAttemptsMetadata, uint32_t count) { - Append(GrpcPreviousRpcAttemptsMetadata::key(), count); - } - - void Encode(GrpcRetryPushbackMsMetadata, Duration count) { - Append(GrpcRetryPushbackMsMetadata::key(), count.millis()); - } - - void Encode(LbTokenMetadata, const Slice& slice) { - Append(LbTokenMetadata::key(), slice); - } - - private: - void Append(absl::string_view key, int64_t value) { - Append(StaticSlice::FromStaticString(key).c_slice(), - Slice::FromInt64(value).c_slice()); - } - - void Append(absl::string_view key, const Slice& value) { - Append(StaticSlice::FromStaticString(key).c_slice(), value.c_slice()); - } - - void Append(grpc_slice key, grpc_slice value) { - if (dest_->count == dest_->capacity) { - Crash(absl::StrCat( - "Too many metadata entries: capacity=", dest_->capacity, " on ", - is_client_ ? "client" : "server", " encoding ", encoding_->count(), - " elements: ", encoding_->DebugString().c_str())); - } - auto* mdusr = &dest_->metadata[dest_->count++]; - mdusr->key = key; - mdusr->value = value; - } - - grpc_metadata_array* const dest_; - const grpc_metadata_batch* const encoding_; - const bool is_client_; -}; -} // namespace - -void FilterStackCall::PublishAppMetadata(grpc_metadata_batch* b, - bool is_trailing) { - if (b->count() == 0) return; - if (!is_client() && is_trailing) return; - if (is_trailing && buffered_metadata_[1] == nullptr) return; - grpc_metadata_array* dest; - dest = buffered_metadata_[is_trailing]; - if (dest->count + b->count() > dest->capacity) { - dest->capacity = - std::max(dest->capacity + b->count(), dest->capacity * 3 / 2); - dest->metadata = static_cast( - gpr_realloc(dest->metadata, sizeof(grpc_metadata) * dest->capacity)); - } - PublishToAppEncoder encoder(dest, b, is_client()); - b->Encode(&encoder); -} - -void FilterStackCall::RecvInitialFilter(grpc_metadata_batch* b) { - ProcessIncomingInitialMetadata(*b); - PublishAppMetadata(b, false); -} - -void FilterStackCall::RecvTrailingFilter(grpc_metadata_batch* b, - grpc_error_handle batch_error) { - if (!batch_error.ok()) { - SetFinalStatus(batch_error); - } else { - absl::optional grpc_status = - b->Take(GrpcStatusMetadata()); - if (grpc_status.has_value()) { - grpc_status_code status_code = *grpc_status; - grpc_error_handle error; - if (status_code != GRPC_STATUS_OK) { - Slice peer = GetPeerString(); - error = grpc_error_set_int( - GRPC_ERROR_CREATE(absl::StrCat("Error received from peer ", - peer.as_string_view())), - StatusIntProperty::kRpcStatus, static_cast(status_code)); - } - auto grpc_message = b->Take(GrpcMessageMetadata()); - if (grpc_message.has_value()) { - error = grpc_error_set_str(error, StatusStrProperty::kGrpcMessage, - grpc_message->as_string_view()); - } else if (!error.ok()) { - error = grpc_error_set_str(error, StatusStrProperty::kGrpcMessage, ""); - } - SetFinalStatus(error); - } else if (!is_client()) { - SetFinalStatus(absl::OkStatus()); - } else { - VLOG(2) << "Received trailing metadata with no error and no status"; - SetFinalStatus(grpc_error_set_int(GRPC_ERROR_CREATE("No status received"), - StatusIntProperty::kRpcStatus, - GRPC_STATUS_UNKNOWN)); - } - } - PublishAppMetadata(b, true); -} - -namespace { -bool AreWriteFlagsValid(uint32_t flags) { - // check that only bits in GRPC_WRITE_(INTERNAL?)_USED_MASK are set - const uint32_t allowed_write_positions = - (GRPC_WRITE_USED_MASK | GRPC_WRITE_INTERNAL_USED_MASK); - const uint32_t invalid_positions = ~allowed_write_positions; - return !(flags & invalid_positions); -} - -bool AreInitialMetadataFlagsValid(uint32_t flags) { - // check that only bits in GRPC_WRITE_(INTERNAL?)_USED_MASK are set - uint32_t invalid_positions = ~GRPC_INITIAL_METADATA_USED_MASK; - return !(flags & invalid_positions); -} - -size_t BatchSlotForOp(grpc_op_type type) { - switch (type) { - case GRPC_OP_SEND_INITIAL_METADATA: - return 0; - case GRPC_OP_SEND_MESSAGE: - return 1; - case GRPC_OP_SEND_CLOSE_FROM_CLIENT: - case GRPC_OP_SEND_STATUS_FROM_SERVER: - return 2; - case GRPC_OP_RECV_INITIAL_METADATA: - return 3; - case GRPC_OP_RECV_MESSAGE: - return 4; - case GRPC_OP_RECV_CLOSE_ON_SERVER: - case GRPC_OP_RECV_STATUS_ON_CLIENT: - return 5; - } - GPR_UNREACHABLE_CODE(return 123456789); -} -} // namespace - -FilterStackCall::BatchControl* FilterStackCall::ReuseOrAllocateBatchControl( - const grpc_op* ops) { - size_t slot_idx = BatchSlotForOp(ops[0].op); - BatchControl** pslot = &active_batches_[slot_idx]; - BatchControl* bctl; - if (*pslot != nullptr) { - bctl = *pslot; - if (bctl->call_ != nullptr) { - return nullptr; - } - bctl->~BatchControl(); - bctl->op_ = {}; - new (&bctl->batch_error_) AtomicError(); - } else { - bctl = arena()->New(); - *pslot = bctl; - } - bctl->call_ = this; - bctl->call_tracer_ = arena()->GetContext(); - bctl->op_.payload = &stream_op_payload_; - return bctl; -} - -void FilterStackCall::BatchControl::PostCompletion() { - FilterStackCall* call = call_; - grpc_error_handle error = batch_error_.get(); - - if (IsCallStatusOverrideOnCancellationEnabled()) { - // On the client side, if final call status is already known (i.e if this op - // includes recv_trailing_metadata) and if the call status is known to be - // OK, then disregard the batch error to ensure call->receiving_buffer_ is - // not cleared. - if (op_.recv_trailing_metadata && call->is_client() && - call->status_error_.ok()) { - error = absl::OkStatus(); - } - } - - if (grpc_call_trace.enabled()) { - gpr_log(GPR_DEBUG, "tag:%p batch_error=%s op:%s", - completion_data_.notify_tag.tag, error.ToString().c_str(), - grpc_transport_stream_op_batch_string(&op_, false).c_str()); - } - - if (op_.send_initial_metadata) { - call->send_initial_metadata_.Clear(); - } - if (op_.send_message) { - if (op_.payload->send_message.stream_write_closed && error.ok()) { - error = grpc_error_add_child( - error, GRPC_ERROR_CREATE( - "Attempt to send message after stream was closed.")); - } - call->sending_message_ = false; - call->send_slice_buffer_.Clear(); - } - if (op_.send_trailing_metadata) { - call->send_trailing_metadata_.Clear(); - } - - if (!error.ok() && op_.recv_message && *call->receiving_buffer_ != nullptr) { - grpc_byte_buffer_destroy(*call->receiving_buffer_); - *call->receiving_buffer_ = nullptr; - } - if (op_.recv_trailing_metadata) { - // propagate cancellation to any interested children - gpr_atm_rel_store(&call->received_final_op_atm_, 1); - call->PropagateCancellationToChildren(); - error = absl::OkStatus(); - } - batch_error_.set(absl::OkStatus()); - - if (completion_data_.notify_tag.is_closure) { - call_ = nullptr; - GrpcClosure::Run( - DEBUG_LOCATION, - static_cast(completion_data_.notify_tag.tag), error); - call->InternalUnref("completion"); - } else { - grpc_cq_end_op( - call->cq_, completion_data_.notify_tag.tag, error, - [](void* user_data, grpc_cq_completion* /*storage*/) { - BatchControl* bctl = static_cast(user_data); - Call* call = bctl->call_; - bctl->call_ = nullptr; - call->InternalUnref("completion"); - }, - this, &completion_data_.cq_completion); - } -} - -void FilterStackCall::BatchControl::FinishStep(PendingOp op) { - if (GPR_UNLIKELY(completed_batch_step(op))) { - PostCompletion(); - } -} - -void FilterStackCall::BatchControl::ProcessDataAfterMetadata() { - FilterStackCall* call = call_; - if (!call->receiving_slice_buffer_.has_value()) { - *call->receiving_buffer_ = nullptr; - call->receiving_message_ = false; - FinishStep(PendingOp::kRecvMessage); - } else { - call->NoteLastMessageFlags(call->receiving_stream_flags_); - if ((call->receiving_stream_flags_ & GRPC_WRITE_INTERNAL_COMPRESS) && - (call->incoming_compression_algorithm() != GRPC_COMPRESS_NONE)) { - *call->receiving_buffer_ = grpc_raw_compressed_byte_buffer_create( - nullptr, 0, call->incoming_compression_algorithm()); - } else { - *call->receiving_buffer_ = grpc_raw_byte_buffer_create(nullptr, 0); - } - grpc_slice_buffer_move_into( - call->receiving_slice_buffer_->c_slice_buffer(), - &(*call->receiving_buffer_)->data.raw.slice_buffer); - call->receiving_message_ = false; - call->receiving_slice_buffer_.reset(); - FinishStep(PendingOp::kRecvMessage); - } -} +// C-based API -void FilterStackCall::BatchControl::ReceivingStreamReady( - grpc_error_handle error) { - if (grpc_call_trace.enabled()) { - gpr_log(GPR_DEBUG, - "tag:%p ReceivingStreamReady error=%s " - "receiving_slice_buffer.has_value=%d recv_state=%" PRIdPTR, - completion_data_.notify_tag.tag, error.ToString().c_str(), - call_->receiving_slice_buffer_.has_value(), - gpr_atm_no_barrier_load(&call_->recv_state_)); - } - FilterStackCall* call = call_; - if (!error.ok()) { - call->receiving_slice_buffer_.reset(); - if (batch_error_.ok()) { - batch_error_.set(error); - } - call->CancelWithError(error); - } - // If recv_state is kRecvNone, we will save the batch_control - // object with rel_cas, and will not use it after the cas. Its corresponding - // acq_load is in receiving_initial_metadata_ready() - if (!error.ok() || !call->receiving_slice_buffer_.has_value() || - !gpr_atm_rel_cas(&call->recv_state_, kRecvNone, - reinterpret_cast(this))) { - ProcessDataAfterMetadata(); - } +void* grpc_call_arena_alloc(grpc_call* call, size_t size) { + grpc_core::ExecCtx exec_ctx; + return grpc_core::Call::FromC(call)->arena()->Alloc(size); } -void FilterStackCall::BatchControl::ReceivingInitialMetadataReady( - grpc_error_handle error) { - FilterStackCall* call = call_; - - GRPC_CALL_COMBINER_STOP(call->call_combiner(), "recv_initial_metadata_ready"); - - if (error.ok()) { - grpc_metadata_batch* md = &call->recv_initial_metadata_; - call->RecvInitialFilter(md); - - absl::optional deadline = md->get(GrpcTimeoutMetadata()); - if (deadline.has_value() && !call->is_client()) { - call_->set_send_deadline(*deadline); - } - } else { - if (batch_error_.ok()) { - batch_error_.set(error); - } - call->CancelWithError(error); - } - - grpc_closure* saved_rsr_closure = nullptr; - while (true) { - gpr_atm rsr_bctlp = gpr_atm_acq_load(&call->recv_state_); - // Should only receive initial metadata once - CHECK_NE(rsr_bctlp, 1); - if (rsr_bctlp == 0) { - // We haven't seen initial metadata and messages before, thus initial - // metadata is received first. - // no_barrier_cas is used, as this function won't access the batch_control - // object saved by receiving_stream_ready() if the initial metadata is - // received first. - if (gpr_atm_no_barrier_cas(&call->recv_state_, kRecvNone, - kRecvInitialMetadataFirst)) { - break; - } - } else { - // Already received messages - saved_rsr_closure = GRPC_CLOSURE_CREATE( - [](void* bctl, grpc_error_handle error) { - static_cast(bctl)->ReceivingStreamReady(error); - }, - reinterpret_cast(rsr_bctlp), - grpc_schedule_on_exec_ctx); - // No need to modify recv_state - break; - } - } - if (saved_rsr_closure != nullptr) { - GrpcClosure::Run(DEBUG_LOCATION, saved_rsr_closure, error); - } - - FinishStep(PendingOp::kRecvInitialMetadata); +void grpc_call_set_completion_queue(grpc_call* call, + grpc_completion_queue* cq) { + grpc_core::Call::FromC(call)->SetCompletionQueue(cq); } -void FilterStackCall::BatchControl::ReceivingTrailingMetadataReady( - grpc_error_handle error) { - GRPC_CALL_COMBINER_STOP(call_->call_combiner(), - "recv_trailing_metadata_ready"); - grpc_metadata_batch* md = &call_->recv_trailing_metadata_; - call_->RecvTrailingFilter(md, error); - FinishStep(PendingOp::kRecvTrailingMetadata); -} +void grpc_call_ref(grpc_call* c) { grpc_core::Call::FromC(c)->ExternalRef(); } -void FilterStackCall::BatchControl::FinishBatch(grpc_error_handle error) { - GRPC_CALL_COMBINER_STOP(call_->call_combiner(), "on_complete"); - if (batch_error_.ok()) { - batch_error_.set(error); - } - if (!error.ok()) { - call_->CancelWithError(error); - } - FinishStep(PendingOp::kSends); -} - -namespace { -void EndOpImmediately(grpc_completion_queue* cq, void* notify_tag, - bool is_notify_tag_closure) { - if (!is_notify_tag_closure) { - CHECK(grpc_cq_begin_op(cq, notify_tag)); - grpc_cq_end_op( - cq, notify_tag, absl::OkStatus(), - [](void*, grpc_cq_completion* completion) { gpr_free(completion); }, - nullptr, - static_cast( - gpr_malloc(sizeof(grpc_cq_completion)))); - } else { - Closure::Run(DEBUG_LOCATION, static_cast(notify_tag), - absl::OkStatus()); - } -} -} // namespace - -grpc_call_error FilterStackCall::StartBatch(const grpc_op* ops, size_t nops, - void* notify_tag, - bool is_notify_tag_closure) { - size_t i; - const grpc_op* op; - BatchControl* bctl; - grpc_call_error error = GRPC_CALL_OK; - grpc_transport_stream_op_batch* stream_op; - grpc_transport_stream_op_batch_payload* stream_op_payload; - uint32_t seen_ops = 0; - intptr_t pending_ops = 0; - - for (i = 0; i < nops; i++) { - if (seen_ops & (1u << ops[i].op)) { - return GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; - } - seen_ops |= (1u << ops[i].op); - } - - if (!is_client() && - (seen_ops & (1u << GRPC_OP_SEND_STATUS_FROM_SERVER)) != 0 && - (seen_ops & (1u << GRPC_OP_RECV_MESSAGE)) != 0) { - gpr_log(GPR_ERROR, - "******************* SEND_STATUS WITH RECV_MESSAGE " - "*******************"); - return GRPC_CALL_ERROR; - } - - GRPC_CALL_LOG_BATCH(GPR_INFO, ops, nops); - - if (nops == 0) { - EndOpImmediately(cq_, notify_tag, is_notify_tag_closure); - error = GRPC_CALL_OK; - goto done; - } - - bctl = ReuseOrAllocateBatchControl(ops); - if (bctl == nullptr) { - return GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; - } - bctl->completion_data_.notify_tag.tag = notify_tag; - bctl->completion_data_.notify_tag.is_closure = - static_cast(is_notify_tag_closure != 0); - - stream_op = &bctl->op_; - stream_op_payload = &stream_op_payload_; - - // rewrite batch ops into a transport op - for (i = 0; i < nops; i++) { - op = &ops[i]; - if (op->reserved != nullptr) { - error = GRPC_CALL_ERROR; - goto done_with_error; - } - switch (op->op) { - case GRPC_OP_SEND_INITIAL_METADATA: { - // Flag validation: currently allow no flags - if (!AreInitialMetadataFlagsValid(op->flags)) { - error = GRPC_CALL_ERROR_INVALID_FLAGS; - goto done_with_error; - } - if (sent_initial_metadata_) { - error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; - goto done_with_error; - } - if (op->data.send_initial_metadata.count > INT_MAX) { - error = GRPC_CALL_ERROR_INVALID_METADATA; - goto done_with_error; - } - stream_op->send_initial_metadata = true; - sent_initial_metadata_ = true; - if (!PrepareApplicationMetadata(op->data.send_initial_metadata.count, - op->data.send_initial_metadata.metadata, - false)) { - error = GRPC_CALL_ERROR_INVALID_METADATA; - goto done_with_error; - } - PrepareOutgoingInitialMetadata(*op, send_initial_metadata_); - // TODO(ctiller): just make these the same variable? - if (is_client() && send_deadline() != Timestamp::InfFuture()) { - send_initial_metadata_.Set(GrpcTimeoutMetadata(), send_deadline()); - } - if (is_client()) { - send_initial_metadata_.Set( - WaitForReady(), - WaitForReady::ValueType{ - (op->flags & GRPC_INITIAL_METADATA_WAIT_FOR_READY) != 0, - (op->flags & - GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET) != 0}); - } - stream_op_payload->send_initial_metadata.send_initial_metadata = - &send_initial_metadata_; - pending_ops |= PendingOpMask(PendingOp::kSends); - break; - } - case GRPC_OP_SEND_MESSAGE: { - if (!AreWriteFlagsValid(op->flags)) { - error = GRPC_CALL_ERROR_INVALID_FLAGS; - goto done_with_error; - } - if (op->data.send_message.send_message == nullptr) { - error = GRPC_CALL_ERROR_INVALID_MESSAGE; - goto done_with_error; - } - if (sending_message_) { - error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; - goto done_with_error; - } - uint32_t flags = op->flags; - // If the outgoing buffer is already compressed, mark it as so in the - // flags. These will be picked up by the compression filter and further - // (wasteful) attempts at compression skipped. - if (op->data.send_message.send_message->data.raw.compression > - GRPC_COMPRESS_NONE) { - flags |= GRPC_WRITE_INTERNAL_COMPRESS; - } - stream_op->send_message = true; - sending_message_ = true; - send_slice_buffer_.Clear(); - grpc_slice_buffer_move_into( - &op->data.send_message.send_message->data.raw.slice_buffer, - send_slice_buffer_.c_slice_buffer()); - stream_op_payload->send_message.flags = flags; - stream_op_payload->send_message.send_message = &send_slice_buffer_; - pending_ops |= PendingOpMask(PendingOp::kSends); - break; - } - case GRPC_OP_SEND_CLOSE_FROM_CLIENT: { - // Flag validation: currently allow no flags - if (op->flags != 0) { - error = GRPC_CALL_ERROR_INVALID_FLAGS; - goto done_with_error; - } - if (!is_client()) { - error = GRPC_CALL_ERROR_NOT_ON_SERVER; - goto done_with_error; - } - if (sent_final_op_) { - error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; - goto done_with_error; - } - stream_op->send_trailing_metadata = true; - sent_final_op_ = true; - stream_op_payload->send_trailing_metadata.send_trailing_metadata = - &send_trailing_metadata_; - pending_ops |= PendingOpMask(PendingOp::kSends); - break; - } - case GRPC_OP_SEND_STATUS_FROM_SERVER: { - // Flag validation: currently allow no flags - if (op->flags != 0) { - error = GRPC_CALL_ERROR_INVALID_FLAGS; - goto done_with_error; - } - if (is_client()) { - error = GRPC_CALL_ERROR_NOT_ON_CLIENT; - goto done_with_error; - } - if (sent_final_op_) { - error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; - goto done_with_error; - } - if (op->data.send_status_from_server.trailing_metadata_count > - INT_MAX) { - error = GRPC_CALL_ERROR_INVALID_METADATA; - goto done_with_error; - } - stream_op->send_trailing_metadata = true; - sent_final_op_ = true; - - if (!PrepareApplicationMetadata( - op->data.send_status_from_server.trailing_metadata_count, - op->data.send_status_from_server.trailing_metadata, true)) { - error = GRPC_CALL_ERROR_INVALID_METADATA; - goto done_with_error; - } - - grpc_error_handle status_error = - op->data.send_status_from_server.status == GRPC_STATUS_OK - ? absl::OkStatus() - : grpc_error_set_int( - GRPC_ERROR_CREATE("Server returned error"), - StatusIntProperty::kRpcStatus, - static_cast( - op->data.send_status_from_server.status)); - if (op->data.send_status_from_server.status_details != nullptr) { - send_trailing_metadata_.Set( - GrpcMessageMetadata(), - Slice(grpc_slice_copy( - *op->data.send_status_from_server.status_details))); - if (!status_error.ok()) { - status_error = grpc_error_set_str( - status_error, StatusStrProperty::kGrpcMessage, - StringViewFromSlice( - *op->data.send_status_from_server.status_details)); - } - } - - status_error_.set(status_error); - - send_trailing_metadata_.Set(GrpcStatusMetadata(), - op->data.send_status_from_server.status); - - // Ignore any te metadata key value pairs specified. - send_trailing_metadata_.Remove(TeMetadata()); - stream_op_payload->send_trailing_metadata.send_trailing_metadata = - &send_trailing_metadata_; - stream_op_payload->send_trailing_metadata.sent = - &sent_server_trailing_metadata_; - pending_ops |= PendingOpMask(PendingOp::kSends); - break; - } - case GRPC_OP_RECV_INITIAL_METADATA: { - // Flag validation: currently allow no flags - if (op->flags != 0) { - error = GRPC_CALL_ERROR_INVALID_FLAGS; - goto done_with_error; - } - if (received_initial_metadata_) { - error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; - goto done_with_error; - } - received_initial_metadata_ = true; - buffered_metadata_[0] = - op->data.recv_initial_metadata.recv_initial_metadata; - GRPC_CLOSURE_INIT( - &receiving_initial_metadata_ready_, - [](void* bctl, grpc_error_handle error) { - static_cast(bctl)->ReceivingInitialMetadataReady( - error); - }, - bctl, grpc_schedule_on_exec_ctx); - stream_op->recv_initial_metadata = true; - stream_op_payload->recv_initial_metadata.recv_initial_metadata = - &recv_initial_metadata_; - stream_op_payload->recv_initial_metadata.recv_initial_metadata_ready = - &receiving_initial_metadata_ready_; - if (is_client()) { - stream_op_payload->recv_initial_metadata.trailing_metadata_available = - &is_trailers_only_; - } - pending_ops |= PendingOpMask(PendingOp::kRecvInitialMetadata); - break; - } - case GRPC_OP_RECV_MESSAGE: { - // Flag validation: currently allow no flags - if (op->flags != 0) { - error = GRPC_CALL_ERROR_INVALID_FLAGS; - goto done_with_error; - } - if (receiving_message_) { - error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; - goto done_with_error; - } - receiving_message_ = true; - stream_op->recv_message = true; - receiving_slice_buffer_.reset(); - receiving_buffer_ = op->data.recv_message.recv_message; - stream_op_payload->recv_message.recv_message = &receiving_slice_buffer_; - receiving_stream_flags_ = 0; - stream_op_payload->recv_message.flags = &receiving_stream_flags_; - stream_op_payload->recv_message.call_failed_before_recv_message = - &call_failed_before_recv_message_; - GRPC_CLOSURE_INIT( - &receiving_stream_ready_, - [](void* bctlp, grpc_error_handle error) { - auto* bctl = static_cast(bctlp); - auto* call = bctl->call_; - // Yields the call combiner before processing the received - // message. - GRPC_CALL_COMBINER_STOP(call->call_combiner(), - "recv_message_ready"); - bctl->ReceivingStreamReady(error); - }, - bctl, grpc_schedule_on_exec_ctx); - stream_op_payload->recv_message.recv_message_ready = - &receiving_stream_ready_; - pending_ops |= PendingOpMask(PendingOp::kRecvMessage); - break; - } - case GRPC_OP_RECV_STATUS_ON_CLIENT: { - // Flag validation: currently allow no flags - if (op->flags != 0) { - error = GRPC_CALL_ERROR_INVALID_FLAGS; - goto done_with_error; - } - if (!is_client()) { - error = GRPC_CALL_ERROR_NOT_ON_SERVER; - goto done_with_error; - } - if (requested_final_op_) { - error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; - goto done_with_error; - } - requested_final_op_ = true; - buffered_metadata_[1] = - op->data.recv_status_on_client.trailing_metadata; - final_op_.client.status = op->data.recv_status_on_client.status; - final_op_.client.status_details = - op->data.recv_status_on_client.status_details; - final_op_.client.error_string = - op->data.recv_status_on_client.error_string; - stream_op->recv_trailing_metadata = true; - stream_op_payload->recv_trailing_metadata.recv_trailing_metadata = - &recv_trailing_metadata_; - stream_op_payload->recv_trailing_metadata.collect_stats = - &final_info_.stats.transport_stream_stats; - GRPC_CLOSURE_INIT( - &receiving_trailing_metadata_ready_, - [](void* bctl, grpc_error_handle error) { - static_cast(bctl)->ReceivingTrailingMetadataReady( - error); - }, - bctl, grpc_schedule_on_exec_ctx); - stream_op_payload->recv_trailing_metadata.recv_trailing_metadata_ready = - &receiving_trailing_metadata_ready_; - pending_ops |= PendingOpMask(PendingOp::kRecvTrailingMetadata); - break; - } - case GRPC_OP_RECV_CLOSE_ON_SERVER: { - // Flag validation: currently allow no flags - if (op->flags != 0) { - error = GRPC_CALL_ERROR_INVALID_FLAGS; - goto done_with_error; - } - if (is_client()) { - error = GRPC_CALL_ERROR_NOT_ON_CLIENT; - goto done_with_error; - } - if (requested_final_op_) { - error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; - goto done_with_error; - } - requested_final_op_ = true; - final_op_.server.cancelled = op->data.recv_close_on_server.cancelled; - stream_op->recv_trailing_metadata = true; - stream_op_payload->recv_trailing_metadata.recv_trailing_metadata = - &recv_trailing_metadata_; - stream_op_payload->recv_trailing_metadata.collect_stats = - &final_info_.stats.transport_stream_stats; - GRPC_CLOSURE_INIT( - &receiving_trailing_metadata_ready_, - [](void* bctl, grpc_error_handle error) { - static_cast(bctl)->ReceivingTrailingMetadataReady( - error); - }, - bctl, grpc_schedule_on_exec_ctx); - stream_op_payload->recv_trailing_metadata.recv_trailing_metadata_ready = - &receiving_trailing_metadata_ready_; - pending_ops |= PendingOpMask(PendingOp::kRecvTrailingMetadata); - break; - } - } - } - - InternalRef("completion"); - if (!is_notify_tag_closure) { - CHECK(grpc_cq_begin_op(cq_, notify_tag)); - } - bctl->set_pending_ops(pending_ops); - - if (pending_ops & PendingOpMask(PendingOp::kSends)) { - GRPC_CLOSURE_INIT( - &bctl->finish_batch_, - [](void* bctl, grpc_error_handle error) { - static_cast(bctl)->FinishBatch(error); - }, - bctl, grpc_schedule_on_exec_ctx); - stream_op->on_complete = &bctl->finish_batch_; - } - - if (grpc_call_trace.enabled()) { - gpr_log(GPR_DEBUG, "BATCH:%p START:%s BATCH:%s (tag:%p)", bctl, - PendingOpString(pending_ops).c_str(), - grpc_transport_stream_op_batch_string(stream_op, false).c_str(), - bctl->completion_data_.notify_tag.tag); - } - ExecuteBatch(stream_op, &bctl->start_batch_); - -done: - return error; - -done_with_error: - // reverse any mutations that occurred - if (stream_op->send_initial_metadata) { - sent_initial_metadata_ = false; - send_initial_metadata_.Clear(); - } - if (stream_op->send_message) { - sending_message_ = false; - } - if (stream_op->send_trailing_metadata) { - sent_final_op_ = false; - send_trailing_metadata_.Clear(); - } - if (stream_op->recv_initial_metadata) { - received_initial_metadata_ = false; - } - if (stream_op->recv_message) { - receiving_message_ = false; - } - if (stream_op->recv_trailing_metadata) { - requested_final_op_ = false; - } - goto done; -} - -/////////////////////////////////////////////////////////////////////////////// -// Metadata validation helpers - -namespace { -bool ValidateMetadata(size_t count, grpc_metadata* metadata) { - if (count > INT_MAX) { - return false; - } - for (size_t i = 0; i < count; i++) { - grpc_metadata* md = &metadata[i]; - if (!GRPC_LOG_IF_ERROR("validate_metadata", - grpc_validate_header_key_is_legal(md->key))) { - return false; - } else if (!grpc_is_binary_header_internal(md->key) && - !GRPC_LOG_IF_ERROR( - "validate_metadata", - grpc_validate_header_nonbin_value_is_legal(md->value))) { - return false; - } else if (GRPC_SLICE_LENGTH(md->value) >= UINT32_MAX) { - // HTTP2 hpack encoding has a maximum limit. - return false; - } - } - return true; -} -} // namespace - -/////////////////////////////////////////////////////////////////////////////// -// PromiseBasedCall -// Will be folded into Call once the promise conversion is done - -class BasicPromiseBasedCall : public ChannelBasedCall, public Party { - public: - using Call::arena; - - BasicPromiseBasedCall(RefCountedPtr arena, - uint32_t initial_external_refs, - uint32_t initial_internal_refs, - const grpc_call_create_args& args) - : ChannelBasedCall(std::move(arena), - args.server_transport_data == nullptr, - args.send_deadline, args.channel->Ref()), - Party(initial_internal_refs), - external_refs_(initial_external_refs), - cq_(args.cq) { - if (args.cq != nullptr) { - GRPC_CQ_INTERNAL_REF(args.cq, "bind"); - } - GetArena()->SetContext(this); - } - - ~BasicPromiseBasedCall() override { - if (cq_) GRPC_CQ_INTERNAL_UNREF(cq_, "bind"); - } - - virtual void OrphanCall() = 0; - - void SetCompletionQueue(grpc_completion_queue* cq) final { - cq_ = cq; - GRPC_CQ_INTERNAL_REF(cq, "bind"); - } - - // Implementation of call refcounting: move this to DualRefCounted once we - // don't need to maintain FilterStackCall compatibility - void ExternalRef() final { - if (external_refs_.fetch_add(1, std::memory_order_relaxed) == 0) { - InternalRef("external"); - } - } - void ExternalUnref() final { - if (external_refs_.fetch_sub(1, std::memory_order_acq_rel) == 1) { - OrphanCall(); - InternalUnref("external"); - } - } - void InternalRef(const char* reason) final { - if (grpc_call_refcount_trace.enabled()) { - gpr_log(GPR_DEBUG, "INTERNAL_REF:%p:%s", this, reason); - } - Party::IncrementRefCount(); - } - void InternalUnref(const char* reason) final { - if (grpc_call_refcount_trace.enabled()) { - gpr_log(GPR_DEBUG, "INTERNAL_UNREF:%p:%s", this, reason); - } - Party::Unref(); - } - - void RunInContext(absl::AnyInvocable fn) { - Spawn( - "run_in_context", - [fn = std::move(fn)]() mutable { - fn(); - return Empty{}; - }, - [](Empty) {}); - } - - // Accept the stats from the context (call once we have proof the transport is - // done with them). - void AcceptTransportStatsFromContext() { - final_stats_ = *call_context_.call_stats(); - } - - // This should return nullptr for the promise stack (and alternative means - // for that functionality be invented) - grpc_call_stack* call_stack() final { return nullptr; } - - virtual RefCountedPtr MakeCallSpine(CallArgs) { - Crash("Not implemented"); - } - - protected: - class ScopedContext : public ScopedActivity, - public promise_detail::Context, - public promise_detail::Context, - public promise_detail::Context { - public: - explicit ScopedContext(BasicPromiseBasedCall* call) - : ScopedActivity(call), - promise_detail::Context(call->arena()), - promise_detail::Context(&call->call_context_), - promise_detail::Context(&call->finalization_) {} - }; - - grpc_completion_queue* cq() { return cq_; } - - // At the end of the call run any finalization actions. - void SetFinalizationStatus(grpc_status_code status, Slice status_details) { - final_message_ = std::move(status_details); - final_status_ = status; - } - - grpc_event_engine::experimental::EventEngine* event_engine() const override { - return channel()->event_engine(); - } - - private: - void PartyOver() final { - { - ScopedContext ctx(this); - std::string message; - grpc_call_final_info final_info; - final_info.stats = final_stats_; - final_info.final_status = final_status_; - // TODO(ctiller): change type here so we don't need to copy this string. - final_info.error_string = nullptr; - if (!final_message_.empty()) { - message = std::string(final_message_.begin(), final_message_.end()); - final_info.error_string = message.c_str(); - } - final_info.stats.latency = - gpr_cycle_counter_sub(gpr_get_cycle_counter(), start_time()); - finalization_.Run(&final_info); - CancelRemainingParticipants(); - arena()->DestroyManagedNewObjects(); - } - DeleteThis(); - } - - // Double refcounted for now: party owns the internal refcount, we track the - // external refcount. Figure out a better scheme post-promise conversion. - std::atomic external_refs_; - CallFinalization finalization_; - CallContext call_context_{this}; - grpc_call_stats final_stats_{}; - Slice final_message_; - grpc_status_code final_status_ = GRPC_STATUS_UNKNOWN; - grpc_completion_queue* cq_; -}; - -class PromiseBasedCall : public BasicPromiseBasedCall { - public: - PromiseBasedCall(RefCountedPtr arena, uint32_t initial_external_refs, - const grpc_call_create_args& args); - - bool Completed() final { return finished_.IsSet(); } - - bool failed_before_recv_message() const final { - return failed_before_recv_message_.load(std::memory_order_relaxed); - } - - using Call::arena; - - protected: - class ScopedContext : public BasicPromiseBasedCall::ScopedContext, - public BatchBuilder, - public promise_detail::Context { - public: - explicit ScopedContext(PromiseBasedCall* call) - : BasicPromiseBasedCall::ScopedContext(call), - BatchBuilder(&call->batch_payload_), - promise_detail::Context(this) {} - }; - - class Completion { - public: - Completion() : index_(kNullIndex) {} - ~Completion() { CHECK(index_ == kNullIndex); } - explicit Completion(uint8_t index) : index_(index) {} - Completion(const Completion& other) = delete; - Completion& operator=(const Completion& other) = delete; - Completion(Completion&& other) noexcept : index_(other.index_) { - other.index_ = kNullIndex; - } - Completion& operator=(Completion&& other) noexcept { - CHECK(index_ == kNullIndex); - index_ = other.index_; - other.index_ = kNullIndex; - return *this; - } - - uint8_t index() const { return index_; } - uint8_t TakeIndex() { return std::exchange(index_, kNullIndex); } - bool has_value() const { return index_ != kNullIndex; } - - private: - enum : uint8_t { kNullIndex = 0xff }; - uint8_t index_; - }; - - // Enumerates why a Completion is still pending - enum class PendingOp { - // We're in the midst of starting a batch of operations - kStartingBatch = 0, - // The following correspond with the batch operations from above - kSendInitialMetadata, - kReceiveInitialMetadata, - kReceiveStatusOnClient, - kReceiveCloseOnServer = kReceiveStatusOnClient, - kSendMessage, - kReceiveMessage, - kSendStatusFromServer, - kSendCloseFromClient = kSendStatusFromServer, - }; - - bool RunParty() override { - ScopedContext ctx(this); - return Party::RunParty(); - } - - const char* PendingOpString(PendingOp reason) const { - switch (reason) { - case PendingOp::kStartingBatch: - return "StartingBatch"; - case PendingOp::kSendInitialMetadata: - return "SendInitialMetadata"; - case PendingOp::kReceiveInitialMetadata: - return "ReceiveInitialMetadata"; - case PendingOp::kReceiveStatusOnClient: - return is_client() ? "ReceiveStatusOnClient" : "ReceiveCloseOnServer"; - case PendingOp::kSendMessage: - return "SendMessage"; - case PendingOp::kReceiveMessage: - return "ReceiveMessage"; - case PendingOp::kSendStatusFromServer: - return is_client() ? "SendCloseFromClient" : "SendStatusFromServer"; - } - return "Unknown"; - } - - static constexpr uint32_t PendingOpBit(PendingOp reason) { - return 1 << static_cast(reason); - } - - // Begin work on a completion, recording the tag/closure to notify. - // Use the op selected in \a ops to determine the index to allocate into. - // Starts the "StartingBatch" PendingOp immediately. - // Assumes at least one operation in \a ops. - Completion StartCompletion(void* tag, bool is_closure, const grpc_op* ops); - // Add one pending op to the completion, and return it. - Completion AddOpToCompletion(const Completion& completion, PendingOp reason); - // Stringify a completion - std::string CompletionString(const Completion& completion) const { - return completion.has_value() - ? completion_info_[completion.index()].pending.ToString(this) - : "no-completion"; - } - // Finish one op on the completion. Must have been previously been added. - // The completion as a whole finishes when all pending ops finish. - void FinishOpOnCompletion(Completion* completion, PendingOp reason); - // Mark the completion as failed. Does not finish it. - void FailCompletion(const Completion& completion, - SourceLocation source_location = {}); - // Mark the completion as infallible. Overrides FailCompletion to report - // success always. - void ForceCompletionSuccess(const Completion& completion); - - std::string PresentAndCompletionText(const char* caption, bool has, - const Completion& completion) const { - if (has) { - if (completion.has_value()) { - return absl::StrCat(caption, ":", CompletionString(completion), " "); - } else { - return absl::StrCat(caption, - ":!!BUG:operation is present, no completion!! "); - } - } else { - if (!completion.has_value()) { - return ""; - } else { - return absl::StrCat(caption, ":no-op:", CompletionString(completion), - " "); - } - } - } - - // Spawn a job that will first do FirstPromise then receive a message - template - void StartRecvMessage(const grpc_op& op, const Completion& completion, - FirstPromise first, - PipeReceiver* receiver, - bool cancel_on_error, Party::BulkSpawner& spawner); - void StartSendMessage(const grpc_op& op, const Completion& completion, - PipeSender* sender, - Party::BulkSpawner& spawner); - - void set_completed() { finished_.Set(); } - - // Returns a promise that resolves to Empty whenever the call is completed. - auto finished() { return finished_.Wait(); } - - // Returns a promise that resolves to Empty whenever there is no outstanding - // send operation - auto WaitForSendingStarted() { - return [this]() -> Poll { - int n = sends_queued_.load(std::memory_order_relaxed); - if (grpc_call_trace.enabled()) { - gpr_log(GPR_DEBUG, "%s[call] WaitForSendingStarted n=%d", - DebugTag().c_str(), n); - } - if (n != 0) return waiting_for_queued_sends_.pending(); - return Empty{}; - }; - } - - // Mark that a send has been queued - blocks sending trailing metadata. - void QueueSend() { - if (grpc_call_trace.enabled()) { - gpr_log(GPR_DEBUG, "%s[call] QueueSend", DebugTag().c_str()); - } - sends_queued_.fetch_add(1, std::memory_order_relaxed); - } - // Mark that a send has been dequeued - allows sending trailing metadata once - // zero sends are queued. - void EnactSend() { - if (grpc_call_trace.enabled()) { - gpr_log(GPR_DEBUG, "%s[call] EnactSend", DebugTag().c_str()); - } - if (1 == sends_queued_.fetch_sub(1, std::memory_order_relaxed)) { - waiting_for_queued_sends_.Wake(); - } - } - - void set_failed_before_recv_message() { - failed_before_recv_message_.store(true, std::memory_order_relaxed); - } - - private: - union CompletionInfo { - static constexpr uint32_t kOpFailed = 0x8000'0000u; - static constexpr uint32_t kOpForceSuccess = 0x4000'0000u; - CompletionInfo() {} - enum CompletionState { - kPending, - kSuccess, - kFailure, - }; - struct Pending { - // Bitmask of PendingOps at the bottom, and kOpFailed, kOpForceSuccess at - // the top. - std::atomic state; - bool is_closure; - // True if this completion was for a recv_message op. - // In that case if the completion as a whole fails we need to cleanup the - // returned message. - bool is_recv_message; - void* tag; - - void Start(bool is_closure, void* tag) { - this->is_closure = is_closure; - this->is_recv_message = false; - this->tag = tag; - state.store(PendingOpBit(PendingOp::kStartingBatch), - std::memory_order_release); - } - - void AddPendingBit(PendingOp reason) { - if (reason == PendingOp::kReceiveMessage) is_recv_message = true; - auto prev = - state.fetch_or(PendingOpBit(reason), std::memory_order_relaxed); - CHECK_EQ((prev & PendingOpBit(reason)), 0u); - } - - CompletionState RemovePendingBit(PendingOp reason) { - const uint32_t mask = ~PendingOpBit(reason); - auto prev = state.fetch_and(mask, std::memory_order_acq_rel); - CHECK_NE((prev & PendingOpBit(reason)), 0u); - switch (prev & mask) { - case kOpFailed: - return kFailure; - case kOpFailed | kOpForceSuccess: - case kOpForceSuccess: - case 0: - return kSuccess; - default: - return kPending; - } - } - - void MarkFailed() { - state.fetch_or(kOpFailed, std::memory_order_relaxed); - } - - void MarkForceSuccess() { - state.fetch_or(kOpForceSuccess, std::memory_order_relaxed); - } - - std::string ToString(const PromiseBasedCall* call) const { - auto state = this->state.load(std::memory_order_relaxed); - std::vector pending_ops; - for (size_t i = 0; i < 24; i++) { - if (state & (1u << i)) { - pending_ops.push_back( - call->PendingOpString(static_cast(i))); - } - } - return absl::StrFormat("{%s}%s:tag=%p", absl::StrJoin(pending_ops, ","), - (state & kOpForceSuccess) ? ":force-success" - : (state & kOpFailed) ? ":failed" - : ":success", - tag); - } - } pending; - grpc_cq_completion completion; - }; - - CompletionInfo completion_info_[6]; - ExternallyObservableLatch finished_; - // Non-zero with an outstanding GRPC_OP_SEND_INITIAL_METADATA or - // GRPC_OP_SEND_MESSAGE (one count each), and 0 once those payloads have been - // pushed onto the outgoing pipe. - std::atomic sends_queued_{0}; - std::atomic failed_before_recv_message_{false}; - // Waiter for when sends_queued_ becomes 0. - IntraActivityWaiter waiting_for_queued_sends_; - grpc_byte_buffer** recv_message_ = nullptr; - grpc_transport_stream_op_batch_payload batch_payload_{}; -}; - -template -grpc_error_handle MakePromiseBasedCall(grpc_call_create_args* args, - grpc_call** out_call) { - Channel* channel = args->channel.get(); - 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(RefCountedPtr arena, - uint32_t initial_external_refs, - const grpc_call_create_args& args) - : BasicPromiseBasedCall(std::move(arena), initial_external_refs, - initial_external_refs != 0 ? 1 : 0, args) {} - -static void CToMetadata(grpc_metadata* metadata, size_t count, - grpc_metadata_batch* b) { - for (size_t i = 0; i < count; i++) { - grpc_metadata* md = &metadata[i]; - auto key = StringViewFromSlice(md->key); - // Filter "content-length metadata" - if (key == "content-length") continue; - b->Append(key, Slice(CSliceRef(md->value)), - [md](absl::string_view error, const Slice& value) { - gpr_log(GPR_DEBUG, "Append error: %s", - absl::StrCat("key=", StringViewFromSlice(md->key), - " error=", error, - " value=", value.as_string_view()) - .c_str()); - }); - } -} - -PromiseBasedCall::Completion PromiseBasedCall::StartCompletion( - void* tag, bool is_closure, const grpc_op* ops) { - Completion c(BatchSlotForOp(ops[0].op)); - if (!is_closure) { - grpc_cq_begin_op(cq(), tag); - } - completion_info_[c.index()].pending.Start(is_closure, tag); - if (grpc_call_trace.enabled()) { - gpr_log(GPR_INFO, "%s[call] StartCompletion %s", DebugTag().c_str(), - CompletionString(c).c_str()); - } - return c; -} - -PromiseBasedCall::Completion PromiseBasedCall::AddOpToCompletion( - const Completion& completion, PendingOp reason) { - if (grpc_call_trace.enabled()) { - gpr_log(GPR_INFO, "%s[call] AddOpToCompletion %s %s", DebugTag().c_str(), - CompletionString(completion).c_str(), PendingOpString(reason)); - } - CHECK(completion.has_value()); - completion_info_[completion.index()].pending.AddPendingBit(reason); - return Completion(completion.index()); -} - -void PromiseBasedCall::FailCompletion(const Completion& completion, - SourceLocation location) { - if (grpc_call_trace.enabled()) { - gpr_log(location.file(), location.line(), GPR_LOG_SEVERITY_ERROR, - "%s[call] FailCompletion %s", DebugTag().c_str(), - CompletionString(completion).c_str()); - } - completion_info_[completion.index()].pending.MarkFailed(); -} - -void PromiseBasedCall::ForceCompletionSuccess(const Completion& completion) { - completion_info_[completion.index()].pending.MarkForceSuccess(); -} - -void PromiseBasedCall::FinishOpOnCompletion(Completion* completion, - PendingOp reason) { - if (grpc_call_trace.enabled()) { - gpr_log(GPR_INFO, "%s[call] FinishOpOnCompletion completion:%s finish:%s", - DebugTag().c_str(), CompletionString(*completion).c_str(), - PendingOpString(reason)); - } - const uint8_t i = completion->TakeIndex(); - CHECK(i < GPR_ARRAY_SIZE(completion_info_)); - CompletionInfo::Pending& pending = completion_info_[i].pending; - bool success; - switch (pending.RemovePendingBit(reason)) { - case CompletionInfo::kPending: - return; // Early out - case CompletionInfo::kSuccess: - success = true; - break; - case CompletionInfo::kFailure: - success = false; - break; - } - if (pending.is_recv_message && !success && *recv_message_ != nullptr) { - grpc_byte_buffer_destroy(*recv_message_); - *recv_message_ = nullptr; - } - auto error = success ? absl::OkStatus() : absl::CancelledError(); - if (pending.is_closure) { - ExecCtx::Run(DEBUG_LOCATION, static_cast(pending.tag), - error); - } else { - InternalRef("cq_end_op"); - grpc_cq_end_op( - cq(), pending.tag, error, - [](void* p, grpc_cq_completion*) { - static_cast(p)->InternalUnref("cq_end_op"); - }, - this, &completion_info_[i].completion); - } -} - -void PromiseBasedCall::StartSendMessage(const grpc_op& op, - const Completion& completion, - PipeSender* sender, - Party::BulkSpawner& spawner) { - QueueSend(); - SliceBuffer send; - grpc_slice_buffer_swap( - &op.data.send_message.send_message->data.raw.slice_buffer, - send.c_slice_buffer()); - auto msg = arena()->MakePooled(std::move(send), op.flags); - spawner.Spawn( - "call_send_message", - [this, sender, msg = std::move(msg)]() mutable { - EnactSend(); - return sender->Push(std::move(msg)); - }, - [this, completion = AddOpToCompletion( - completion, PendingOp::kSendMessage)](bool result) mutable { - if (grpc_call_trace.enabled()) { - gpr_log(GPR_DEBUG, "%sSendMessage completes %s", DebugTag().c_str(), - result ? "successfully" : "with failure"); - } - if (!result) FailCompletion(completion); - FinishOpOnCompletion(&completion, PendingOp::kSendMessage); - }); -} - -template -void PromiseBasedCall::StartRecvMessage( - const grpc_op& op, const Completion& completion, - FirstPromiseFactory first_promise_factory, - PipeReceiver* receiver, bool cancel_on_error, - Party::BulkSpawner& spawner) { - if (grpc_call_trace.enabled()) { - gpr_log(GPR_INFO, "%s[call] Start RecvMessage: %s", DebugTag().c_str(), - CompletionString(completion).c_str()); - } - recv_message_ = op.data.recv_message.recv_message; - spawner.Spawn( - "call_recv_message", - [first_promise_factory = std::move(first_promise_factory), receiver]() { - return Seq(first_promise_factory(), receiver->Next()); - }, - [this, cancel_on_error, - completion = AddOpToCompletion(completion, PendingOp::kReceiveMessage)]( - NextResult result) mutable { - if (result.has_value()) { - MessageHandle& message = *result; - NoteLastMessageFlags(message->flags()); - if ((message->flags() & GRPC_WRITE_INTERNAL_COMPRESS) && - (incoming_compression_algorithm() != GRPC_COMPRESS_NONE)) { - *recv_message_ = grpc_raw_compressed_byte_buffer_create( - nullptr, 0, incoming_compression_algorithm()); - } else { - *recv_message_ = grpc_raw_byte_buffer_create(nullptr, 0); - } - grpc_slice_buffer_move_into(message->payload()->c_slice_buffer(), - &(*recv_message_)->data.raw.slice_buffer); - if (grpc_call_trace.enabled()) { - gpr_log(GPR_INFO, - "%s[call] RecvMessage: outstanding_recv " - "finishes: received %" PRIdPTR " byte message", - DebugTag().c_str(), - (*recv_message_)->data.raw.slice_buffer.length); - } - } else if (result.cancelled()) { - if (grpc_call_trace.enabled()) { - gpr_log(GPR_INFO, - "%s[call] RecvMessage: outstanding_recv " - "finishes: received end-of-stream with error", - DebugTag().c_str()); - } - set_failed_before_recv_message(); - FailCompletion(completion); - if (cancel_on_error) CancelWithError(absl::CancelledError()); - *recv_message_ = nullptr; - } else { - if (grpc_call_trace.enabled()) { - gpr_log(GPR_INFO, - "%s[call] RecvMessage: outstanding_recv " - "finishes: received end-of-stream", - DebugTag().c_str()); - } - *recv_message_ = nullptr; - } - FinishOpOnCompletion(&completion, PendingOp::kReceiveMessage); - }); -} - -/////////////////////////////////////////////////////////////////////////////// -// CallContext - -void CallContext::RunInContext(absl::AnyInvocable fn) { - call_->RunInContext(std::move(fn)); -} - -void CallContext::IncrementRefCount(const char* reason) { - call_->InternalRef(reason); -} - -void CallContext::Unref(const char* reason) { call_->InternalUnref(reason); } - -RefCountedPtr CallContext::MakeCallSpine( - CallArgs call_args) { - return call_->MakeCallSpine(std::move(call_args)); -} - -grpc_call* CallContext::c_call() { return call_->c_ptr(); } - -/////////////////////////////////////////////////////////////////////////////// -// PublishMetadataArray - -namespace { -void PublishMetadataArray(grpc_metadata_batch* md, grpc_metadata_array* array, - bool is_client) { - const auto md_count = md->count(); - if (md_count > array->capacity) { - array->capacity = - std::max(array->capacity + md->count(), array->capacity * 3 / 2); - array->metadata = static_cast( - gpr_realloc(array->metadata, sizeof(grpc_metadata) * array->capacity)); - } - PublishToAppEncoder encoder(array, md, is_client); - md->Encode(&encoder); -} -} // namespace - -/////////////////////////////////////////////////////////////////////////////// -// ClientPromiseBasedCall - -#ifdef GRPC_EXPERIMENT_IS_INCLUDED_PROMISE_BASED_CLIENT_CALL -class ClientPromiseBasedCall final : public PromiseBasedCall { - public: - 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( - grpc_cq_pollset(args->cq)) - : (args->pollset_set_alternative != nullptr - ? grpc_polling_entity_create_from_pollset_set( - args->pollset_set_alternative) - : grpc_polling_entity{})) { - global_stats().IncrementClientCallsCreated(); - if (args->cq != nullptr) { - CHECK(args->pollset_set_alternative == nullptr) - << "Only one of 'cq' and 'pollset_set_alternative' should be " - "non-nullptr."; - } - ScopedContext context(this); - args->channel->channel_stack()->stats_plugin_group->AddClientCallTracers( - *args->path, args->registered_method, GetArena()); - send_initial_metadata_ = Arena::MakePooled(); - send_initial_metadata_->Set(HttpPathMetadata(), std::move(*args->path)); - if (args->authority.has_value()) { - send_initial_metadata_->Set(HttpAuthorityMetadata(), - std::move(*args->authority)); - } - send_initial_metadata_->Set(GrpcRegisteredMethod(), - reinterpret_cast(static_cast( - args->registered_method))); - if (auto* channelz_channel = channel()->channelz_node()) { - channelz_channel->RecordCallStarted(); - } - if (args->send_deadline != Timestamp::InfFuture()) { - UpdateDeadline(args->send_deadline); - } - Call* parent = Call::FromC(args->parent); - if (parent != nullptr) { - auto parent_status = InitParent(parent, args->propagation_mask); - if (!parent_status.ok()) { - CancelWithError(std::move(parent_status)); - } - PublishToParent(parent); - } - } - - void OrphanCall() override { MaybeUnpublishFromParent(); } - - ~ClientPromiseBasedCall() override { - ScopedContext context(this); - send_initial_metadata_.reset(); - // Need to destroy the pipes under the ScopedContext above, so we - // move them out here and then allow the destructors to run at - // end of scope, but before context. - auto c2s = std::move(client_to_server_messages_); - auto s2c = std::move(server_to_client_messages_); - auto sim = std::move(server_initial_metadata_); - } - - void CancelWithError(absl::Status error) override { - if (cancel_with_error_called_.exchange(true, std::memory_order_relaxed)) { - return; - } - if (!started_.exchange(true, std::memory_order_relaxed)) { - // Initial metadata not sent yet, so we can just fail the call. - Spawn( - "cancel_before_initial_metadata", - [error = std::move(error), this]() { - server_to_client_messages_.sender.Close(); - auto md = ServerMetadataFromStatus(error); - md->Set(GrpcCallWasCancelled(), true); - Finish(std::move(md)); - return Empty{}; - }, - [](Empty) {}); - } else { - Spawn( - "cancel_with_error", - [error = std::move(error), this]() { - if (!cancel_error_.is_set()) { - auto md = ServerMetadataFromStatus(error); - md->Set(GrpcCallWasCancelled(), true); - cancel_error_.Set(std::move(md)); - } - return Empty{}; - }, - [](Empty) {}); - } - } - absl::string_view GetServerAuthority() const override { abort(); } - bool is_trailers_only() const override { return is_trailers_only_; } - - grpc_call_error StartBatch(const grpc_op* ops, size_t nops, void* notify_tag, - bool is_notify_tag_closure) override; - - std::string DebugTag() const override { - return absl::StrFormat("CLIENT_CALL[%p]: ", this); - } - - RefCountedPtr MakeCallSpine(CallArgs call_args) final { - class WrappingCallSpine final : public PipeBasedCallSpine { - public: - WrappingCallSpine(ClientPromiseBasedCall* call, - ClientMetadataHandle metadata) - : call_(call) { - call_->InternalRef("call-spine"); - SpawnInfallible( - "send_client_initial_metadata", - [self = Ref(), metadata = std::move(metadata)]() mutable { - return Map(self->client_initial_metadata_.sender.Push( - std::move(metadata)), - [self](bool) { return Empty{}; }); - }); - } - - ~WrappingCallSpine() override { - { - ScopedContext context(call_); - // Move these out and destroy before the internal unref. - auto client_initial_metadata = std::move(client_initial_metadata_); - auto server_trailing_metadata = std::move(server_trailing_metadata_); - } - call_->InternalUnref("call-spine"); - } - - Pipe& client_initial_metadata() override { - return client_initial_metadata_; - } - - Pipe& client_to_server_messages() override { - return call_->client_to_server_messages_; - } - - Pipe& server_initial_metadata() override { - return call_->server_initial_metadata_; - } - - Pipe& server_to_client_messages() override { - return call_->server_to_client_messages_; - } - - Latch& cancel_latch() override { - return cancel_error_; - } - - Latch& was_cancelled_latch() override { - return was_cancelled_latch_; - } - - Party& party() override { return *call_; } - Arena* arena() override { return call_->arena(); } - - void IncrementRefCount() override { refs_.Ref(); } - void Unref() override { - if (refs_.Unref()) delete this; - } - RefCountedPtr Ref() { - IncrementRefCount(); - return RefCountedPtr(this); - } - - ClientMetadata& UnprocessedClientInitialMetadata() override { - Crash("not for v2"); - } - - void V2HackToStartCallWithoutACallFilterStack() override {} - - private: - RefCount refs_; - ClientPromiseBasedCall* const call_; - std::atomic sent_trailing_metadata_{false}; - Pipe client_initial_metadata_{call_->arena()}; - Pipe server_trailing_metadata_{call_->arena()}; - Latch cancel_error_; - Latch was_cancelled_latch_; - }; - CHECK(call_args.server_initial_metadata == - &server_initial_metadata_.sender); - CHECK(call_args.client_to_server_messages == - &client_to_server_messages_.receiver); - CHECK(call_args.server_to_client_messages == - &server_to_client_messages_.sender); - call_args.client_initial_metadata_outstanding.Complete(true); - return MakeRefCounted( - this, std::move(call_args.client_initial_metadata)); - } - - private: - // Finish the call with the given status/trailing metadata. - void Finish(ServerMetadataHandle trailing_metadata); - // Validate that a set of ops is valid for a client call. - grpc_call_error ValidateBatch(const grpc_op* ops, size_t nops) const; - // Commit a valid batch of operations to be executed. - void CommitBatch(const grpc_op* ops, size_t nops, - const Completion& completion); - // Start the underlying promise. - void StartPromise(ClientMetadataHandle client_initial_metadata, - const Completion& completion, Party::BulkSpawner& spawner); - // Start receiving initial metadata - void StartRecvInitialMetadata(grpc_metadata_array* array, - const Completion& completion, - Party::BulkSpawner& spawner); - void StartRecvStatusOnClient( - const Completion& completion, - grpc_op::grpc_op_data::grpc_op_recv_status_on_client op_args, - Party::BulkSpawner& spawner); - // Publish status out to the application. - void PublishStatus( - grpc_op::grpc_op_data::grpc_op_recv_status_on_client op_args, - ServerMetadataHandle trailing_metadata); - // Publish server initial metadata out to the application. - void PublishInitialMetadata(ServerMetadata* metadata); - - ClientMetadataHandle send_initial_metadata_; - Pipe server_initial_metadata_{GetArena()}; - Latch server_trailing_metadata_; - Latch cancel_error_; - Latch polling_entity_; - Pipe client_to_server_messages_{GetArena()}; - Pipe server_to_client_messages_{GetArena()}; - bool is_trailers_only_ = false; - bool scheduled_receive_status_ = false; - bool scheduled_send_close_ = false; - // True once the promise for the call is started. - // This corresponds to sending initial metadata, or cancelling before doing - // so. - // In the latter case real world code sometimes does not sent the initial - // metadata, and so gating based upon that does not work out. - std::atomic started_{false}; - // True after the first CancelWithError call - prevents spamming cancels from - // overflowing the party. - std::atomic cancel_with_error_called_{false}; - // TODO(ctiller): delete when we remove the filter based API (may require some - // cleanup in wrapped languages: they depend on this to hold slice refs) - ServerMetadataHandle recv_initial_metadata_; - ServerMetadataHandle recv_trailing_metadata_; -}; - -void ClientPromiseBasedCall::StartPromise( - ClientMetadataHandle client_initial_metadata, const Completion& completion, - Party::BulkSpawner& spawner) { - auto token = ClientInitialMetadataOutstandingToken::New(arena()); - spawner.Spawn( - "call_send_initial_metadata", token.Wait(), - [this, - completion = AddOpToCompletion( - completion, PendingOp::kSendInitialMetadata)](bool result) mutable { - if (!result) FailCompletion(completion); - FinishOpOnCompletion(&completion, PendingOp::kSendInitialMetadata); - }); - spawner.Spawn( - "client_promise", - [this, client_initial_metadata = std::move(client_initial_metadata), - token = std::move(token)]() mutable { - return Race( - cancel_error_.Wait(), - Map(channel()->channel_stack()->MakeClientCallPromise(CallArgs{ - std::move(client_initial_metadata), std::move(token), - &polling_entity_, &server_initial_metadata_.sender, - &client_to_server_messages_.receiver, - &server_to_client_messages_.sender}), - [this](ServerMetadataHandle trailing_metadata) { - // If we're cancelled the transport doesn't get to return - // stats. - AcceptTransportStatsFromContext(); - return trailing_metadata; - })); - }, - [this](ServerMetadataHandle trailing_metadata) { - Finish(std::move(trailing_metadata)); - }); -} - -grpc_call_error ClientPromiseBasedCall::ValidateBatch(const grpc_op* ops, - size_t nops) const { - BitSet<8> got_ops; - for (size_t op_idx = 0; op_idx < nops; op_idx++) { - const grpc_op& op = ops[op_idx]; - switch (op.op) { - case GRPC_OP_SEND_INITIAL_METADATA: - if (!AreInitialMetadataFlagsValid(op.flags)) { - return GRPC_CALL_ERROR_INVALID_FLAGS; - } - if (!ValidateMetadata(op.data.send_initial_metadata.count, - op.data.send_initial_metadata.metadata)) { - return GRPC_CALL_ERROR_INVALID_METADATA; - } - break; - case GRPC_OP_SEND_MESSAGE: - if (!AreWriteFlagsValid(op.flags)) { - return GRPC_CALL_ERROR_INVALID_FLAGS; - } - break; - case GRPC_OP_RECV_INITIAL_METADATA: - case GRPC_OP_RECV_MESSAGE: - if (op.flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; - break; - case GRPC_OP_SEND_CLOSE_FROM_CLIENT: - if (scheduled_send_close_) return GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; - if (op.flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; - break; - case GRPC_OP_RECV_STATUS_ON_CLIENT: - if (op.flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; - if (scheduled_receive_status_) { - return GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; - } - break; - case GRPC_OP_RECV_CLOSE_ON_SERVER: - case GRPC_OP_SEND_STATUS_FROM_SERVER: - return GRPC_CALL_ERROR_NOT_ON_CLIENT; - } - if (got_ops.is_set(op.op)) { - return GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; - } - got_ops.set(op.op); - } - return GRPC_CALL_OK; -} - -void ClientPromiseBasedCall::CommitBatch(const grpc_op* ops, size_t nops, - const Completion& completion) { - Party::BulkSpawner spawner(this); - for (size_t op_idx = 0; op_idx < nops; op_idx++) { - const grpc_op& op = ops[op_idx]; - switch (op.op) { - case GRPC_OP_SEND_INITIAL_METADATA: { - if (started_.exchange(true, std::memory_order_relaxed)) break; - CToMetadata(op.data.send_initial_metadata.metadata, - op.data.send_initial_metadata.count, - send_initial_metadata_.get()); - PrepareOutgoingInitialMetadata(op, *send_initial_metadata_); - if (send_deadline() != Timestamp::InfFuture()) { - send_initial_metadata_->Set(GrpcTimeoutMetadata(), send_deadline()); - } - send_initial_metadata_->Set( - WaitForReady(), - WaitForReady::ValueType{ - (op.flags & GRPC_INITIAL_METADATA_WAIT_FOR_READY) != 0, - (op.flags & - GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET) != 0}); - StartPromise(std::move(send_initial_metadata_), completion, spawner); - } break; - case GRPC_OP_RECV_INITIAL_METADATA: { - StartRecvInitialMetadata( - op.data.recv_initial_metadata.recv_initial_metadata, completion, - spawner); - } break; - case GRPC_OP_RECV_STATUS_ON_CLIENT: { - scheduled_receive_status_ = true; - StartRecvStatusOnClient(completion, op.data.recv_status_on_client, - spawner); - } break; - case GRPC_OP_SEND_MESSAGE: - StartSendMessage(op, completion, &client_to_server_messages_.sender, - spawner); - break; - case GRPC_OP_RECV_MESSAGE: - StartRecvMessage( - op, completion, - [this]() { - return Race(server_initial_metadata_.receiver.AwaitClosed(), - server_to_client_messages_.receiver.AwaitClosed()); - }, - &server_to_client_messages_.receiver, false, spawner); - break; - case GRPC_OP_SEND_CLOSE_FROM_CLIENT: - scheduled_send_close_ = true; - spawner.Spawn( - "send_close_from_client", - [this]() { - client_to_server_messages_.sender.Close(); - return Empty{}; - }, - [this, - completion = AddOpToCompletion( - completion, PendingOp::kSendCloseFromClient)](Empty) mutable { - FinishOpOnCompletion(&completion, - PendingOp::kSendCloseFromClient); - }); - break; - case GRPC_OP_SEND_STATUS_FROM_SERVER: - case GRPC_OP_RECV_CLOSE_ON_SERVER: - abort(); // unreachable - } - } -} - -grpc_call_error ClientPromiseBasedCall::StartBatch(const grpc_op* ops, - size_t nops, - void* notify_tag, - bool is_notify_tag_closure) { - if (nops == 0) { - EndOpImmediately(cq(), notify_tag, is_notify_tag_closure); - return GRPC_CALL_OK; - } - const grpc_call_error validation_result = ValidateBatch(ops, nops); - if (validation_result != GRPC_CALL_OK) { - return validation_result; - } - Completion completion = - StartCompletion(notify_tag, is_notify_tag_closure, ops); - CommitBatch(ops, nops, completion); - FinishOpOnCompletion(&completion, PendingOp::kStartingBatch); - return GRPC_CALL_OK; -} - -void ClientPromiseBasedCall::StartRecvInitialMetadata( - grpc_metadata_array* array, const Completion& completion, - Party::BulkSpawner& spawner) { - spawner.Spawn( - "recv_initial_metadata", - [this]() { - return Race(server_initial_metadata_.receiver.Next(), - Map(finished(), [](Empty) { - return NextResult(true); - })); - }, - [this, array, - completion = - AddOpToCompletion(completion, PendingOp::kReceiveInitialMetadata)]( - NextResult next_metadata) mutable { - server_initial_metadata_.sender.Close(); - ServerMetadataHandle metadata; - if (grpc_call_trace.enabled()) { - gpr_log(GPR_INFO, "%s[call] RecvTrailingMetadata: %s", - DebugTag().c_str(), - next_metadata.has_value() - ? next_metadata.value()->DebugString().c_str() - : "null"); - } - if (next_metadata.has_value()) { - metadata = std::move(next_metadata.value()); - is_trailers_only_ = metadata->get(GrpcTrailersOnly()).value_or(false); - } else { - is_trailers_only_ = true; - metadata = arena()->MakePooled(); - } - ProcessIncomingInitialMetadata(*metadata); - PublishMetadataArray(metadata.get(), array, true); - recv_initial_metadata_ = std::move(metadata); - FinishOpOnCompletion(&completion, PendingOp::kReceiveInitialMetadata); - }); -} - -void ClientPromiseBasedCall::Finish(ServerMetadataHandle trailing_metadata) { - if (grpc_call_trace.enabled()) { - gpr_log(GPR_INFO, "%s[call] Finish: %s", DebugTag().c_str(), - trailing_metadata->DebugString().c_str()); - } - ResetDeadline(); - set_completed(); - client_to_server_messages_.sender.CloseWithError(); - client_to_server_messages_.receiver.CloseWithError(); - if (trailing_metadata->get(GrpcCallWasCancelled()).value_or(false)) { - server_to_client_messages_.receiver.CloseWithError(); - server_initial_metadata_.receiver.CloseWithError(); - } - if (auto* channelz_channel = channel()->channelz_node()) { - if (trailing_metadata->get(GrpcStatusMetadata()) - .value_or(GRPC_STATUS_UNKNOWN) == GRPC_STATUS_OK) { - channelz_channel->RecordCallSucceeded(); - } else { - channelz_channel->RecordCallFailed(); - } - } - server_trailing_metadata_.Set(std::move(trailing_metadata)); -} - -namespace { -std::string MakeErrorString(const ServerMetadata* trailing_metadata) { - std::string out = absl::StrCat( - trailing_metadata->get(GrpcStatusFromWire()).value_or(false) - ? "Error received from peer" - : "Error generated by client", - "grpc_status: ", - grpc_status_code_to_string(trailing_metadata->get(GrpcStatusMetadata()) - .value_or(GRPC_STATUS_UNKNOWN))); - if (const Slice* message = - trailing_metadata->get_pointer(GrpcMessageMetadata())) { - absl::StrAppend(&out, "\ngrpc_message: ", message->as_string_view()); - } - if (auto annotations = trailing_metadata->get_pointer(GrpcStatusContext())) { - absl::StrAppend(&out, "\nStatus Context:"); - for (const std::string& annotation : *annotations) { - absl::StrAppend(&out, "\n ", annotation); - } - } - return out; -} -} // namespace - -void ClientPromiseBasedCall::StartRecvStatusOnClient( - const Completion& completion, - grpc_op::grpc_op_data::grpc_op_recv_status_on_client op_args, - Party::BulkSpawner& spawner) { - ForceCompletionSuccess(completion); - spawner.Spawn( - "recv_status_on_client", server_trailing_metadata_.Wait(), - [this, op_args, - completion = - AddOpToCompletion(completion, PendingOp::kReceiveStatusOnClient)]( - ServerMetadataHandle trailing_metadata) mutable { - const grpc_status_code status = - trailing_metadata->get(GrpcStatusMetadata()) - .value_or(GRPC_STATUS_UNKNOWN); - *op_args.status = status; - Slice message_slice; - if (Slice* message = - trailing_metadata->get_pointer(GrpcMessageMetadata())) { - message_slice = message->Ref(); - } - SetFinalizationStatus(status, message_slice.Ref()); - *op_args.status_details = message_slice.TakeCSlice(); - if (op_args.error_string != nullptr && status != GRPC_STATUS_OK) { - *op_args.error_string = - gpr_strdup(MakeErrorString(trailing_metadata.get()).c_str()); - } - PublishMetadataArray(trailing_metadata.get(), op_args.trailing_metadata, - true); - recv_trailing_metadata_ = std::move(trailing_metadata); - FinishOpOnCompletion(&completion, PendingOp::kReceiveStatusOnClient); - }); -} -#endif - -/////////////////////////////////////////////////////////////////////////////// -// CallSpine based Server Call - -grpc_call_error ValidateServerBatch(const grpc_op* ops, size_t nops) { - BitSet<8> got_ops; - for (size_t op_idx = 0; op_idx < nops; op_idx++) { - const grpc_op& op = ops[op_idx]; - switch (op.op) { - case GRPC_OP_SEND_INITIAL_METADATA: - if (!AreInitialMetadataFlagsValid(op.flags)) { - return GRPC_CALL_ERROR_INVALID_FLAGS; - } - if (!ValidateMetadata(op.data.send_initial_metadata.count, - op.data.send_initial_metadata.metadata)) { - return GRPC_CALL_ERROR_INVALID_METADATA; - } - break; - case GRPC_OP_SEND_MESSAGE: - if (!AreWriteFlagsValid(op.flags)) { - return GRPC_CALL_ERROR_INVALID_FLAGS; - } - break; - case GRPC_OP_SEND_STATUS_FROM_SERVER: - if (op.flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; - if (!ValidateMetadata( - op.data.send_status_from_server.trailing_metadata_count, - op.data.send_status_from_server.trailing_metadata)) { - return GRPC_CALL_ERROR_INVALID_METADATA; - } - break; - case GRPC_OP_RECV_MESSAGE: - case GRPC_OP_RECV_CLOSE_ON_SERVER: - if (op.flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; - break; - case GRPC_OP_RECV_INITIAL_METADATA: - case GRPC_OP_SEND_CLOSE_FROM_CLIENT: - case GRPC_OP_RECV_STATUS_ON_CLIENT: - return GRPC_CALL_ERROR_NOT_ON_SERVER; - } - if (got_ops.is_set(op.op)) return GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; - got_ops.set(op.op); - } - return GRPC_CALL_OK; -} - -class ServerCall final : public Call, public DualRefCounted { - public: - ServerCall(ClientMetadataHandle client_initial_metadata, - CallHandler call_handler, ServerInterface* server, - grpc_completion_queue* cq) - : Call(false, - client_initial_metadata->get(GrpcTimeoutMetadata()) - .value_or(Timestamp::InfFuture()), - call_handler.event_engine()), - call_handler_(std::move(call_handler)), - client_initial_metadata_stored_(std::move(client_initial_metadata)), - cq_(cq), - server_(server) { - call_handler_.arena()->SetContext(this); - global_stats().IncrementServerCallsCreated(); - } - - void CancelWithError(grpc_error_handle error) override { - call_handler_.SpawnInfallible( - "CancelWithError", - [self = WeakRefAsSubclass(), error = std::move(error)] { - auto status = ServerMetadataFromStatus(error); - status->Set(GrpcCallWasCancelled(), true); - self->call_handler_.PushServerTrailingMetadata(std::move(status)); - return Empty{}; - }); - } - bool is_trailers_only() const override { - Crash("is_trailers_only not implemented for server calls"); - } - absl::string_view GetServerAuthority() const override { - Crash("unimplemented"); - } - grpc_call_error StartBatch(const grpc_op* ops, size_t nops, void* notify_tag, - bool is_notify_tag_closure) override; - - Arena* arena() override { return call_handler_.arena(); } - - grpc_event_engine::experimental::EventEngine* event_engine() const override { - return call_handler_.event_engine(); - } - - void ExternalRef() override { Ref().release(); } - void ExternalUnref() override { Unref(); } - void InternalRef(const char*) override { WeakRef().release(); } - void InternalUnref(const char*) override { WeakUnref(); } - - void Orphaned() override { - // TODO(ctiller): only when we're not already finished - CancelWithError(absl::CancelledError()); - } - - void SetCompletionQueue(grpc_completion_queue*) override { - Crash("unimplemented"); - } - - grpc_compression_options compression_options() override { - return server_->compression_options(); - } - - grpc_call_stack* call_stack() override { return nullptr; } - - char* GetPeer() override { - Slice peer_slice = GetPeerString(); - if (!peer_slice.empty()) { - absl::string_view peer_string_view = peer_slice.as_string_view(); - char* peer_string = - static_cast(gpr_malloc(peer_string_view.size() + 1)); - memcpy(peer_string, peer_string_view.data(), peer_string_view.size()); - peer_string[peer_string_view.size()] = '\0'; - return peer_string; - } - return gpr_strdup("unknown"); - } - - bool Completed() final { Crash("unimplemented"); } - bool failed_before_recv_message() const final { Crash("unimplemented"); } - - private: - void CommitBatch(const grpc_op* ops, size_t nops, void* notify_tag, - bool is_notify_tag_closure); - StatusFlag FinishRecvMessage( - ValueOrFailure> result); - - std::string DebugTag() { return absl::StrFormat("SERVER_CALL[%p]: ", this); } - - CallHandler call_handler_; - grpc_byte_buffer** recv_message_ = nullptr; - ClientMetadataHandle client_initial_metadata_stored_; - grpc_completion_queue* const cq_; - ServerInterface* const server_; -}; - -grpc_call_error ServerCall::StartBatch(const grpc_op* ops, size_t nops, - void* notify_tag, - bool is_notify_tag_closure) { - if (nops == 0) { - EndOpImmediately(cq_, notify_tag, is_notify_tag_closure); - return GRPC_CALL_OK; - } - const grpc_call_error validation_result = ValidateServerBatch(ops, nops); - if (validation_result != GRPC_CALL_OK) { - return validation_result; - } - CommitBatch(ops, nops, notify_tag, is_notify_tag_closure); - return GRPC_CALL_OK; -} - -namespace { -template -class MaybeOpImpl { - public: - using PromiseFactory = promise_detail::OncePromiseFactory; - using Promise = typename PromiseFactory::Promise; - static_assert(!std::is_same::value, - "PromiseFactory must return a promise"); - - MaybeOpImpl() : state_(State::kDismissed) {} - explicit MaybeOpImpl(SetupResult result) : state_(State::kPromiseFactory) { - Construct(&promise_factory_, std::move(result)); - } - - ~MaybeOpImpl() { - switch (state_) { - case State::kDismissed: - break; - case State::kPromiseFactory: - Destruct(&promise_factory_); - break; - case State::kPromise: - Destruct(&promise_); - break; - } - } - - MaybeOpImpl(const MaybeOpImpl&) = delete; - MaybeOpImpl& operator=(const MaybeOpImpl&) = delete; - MaybeOpImpl(MaybeOpImpl&& other) noexcept : state_(other.state_) { - switch (state_) { - case State::kDismissed: - break; - case State::kPromiseFactory: - Construct(&promise_factory_, std::move(other.promise_factory_)); - break; - case State::kPromise: - Construct(&promise_, std::move(other.promise_)); - break; - } - } - MaybeOpImpl& operator=(MaybeOpImpl&& other) noexcept = delete; - - Poll operator()() { - switch (state_) { - case State::kDismissed: - return Success{}; - case State::kPromiseFactory: { - auto promise = promise_factory_.Make(); - Destruct(&promise_factory_); - Construct(&promise_, std::move(promise)); - state_ = State::kPromise; - } - ABSL_FALLTHROUGH_INTENDED; - case State::kPromise: { - if (grpc_call_trace.enabled()) { - gpr_log(GPR_INFO, "%sBeginPoll %s", - Activity::current()->DebugTag().c_str(), OpName()); - } - auto r = poll_cast(promise_()); - if (grpc_call_trace.enabled()) { - gpr_log( - GPR_INFO, "%sEndPoll %s --> %s", - Activity::current()->DebugTag().c_str(), OpName(), - r.pending() ? "PENDING" : (r.value().ok() ? "OK" : "FAILURE")); - } - return r; - } - } - GPR_UNREACHABLE_CODE(return Pending{}); - } - - private: - enum class State { - kDismissed, - kPromiseFactory, - kPromise, - }; - - static const char* OpName() { - switch (kOp) { - case GRPC_OP_SEND_INITIAL_METADATA: - return "SendInitialMetadata"; - case GRPC_OP_SEND_MESSAGE: - return "SendMessage"; - case GRPC_OP_SEND_STATUS_FROM_SERVER: - return "SendStatusFromServer"; - case GRPC_OP_SEND_CLOSE_FROM_CLIENT: - return "SendCloseFromClient"; - case GRPC_OP_RECV_MESSAGE: - return "RecvMessage"; - case GRPC_OP_RECV_CLOSE_ON_SERVER: - return "RecvCloseOnServer"; - case GRPC_OP_RECV_INITIAL_METADATA: - return "RecvInitialMetadata"; - case GRPC_OP_RECV_STATUS_ON_CLIENT: - return "RecvStatusOnClient"; - } - Crash("Unreachable"); - } - - // gcc-12 has problems with this being a variant - GPR_NO_UNIQUE_ADDRESS State state_; - union { - PromiseFactory promise_factory_; - Promise promise_; - }; -}; - -// MaybeOp captures a fairly complicated dance we need to do for the batch -// API. We first check if an op is included or not, and if it is, we run the -// setup function in the context of the API call (NOT in the call party). This -// setup function returns a promise factory which we'll then run *in* the -// party to do initial setup, and have it return the promise that we'll -// ultimately poll on til completion. -// Once we express our surface API in terms of core internal types this whole -// dance will go away. -template -auto MaybeOp(const grpc_op* ops, const std::array& idxs, - SetupFn setup) { - using SetupResult = decltype(std::declval()(grpc_op())); - if (idxs[op_type] == 255) { - return MaybeOpImpl(); - } else { - auto r = setup(ops[idxs[op_type]]); - return MaybeOpImpl(std::move(r)); - } -} - -template -class PollBatchLogger { - public: - PollBatchLogger(void* tag, F f) : tag_(tag), f_(std::move(f)) {} - - auto operator()() { - if (grpc_call_trace.enabled()) { - gpr_log(GPR_INFO, "Poll batch %p", tag_); - } - auto r = f_(); - if (grpc_call_trace.enabled()) { - gpr_log(GPR_INFO, "Poll batch %p --> %s", tag_, ResultString(r).c_str()); - } - return r; - } - - private: - template - static std::string ResultString(Poll r) { - if (r.pending()) return "PENDING"; - return ResultString(r.value()); - } - static std::string ResultString(Empty) { return "DONE"; } - - void* tag_; - F f_; -}; - -template -PollBatchLogger LogPollBatch(void* tag, F f) { - return PollBatchLogger(tag, std::move(f)); -} -} // namespace - -StatusFlag ServerCall::FinishRecvMessage( - ValueOrFailure> result) { - if (!result.ok()) { - if (grpc_call_trace.enabled()) { - gpr_log(GPR_INFO, - "%s[call] RecvMessage: outstanding_recv " - "finishes: received end-of-stream with error", - DebugTag().c_str()); - } - *recv_message_ = nullptr; - recv_message_ = nullptr; - return Failure{}; - } - if (!result->has_value()) { - if (grpc_call_trace.enabled()) { - gpr_log(GPR_INFO, - "%s[call] RecvMessage: outstanding_recv " - "finishes: received end-of-stream", - DebugTag().c_str()); - } - *recv_message_ = nullptr; - recv_message_ = nullptr; - return Success{}; - } - MessageHandle& message = **result; - NoteLastMessageFlags(message->flags()); - if ((message->flags() & GRPC_WRITE_INTERNAL_COMPRESS) && - (incoming_compression_algorithm() != GRPC_COMPRESS_NONE)) { - *recv_message_ = grpc_raw_compressed_byte_buffer_create( - nullptr, 0, incoming_compression_algorithm()); - } else { - *recv_message_ = grpc_raw_byte_buffer_create(nullptr, 0); - } - grpc_slice_buffer_move_into(message->payload()->c_slice_buffer(), - &(*recv_message_)->data.raw.slice_buffer); - if (grpc_call_trace.enabled()) { - gpr_log(GPR_INFO, - "%s[call] RecvMessage: outstanding_recv " - "finishes: received %" PRIdPTR " byte message", - DebugTag().c_str(), (*recv_message_)->data.raw.slice_buffer.length); - } - recv_message_ = nullptr; - return Success{}; -} - -void ServerCall::CommitBatch(const grpc_op* ops, size_t nops, void* notify_tag, - bool is_notify_tag_closure) { - std::array got_ops{255, 255, 255, 255, 255, 255, 255, 255}; - for (size_t op_idx = 0; op_idx < nops; op_idx++) { - const grpc_op& op = ops[op_idx]; - got_ops[op.op] = op_idx; - } - if (!is_notify_tag_closure) grpc_cq_begin_op(cq_, notify_tag); - auto send_initial_metadata = MaybeOp( - ops, got_ops, [this](const grpc_op& op) { - auto metadata = arena()->MakePooled(); - PrepareOutgoingInitialMetadata(op, *metadata); - CToMetadata(op.data.send_initial_metadata.metadata, - op.data.send_initial_metadata.count, metadata.get()); - if (grpc_call_trace.enabled()) { - gpr_log(GPR_INFO, "%s[call] Send initial metadata", - DebugTag().c_str()); - } - return [this, metadata = std::move(metadata)]() mutable { - return call_handler_.PushServerInitialMetadata(std::move(metadata)); - }; - }); - auto send_message = - MaybeOp(ops, got_ops, [this](const grpc_op& op) { - SliceBuffer send; - grpc_slice_buffer_swap( - &op.data.send_message.send_message->data.raw.slice_buffer, - send.c_slice_buffer()); - auto msg = arena()->MakePooled(std::move(send), op.flags); - return [this, msg = std::move(msg)]() mutable { - return call_handler_.PushMessage(std::move(msg)); - }; - }); - auto send_trailing_metadata = MaybeOp( - ops, got_ops, [this](const grpc_op& op) { - auto metadata = arena()->MakePooled(); - CToMetadata(op.data.send_status_from_server.trailing_metadata, - op.data.send_status_from_server.trailing_metadata_count, - metadata.get()); - metadata->Set(GrpcStatusMetadata(), - op.data.send_status_from_server.status); - if (auto* details = op.data.send_status_from_server.status_details) { - // TODO(ctiller): this should not be a copy, but we have - // callers that allocate and pass in a slice created with - // grpc_slice_from_static_string and then delete the string - // after passing it in, which shouldn't be a supported API. - metadata->Set(GrpcMessageMetadata(), - Slice(grpc_slice_copy(*details))); - } - CHECK(metadata != nullptr); - return [this, metadata = std::move(metadata)]() mutable { - CHECK(metadata != nullptr); - return [this, - metadata = std::move(metadata)]() mutable -> Poll { - CHECK(metadata != nullptr); - call_handler_.PushServerTrailingMetadata(std::move(metadata)); - return Success{}; - }; - }; - }); - auto recv_message = - MaybeOp(ops, got_ops, [this](const grpc_op& op) { - CHECK_EQ(recv_message_, nullptr); - recv_message_ = op.data.recv_message.recv_message; - return [this]() mutable { - return Map(call_handler_.PullMessage(), - [this](ValueOrFailure> msg) { - return FinishRecvMessage(std::move(msg)); - }); - }; - }); - auto primary_ops = AllOk( - TrySeq(AllOk(std::move(send_initial_metadata), - std::move(send_message)), - std::move(send_trailing_metadata)), - std::move(recv_message)); - if (got_ops[GRPC_OP_RECV_CLOSE_ON_SERVER] != 255) { - auto recv_trailing_metadata = MaybeOp( - ops, got_ops, [this](const grpc_op& op) { - return [this, cancelled = op.data.recv_close_on_server.cancelled]() { - return Map(call_handler_.WasCancelled(), - [cancelled, this](bool result) -> Success { - ResetDeadline(); - *cancelled = result ? 1 : 0; - return Success{}; - }); - }; - }); - call_handler_.SpawnInfallible( - "final-batch", - [primary_ops = std::move(primary_ops), - recv_trailing_metadata = std::move(recv_trailing_metadata), - is_notify_tag_closure, notify_tag, this]() mutable { - return LogPollBatch( - notify_tag, - Seq(std::move(primary_ops), std::move(recv_trailing_metadata), - [is_notify_tag_closure, notify_tag, this](StatusFlag) { - return WaitForCqEndOp(is_notify_tag_closure, notify_tag, - absl::OkStatus(), cq_); - })); - }); - } else { - call_handler_.SpawnInfallible( - "batch", [primary_ops = std::move(primary_ops), is_notify_tag_closure, - notify_tag, this]() mutable { - return LogPollBatch( - notify_tag, - Seq(std::move(primary_ops), [is_notify_tag_closure, notify_tag, - this](StatusFlag r) { - return WaitForCqEndOp(is_notify_tag_closure, notify_tag, - StatusCast(r), cq_); - })); - }); - } -} - -grpc_call* MakeServerCall(CallHandler call_handler, - ClientMetadataHandle client_initial_metadata, - ServerInterface* server, grpc_completion_queue* cq, - grpc_metadata_array* publish_initial_metadata) { - PublishMetadataArray(client_initial_metadata.get(), publish_initial_metadata, - false); - // TODO(ctiller): ideally we'd put this in the arena with the CallHandler, - // but there's an ownership problem: CallHandler owns the arena, and so would - // get destroyed before the base class Call destructor runs, leading to - // UB/crash. Investigate another path. - return (new ServerCall(std::move(client_initial_metadata), - std::move(call_handler), server, cq)) - ->c_ptr(); -} - -} // namespace grpc_core - -/////////////////////////////////////////////////////////////////////////////// -// C-based API - -void* grpc_call_arena_alloc(grpc_call* call, size_t size) { - grpc_core::ExecCtx exec_ctx; - return grpc_core::Call::FromC(call)->arena()->Alloc(size); -} - -size_t grpc_call_get_initial_size_estimate() { - return grpc_core::FilterStackCall::InitialSizeEstimate(); -} - -grpc_error_handle grpc_call_create(grpc_call_create_args* args, - grpc_call** out_call) { -#ifdef GRPC_EXPERIMENT_IS_INCLUDED_PROMISE_BASED_CLIENT_CALL - if (grpc_core::IsPromiseBasedClientCallEnabled() && - args->server_transport_data == nullptr && args->channel->is_promising()) { - return grpc_core::MakePromiseBasedCall( - args, out_call); - } -#endif -#ifdef GRPC_EXPERIMENT_IS_INCLUDED_PROMISE_BASED_SERVER_CALL - if (grpc_core::IsPromiseBasedServerCallEnabled() && - args->server_transport_data != nullptr && args->channel->is_promising()) { - return grpc_core::MakePromiseBasedCall( - args, out_call); - } -#endif - return grpc_core::FilterStackCall::Create(args, out_call); -} - -void grpc_call_set_completion_queue(grpc_call* call, - grpc_completion_queue* cq) { - grpc_core::Call::FromC(call)->SetCompletionQueue(cq); -} - -void grpc_call_ref(grpc_call* c) { grpc_core::Call::FromC(c)->ExternalRef(); } - -void grpc_call_unref(grpc_call* c) { - grpc_core::ExecCtx exec_ctx; - grpc_core::Call::FromC(c)->ExternalUnref(); +void grpc_call_unref(grpc_call* c) { + grpc_core::ExecCtx exec_ctx; + grpc_core::Call::FromC(c)->ExternalUnref(); } char* grpc_call_get_peer(grpc_call* call) { return grpc_core::Call::FromC(call)->GetPeer(); } -grpc_call* grpc_call_from_top_element(grpc_call_element* surface_element) { - return grpc_core::FilterStackCall::FromTopElem(surface_element)->c_ptr(); -} - grpc_call_error grpc_call_cancel(grpc_call* call, void* reserved) { GRPC_API_TRACE("grpc_call_cancel(call=%p, reserved=%p)", 2, (call, reserved)); CHECK_EQ(reserved, nullptr); @@ -3645,7 +449,7 @@ void grpc_call_cancel_internal(grpc_call* call) { grpc_compression_algorithm grpc_call_test_only_get_compression_algorithm( grpc_call* call) { - return grpc_core::Call::FromC(call)->test_only_compression_algorithm(); + return grpc_core::Call::FromC(call)->incoming_compression_algorithm(); } uint32_t grpc_call_test_only_get_message_flags(grpc_call* call) { diff --git a/src/core/lib/surface/call.h b/src/core/lib/surface/call.h index 038235841cd..b824e38f602 100644 --- a/src/core/lib/surface/call.h +++ b/src/core/lib/surface/call.h @@ -86,7 +86,7 @@ class Call : public CppImplOf, public grpc_event_engine::experimental::EventEngine:: Closure /* for deadlines */ { public: - virtual Arena* arena() = 0; + Arena* arena() { return arena_.get(); } bool is_client() const { return is_client_; } virtual bool Completed() = 0; @@ -112,10 +112,7 @@ class Call : public CppImplOf, return deadline_; } - grpc_compression_algorithm test_only_compression_algorithm() { - return incoming_compression_algorithm_; - } - uint32_t test_only_message_flags() { return test_only_last_message_flags_; } + virtual uint32_t test_only_message_flags() = 0; CompressionAlgorithmSet encodings_accepted_by_peer() { return encodings_accepted_by_peer_; } @@ -125,14 +122,20 @@ class Call : public CppImplOf, virtual grpc_call_stack* call_stack() = 0; // Return the EventEngine used for this call's async execution. - virtual grpc_event_engine::experimental::EventEngine* event_engine() - const = 0; + grpc_event_engine::experimental::EventEngine* event_engine() const { + return event_engine_; + } // Implementation of EventEngine::Closure, called when deadline expires void Run() final; gpr_cycle_counter start_time() const { return start_time_; } + void set_traced(bool traced) { traced_ = traced; } + bool traced() const { return traced_; } + + virtual grpc_compression_algorithm incoming_compression_algorithm() = 0; + protected: // The maximum number of concurrent batches possible. // Based upon the maximum number of individually queueable ops in the batch @@ -160,11 +163,8 @@ class Call : public CppImplOf, Call* sibling_prev = nullptr; }; - Call(bool is_client, Timestamp send_deadline, - grpc_event_engine::experimental::EventEngine* event_engine) - : send_deadline_(send_deadline), - is_client_(is_client), - event_engine_(event_engine) {} + Call(bool is_client, Timestamp send_deadline, RefCountedPtr arena, + grpc_event_engine::experimental::EventEngine* event_engine); ~Call() override = default; ParentCall* GetOrCreateParentCall(); @@ -200,12 +200,6 @@ class Call : public CppImplOf, // internal headers against external modification. void PrepareOutgoingInitialMetadata(const grpc_op& op, grpc_metadata_batch& md); - void NoteLastMessageFlags(uint32_t flags) { - test_only_last_message_flags_ = flags; - } - grpc_compression_algorithm incoming_compression_algorithm() const { - return incoming_compression_algorithm_; - } void HandleCompressionAlgorithmDisabled( grpc_compression_algorithm compression_algorithm) GPR_ATTRIBUTE_NOINLINE; @@ -214,20 +208,22 @@ class Call : public CppImplOf, virtual grpc_compression_options compression_options() = 0; + virtual void SetIncomingCompressionAlgorithm( + grpc_compression_algorithm algorithm) = 0; + private: + const RefCountedPtr arena_; std::atomic parent_call_{nullptr}; ChildCall* child_ = nullptr; Timestamp send_deadline_; const bool is_client_; // flag indicating that cancellation is inherited bool cancellation_is_inherited_ = false; - // Compression algorithm for *incoming* data - grpc_compression_algorithm incoming_compression_algorithm_ = - GRPC_COMPRESS_NONE; + // Is this call traced? + bool traced_ = false; // Supported encodings (compression algorithms), a bitset. // Always support no compression. CompressionAlgorithmSet encodings_accepted_by_peer_{GRPC_COMPRESS_NONE}; - uint32_t test_only_last_message_flags_ = 0; // Peer name is protected by a mutex because it can be accessed by the // application at the same moment as it is being set by the completion // of the recv_initial_metadata op. The mutex should be mostly uncontended. @@ -247,66 +243,6 @@ struct ArenaContextType { static void Destroy(Call*) {} }; -class BasicPromiseBasedCall; -class ServerPromiseBasedCall; - -// TODO(ctiller): move more call things into this type -class CallContext { - public: - explicit CallContext(BasicPromiseBasedCall* call) : call_(call) {} - - // Run some action in the call activity context. This is needed to adapt some - // legacy systems to promises, and will likely disappear once that conversion - // is complete. - void RunInContext(absl::AnyInvocable fn); - - // TODO(ctiller): remove this once transport APIs are promise based - void IncrementRefCount(const char* reason = "call_context"); - - // TODO(ctiller): remove this once transport APIs are promise based - void Unref(const char* reason = "call_context"); - - RefCountedPtr Ref() { - IncrementRefCount(); - return RefCountedPtr(this); - } - - grpc_call_stats* call_stats() { return &call_stats_; } - gpr_atm* peer_string_atm_ptr(); - gpr_cycle_counter call_start_time() { return start_time_; } - - void set_traced(bool traced) { traced_ = traced; } - bool traced() const { return traced_; } - - // TEMPORARY HACK - // Create a call spine object for this call. - // Said object should only be created once. - // Allows interop between the v2 call stack and the v3 (which is required by - // transports). - RefCountedPtr MakeCallSpine(CallArgs call_args); - grpc_call* c_call(); - - private: - friend class PromiseBasedCall; - // Call final info. - grpc_call_stats call_stats_; - // TODO(ctiller): remove this once transport APIs are promise based and we - // don't need refcounting here. - BasicPromiseBasedCall* const call_; - gpr_cycle_counter start_time_ = gpr_get_cycle_counter(); - // Is this call traced? - bool traced_ = false; -}; - -template <> -struct ContextType {}; - -// TODO(ctiller): remove once call-v3 finalized -grpc_call* MakeServerCall(CallHandler call_handler, - ClientMetadataHandle client_initial_metadata, - ServerInterface* server, grpc_completion_queue* cq, - grpc_metadata_array* publish_initial_metadata); - } // namespace grpc_core // Create a new call based on \a args. @@ -349,11 +285,6 @@ void* grpc_call_tracer_get(grpc_call* call); uint8_t grpc_call_is_client(grpc_call* call); -// Get the estimated memory size for a call BESIDES the call stack. Combined -// with the size of the call stack, it helps estimate the arena size for the -// initial call. -size_t grpc_call_get_initial_size_estimate(); - // Return an appropriate compression algorithm for the requested compression \a // level in the context of \a call. grpc_compression_algorithm grpc_call_compression_for_level( diff --git a/src/core/lib/surface/call_utils.cc b/src/core/lib/surface/call_utils.cc new file mode 100644 index 00000000000..e749e70d13a --- /dev/null +++ b/src/core/lib/surface/call_utils.cc @@ -0,0 +1,286 @@ +// 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/lib/surface/call_utils.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "absl/log/check.h" +#include "absl/status/status.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "src/core/lib/channel/status_util.h" +#include "src/core/lib/gprpp/crash.h" +#include "src/core/lib/gprpp/debug_location.h" +#include "src/core/lib/gprpp/match.h" +#include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/promise/activity.h" +#include "src/core/lib/promise/context.h" +#include "src/core/lib/promise/poll.h" +#include "src/core/lib/promise/status_flag.h" +#include "src/core/lib/slice/slice_buffer.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/surface/completion_queue.h" +#include "src/core/lib/surface/validate_metadata.h" +#include "src/core/lib/transport/metadata.h" +#include "src/core/lib/transport/metadata_batch.h" + +namespace grpc_core { + +void PublishMetadataArray(grpc_metadata_batch* md, grpc_metadata_array* array, + bool is_client) { + const auto md_count = md->count(); + if (md_count > array->capacity) { + array->capacity = + std::max(array->capacity + md->count(), array->capacity * 3 / 2); + array->metadata = static_cast( + gpr_realloc(array->metadata, sizeof(grpc_metadata) * array->capacity)); + } + PublishToAppEncoder encoder(array, md, is_client); + md->Encode(&encoder); +} + +void CToMetadata(grpc_metadata* metadata, size_t count, + grpc_metadata_batch* b) { + for (size_t i = 0; i < count; i++) { + grpc_metadata* md = &metadata[i]; + auto key = StringViewFromSlice(md->key); + // Filter "content-length metadata" + if (key == "content-length") continue; + b->Append(key, Slice(CSliceRef(md->value)), + [md](absl::string_view error, const Slice& value) { + gpr_log(GPR_DEBUG, "Append error: %s", + absl::StrCat("key=", StringViewFromSlice(md->key), + " error=", error, + " value=", value.as_string_view()) + .c_str()); + }); + } +} + +const char* GrpcOpTypeName(grpc_op_type op) { + switch (op) { + case GRPC_OP_SEND_INITIAL_METADATA: + return "SendInitialMetadata"; + case GRPC_OP_SEND_MESSAGE: + return "SendMessage"; + case GRPC_OP_SEND_STATUS_FROM_SERVER: + return "SendStatusFromServer"; + case GRPC_OP_SEND_CLOSE_FROM_CLIENT: + return "SendCloseFromClient"; + case GRPC_OP_RECV_MESSAGE: + return "RecvMessage"; + case GRPC_OP_RECV_CLOSE_ON_SERVER: + return "RecvCloseOnServer"; + case GRPC_OP_RECV_INITIAL_METADATA: + return "RecvInitialMetadata"; + case GRPC_OP_RECV_STATUS_ON_CLIENT: + return "RecvStatusOnClient"; + } + Crash("Unreachable"); +} + +//////////////////////////////////////////////////////////////////////// +// WaitForCqEndOp + +Poll WaitForCqEndOp::operator()() { + if (grpc_trace_promise_primitives.enabled()) { + gpr_log(GPR_INFO, "%sWaitForCqEndOp[%p] %s", + Activity::current()->DebugTag().c_str(), this, + StateString(state_).c_str()); + } + if (auto* n = absl::get_if(&state_)) { + if (n->is_closure) { + ExecCtx::Run(DEBUG_LOCATION, static_cast(n->tag), + std::move(n->error)); + return Empty{}; + } else { + auto not_started = std::move(*n); + auto& started = + state_.emplace(GetContext()->MakeOwningWaker()); + grpc_cq_end_op( + not_started.cq, not_started.tag, std::move(not_started.error), + [](void* p, grpc_cq_completion*) { + auto started = static_cast(p); + auto wakeup = std::move(started->waker); + started->done.store(true, std::memory_order_release); + wakeup.Wakeup(); + }, + &started, &started.completion); + } + } + auto& started = absl::get(state_); + if (started.done.load(std::memory_order_acquire)) { + return Empty{}; + } else { + return Pending{}; + } +} + +std::string WaitForCqEndOp::StateString(const State& state) { + return Match( + state, + [](const NotStarted& x) { + return absl::StrFormat( + "NotStarted{is_closure=%s, tag=%p, error=%s, cq=%p}", + x.is_closure ? "true" : "false", x.tag, x.error.ToString(), x.cq); + }, + [](const Started& x) { + return absl::StrFormat( + "Started{completion=%p, done=%s}", &x.completion, + x.done.load(std::memory_order_relaxed) ? "true" : "false"); + }, + [](const Invalid&) -> std::string { return "Invalid{}"; }); +} + +//////////////////////////////////////////////////////////////////////// +// MessageReceiver + +StatusFlag MessageReceiver::FinishRecvMessage( + ValueOrFailure> result) { + if (!result.ok()) { + if (grpc_call_trace.enabled()) { + gpr_log(GPR_INFO, + "%s[call] RecvMessage: outstanding_recv " + "finishes: received end-of-stream with error", + Activity::current()->DebugTag().c_str()); + } + *recv_message_ = nullptr; + recv_message_ = nullptr; + return Failure{}; + } + if (!result->has_value()) { + if (grpc_call_trace.enabled()) { + gpr_log(GPR_INFO, + "%s[call] RecvMessage: outstanding_recv " + "finishes: received end-of-stream", + Activity::current()->DebugTag().c_str()); + } + *recv_message_ = nullptr; + recv_message_ = nullptr; + return Success{}; + } + MessageHandle& message = **result; + test_only_last_message_flags_ = message->flags(); + if ((message->flags() & GRPC_WRITE_INTERNAL_COMPRESS) && + (incoming_compression_algorithm_ != GRPC_COMPRESS_NONE)) { + *recv_message_ = grpc_raw_compressed_byte_buffer_create( + nullptr, 0, incoming_compression_algorithm_); + } else { + *recv_message_ = grpc_raw_byte_buffer_create(nullptr, 0); + } + grpc_slice_buffer_move_into(message->payload()->c_slice_buffer(), + &(*recv_message_)->data.raw.slice_buffer); + if (grpc_call_trace.enabled()) { + gpr_log(GPR_INFO, + "%s[call] RecvMessage: outstanding_recv " + "finishes: received %" PRIdPTR " byte message", + Activity::current()->DebugTag().c_str(), + (*recv_message_)->data.raw.slice_buffer.length); + } + recv_message_ = nullptr; + return Success{}; +} + +//////////////////////////////////////////////////////////////////////// +// MakeErrorString + +std::string MakeErrorString(const ServerMetadata* trailing_metadata) { + std::string out = absl::StrCat( + trailing_metadata->get(GrpcStatusFromWire()).value_or(false) + ? "Error received from peer" + : "Error generated by client", + "grpc_status: ", + grpc_status_code_to_string(trailing_metadata->get(GrpcStatusMetadata()) + .value_or(GRPC_STATUS_UNKNOWN))); + if (const Slice* message = + trailing_metadata->get_pointer(GrpcMessageMetadata())) { + absl::StrAppend(&out, "\ngrpc_message: ", message->as_string_view()); + } + if (auto annotations = trailing_metadata->get_pointer(GrpcStatusContext())) { + absl::StrAppend(&out, "\nStatus Context:"); + for (const std::string& annotation : *annotations) { + absl::StrAppend(&out, "\n ", annotation); + } + } + return out; +} + +bool ValidateMetadata(size_t count, grpc_metadata* metadata) { + if (count > INT_MAX) { + return false; + } + for (size_t i = 0; i < count; i++) { + grpc_metadata* md = &metadata[i]; + if (!GRPC_LOG_IF_ERROR("validate_metadata", + grpc_validate_header_key_is_legal(md->key))) { + return false; + } else if (!grpc_is_binary_header_internal(md->key) && + !GRPC_LOG_IF_ERROR( + "validate_metadata", + grpc_validate_header_nonbin_value_is_legal(md->value))) { + return false; + } else if (GRPC_SLICE_LENGTH(md->value) >= UINT32_MAX) { + // HTTP2 hpack encoding has a maximum limit. + return false; + } + } + return true; +} + +void EndOpImmediately(grpc_completion_queue* cq, void* notify_tag, + bool is_notify_tag_closure) { + if (!is_notify_tag_closure) { + CHECK(grpc_cq_begin_op(cq, notify_tag)); + grpc_cq_end_op( + cq, notify_tag, absl::OkStatus(), + [](void*, grpc_cq_completion* completion) { gpr_free(completion); }, + nullptr, + static_cast( + gpr_malloc(sizeof(grpc_cq_completion)))); + } else { + Closure::Run(DEBUG_LOCATION, static_cast(notify_tag), + absl::OkStatus()); + } +} + +} // namespace grpc_core \ No newline at end of file diff --git a/src/core/lib/surface/call_utils.h b/src/core/lib/surface/call_utils.h new file mode 100644 index 00000000000..ca71f2af168 --- /dev/null +++ b/src/core/lib/surface/call_utils.h @@ -0,0 +1,457 @@ +// 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_LIB_SURFACE_CALL_UTILS_H +#define GRPC_SRC_CORE_LIB_SURFACE_CALL_UTILS_H + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "absl/log/check.h" +#include "absl/status/status.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "src/core/lib/gprpp/crash.h" +#include "src/core/lib/promise/activity.h" +#include "src/core/lib/promise/cancel_callback.h" +#include "src/core/lib/promise/map.h" +#include "src/core/lib/promise/poll.h" +#include "src/core/lib/promise/seq.h" +#include "src/core/lib/promise/status_flag.h" +#include "src/core/lib/surface/call_trace.h" +#include "src/core/lib/surface/completion_queue.h" +#include "src/core/lib/transport/message.h" +#include "src/core/lib/transport/metadata.h" +#include "src/core/lib/transport/metadata_batch.h" + +namespace grpc_core { + +class PublishToAppEncoder { + public: + explicit PublishToAppEncoder(grpc_metadata_array* dest, + const grpc_metadata_batch* encoding, + bool is_client) + : dest_(dest), encoding_(encoding), is_client_(is_client) {} + + void Encode(const Slice& key, const Slice& value) { + Append(key.c_slice(), value.c_slice()); + } + + // Catch anything that is not explicitly handled, and do not publish it to the + // application. If new metadata is added to a batch that needs to be + // published, it should be called out here. + template + void Encode(Which, const typename Which::ValueType&) {} + + void Encode(UserAgentMetadata, const Slice& slice) { + Append(UserAgentMetadata::key(), slice); + } + + void Encode(HostMetadata, const Slice& slice) { + Append(HostMetadata::key(), slice); + } + + void Encode(GrpcPreviousRpcAttemptsMetadata, uint32_t count) { + Append(GrpcPreviousRpcAttemptsMetadata::key(), count); + } + + void Encode(GrpcRetryPushbackMsMetadata, Duration count) { + Append(GrpcRetryPushbackMsMetadata::key(), count.millis()); + } + + void Encode(LbTokenMetadata, const Slice& slice) { + Append(LbTokenMetadata::key(), slice); + } + + private: + void Append(absl::string_view key, int64_t value) { + Append(StaticSlice::FromStaticString(key).c_slice(), + Slice::FromInt64(value).c_slice()); + } + + void Append(absl::string_view key, const Slice& value) { + Append(StaticSlice::FromStaticString(key).c_slice(), value.c_slice()); + } + + void Append(grpc_slice key, grpc_slice value) { + if (dest_->count == dest_->capacity) { + Crash(absl::StrCat( + "Too many metadata entries: capacity=", dest_->capacity, " on ", + is_client_ ? "client" : "server", " encoding ", encoding_->count(), + " elements: ", encoding_->DebugString().c_str())); + } + auto* mdusr = &dest_->metadata[dest_->count++]; + mdusr->key = key; + mdusr->value = value; + } + + grpc_metadata_array* const dest_; + const grpc_metadata_batch* const encoding_; + const bool is_client_; +}; + +void PublishMetadataArray(grpc_metadata_batch* md, grpc_metadata_array* array, + bool is_client); +void CToMetadata(grpc_metadata* metadata, size_t count, grpc_metadata_batch* b); +const char* GrpcOpTypeName(grpc_op_type op); + +bool ValidateMetadata(size_t count, grpc_metadata* metadata); +void EndOpImmediately(grpc_completion_queue* cq, void* notify_tag, + bool is_notify_tag_closure); + +inline bool AreWriteFlagsValid(uint32_t flags) { + // check that only bits in GRPC_WRITE_(INTERNAL?)_USED_MASK are set + const uint32_t allowed_write_positions = + (GRPC_WRITE_USED_MASK | GRPC_WRITE_INTERNAL_USED_MASK); + const uint32_t invalid_positions = ~allowed_write_positions; + return !(flags & invalid_positions); +} + +inline bool AreInitialMetadataFlagsValid(uint32_t flags) { + // check that only bits in GRPC_WRITE_(INTERNAL?)_USED_MASK are set + uint32_t invalid_positions = ~GRPC_INITIAL_METADATA_USED_MASK; + return !(flags & invalid_positions); +} + +// One batch operation +// Wrapper around promise steps to perform once of the batch operations for the +// legacy grpc surface api. +template +class OpHandlerImpl { + public: + using PromiseFactory = promise_detail::OncePromiseFactory; + using Promise = typename PromiseFactory::Promise; + static_assert(!std::is_same::value, + "PromiseFactory must return a promise"); + + OpHandlerImpl() : state_(State::kDismissed) {} + explicit OpHandlerImpl(SetupResult result) : state_(State::kPromiseFactory) { + Construct(&promise_factory_, std::move(result)); + } + + ~OpHandlerImpl() { + switch (state_) { + case State::kDismissed: + break; + case State::kPromiseFactory: + Destruct(&promise_factory_); + break; + case State::kPromise: + Destruct(&promise_); + break; + } + } + + OpHandlerImpl(const OpHandlerImpl&) = delete; + OpHandlerImpl& operator=(const OpHandlerImpl&) = delete; + OpHandlerImpl(OpHandlerImpl&& other) noexcept : state_(other.state_) { + switch (state_) { + case State::kDismissed: + break; + case State::kPromiseFactory: + Construct(&promise_factory_, std::move(other.promise_factory_)); + break; + case State::kPromise: + Construct(&promise_, std::move(other.promise_)); + break; + } + } + OpHandlerImpl& operator=(OpHandlerImpl&& other) noexcept = delete; + + Poll operator()() { + switch (state_) { + case State::kDismissed: + return Success{}; + case State::kPromiseFactory: { + auto promise = promise_factory_.Make(); + Destruct(&promise_factory_); + Construct(&promise_, std::move(promise)); + state_ = State::kPromise; + } + ABSL_FALLTHROUGH_INTENDED; + case State::kPromise: { + if (grpc_call_trace.enabled()) { + gpr_log(GPR_INFO, "%sBeginPoll %s", + Activity::current()->DebugTag().c_str(), OpName()); + } + auto r = poll_cast(promise_()); + if (grpc_call_trace.enabled()) { + gpr_log( + GPR_INFO, "%sEndPoll %s --> %s", + Activity::current()->DebugTag().c_str(), OpName(), + r.pending() ? "PENDING" : (r.value().ok() ? "OK" : "FAILURE")); + } + return r; + } + } + GPR_UNREACHABLE_CODE(return Pending{}); + } + + private: + enum class State { + kDismissed, + kPromiseFactory, + kPromise, + }; + + static const char* OpName() { return GrpcOpTypeName(kOp); } + + // gcc-12 has problems with this being a variant + GPR_NO_UNIQUE_ADDRESS State state_; + union { + PromiseFactory promise_factory_; + Promise promise_; + }; +}; + +template +auto OpHandler(PromiseFactory setup) { + return OpHandlerImpl(std::move(setup)); +} + +class BatchOpIndex { + public: + BatchOpIndex(const grpc_op* ops, size_t nops) : ops_(ops) { + for (size_t i = 0; i < nops; i++) { + idxs_[ops[i].op] = static_cast(i); + } + } + + // 1. Check if op_type is in the batch + // 2. If it is, run the setup function in the context of the API call (NOT in + // the call party). + // 3. This setup function returns a promise factory which we'll then run *in* + // the party to do initial setup, and have it return the promise that we'll + // ultimately poll on til completion. + // Once we express our surface API in terms of core internal types this whole + // dance will go away. + template + auto OpHandler(SetupFn setup) { + using SetupResult = decltype(std::declval()(grpc_op())); + using Impl = OpHandlerImpl; + if (const grpc_op* op = this->op(op_type)) { + auto r = setup(*op); + return Impl(std::move(r)); + } else { + return Impl(); + } + } + + const grpc_op* op(grpc_op_type op_type) const { + return idxs_[op_type] == 255 ? nullptr : &ops_[idxs_[op_type]]; + } + + private: + const grpc_op* const ops_; + std::array idxs_{255, 255, 255, 255, 255, 255, 255, 255}; +}; + +// Defines a promise that calls grpc_cq_end_op() (on first poll) and then waits +// for the callback supplied to grpc_cq_end_op() to be called, before resolving +// to Empty{} +class WaitForCqEndOp { + public: + WaitForCqEndOp(bool is_closure, void* tag, grpc_error_handle error, + grpc_completion_queue* cq) + : state_{NotStarted{is_closure, tag, std::move(error), cq}} {} + + Poll operator()(); + + WaitForCqEndOp(const WaitForCqEndOp&) = delete; + WaitForCqEndOp& operator=(const WaitForCqEndOp&) = delete; + WaitForCqEndOp(WaitForCqEndOp&& other) noexcept + : state_(std::move(absl::get(other.state_))) { + other.state_.emplace(); + } + WaitForCqEndOp& operator=(WaitForCqEndOp&& other) noexcept { + state_ = std::move(absl::get(other.state_)); + other.state_.emplace(); + return *this; + } + + private: + struct NotStarted { + bool is_closure; + void* tag; + grpc_error_handle error; + grpc_completion_queue* cq; + }; + struct Started { + explicit Started(Waker waker) : waker(std::move(waker)) {} + Waker waker; + grpc_cq_completion completion; + std::atomic done{false}; + }; + struct Invalid {}; + using State = absl::variant; + + static std::string StateString(const State& state); + + State state_{Invalid{}}; +}; + +template +auto InfallibleBatch(FalliblePart fallible_part, FinalPart final_part, + bool is_notify_tag_closure, void* notify_tag, + grpc_completion_queue* cq) { + // Perform fallible_part, then final_part, then wait for the + // completion queue to be done. + // If cancelled, we'll ensure the completion queue is notified. + // There's a slight bug here in that if we cancel this promise after + // the WaitForCqEndOp we'll double post -- but we don't currently do that. + return OnCancelFactory( + [fallible_part = std::move(fallible_part), + final_part = std::move(final_part), is_notify_tag_closure, notify_tag, + cq]() mutable { + return LogPollBatch(notify_tag, + Seq(std::move(fallible_part), std::move(final_part), + [is_notify_tag_closure, notify_tag, cq]() { + return WaitForCqEndOp(is_notify_tag_closure, + notify_tag, + absl::OkStatus(), cq); + })); + }, + [cq, notify_tag]() { + grpc_cq_end_op( + cq, notify_tag, absl::OkStatus(), + [](void*, grpc_cq_completion* completion) { delete completion; }, + nullptr, new grpc_cq_completion); + }); +} + +template +auto FallibleBatch(FalliblePart fallible_part, bool is_notify_tag_closure, + void* notify_tag, grpc_completion_queue* cq) { + // Perform fallible_part, then wait for the completion queue to be done. + // If cancelled, we'll ensure the completion queue is notified. + // There's a slight bug here in that if we cancel this promise after + // the WaitForCqEndOp we'll double post -- but we don't currently do that. + return OnCancelFactory( + [fallible_part = std::move(fallible_part), is_notify_tag_closure, + notify_tag, cq]() mutable { + return LogPollBatch( + notify_tag, + Seq(std::move(fallible_part), + [is_notify_tag_closure, notify_tag, cq](StatusFlag r) { + return WaitForCqEndOp(is_notify_tag_closure, notify_tag, + StatusCast(r), cq); + })); + }, + [cq]() { + grpc_cq_end_op( + cq, nullptr, absl::CancelledError(), + [](void*, grpc_cq_completion* completion) { delete completion; }, + nullptr, new grpc_cq_completion); + }); +} + +template +class PollBatchLogger { + public: + PollBatchLogger(void* tag, F f) : tag_(tag), f_(std::move(f)) {} + + auto operator()() { + if (grpc_call_trace.enabled()) { + gpr_log(GPR_INFO, "Poll batch %p", tag_); + } + auto r = f_(); + if (grpc_call_trace.enabled()) { + gpr_log(GPR_INFO, "Poll batch %p --> %s", tag_, ResultString(r).c_str()); + } + return r; + } + + private: + template + static std::string ResultString(Poll r) { + if (r.pending()) return "PENDING"; + return ResultString(r.value()); + } + static std::string ResultString(Empty) { return "DONE"; } + + void* tag_; + F f_; +}; + +template +PollBatchLogger LogPollBatch(void* tag, F f) { + return PollBatchLogger(tag, std::move(f)); +} + +class MessageReceiver { + public: + grpc_compression_algorithm incoming_compression_algorithm() const { + return incoming_compression_algorithm_; + } + + void SetIncomingCompressionAlgorithm( + grpc_compression_algorithm incoming_compression_algorithm) { + incoming_compression_algorithm_ = incoming_compression_algorithm; + } + + uint32_t last_message_flags() const { return test_only_last_message_flags_; } + + template + auto MakeBatchOp(const grpc_op& op, Puller* puller) { + CHECK_EQ(recv_message_, nullptr); + recv_message_ = op.data.recv_message.recv_message; + return [this, puller]() mutable { + return Map(puller->PullMessage(), + [this](ValueOrFailure> msg) { + return FinishRecvMessage(std::move(msg)); + }); + }; + } + + private: + StatusFlag FinishRecvMessage( + ValueOrFailure> result); + + grpc_byte_buffer** recv_message_ = nullptr; + uint32_t test_only_last_message_flags_ = 0; + // Compression algorithm for incoming data + grpc_compression_algorithm incoming_compression_algorithm_ = + GRPC_COMPRESS_NONE; +}; + +std::string MakeErrorString(const ServerMetadata* trailing_metadata); + +} // namespace grpc_core + +#endif // GRPC_SRC_CORE_LIB_SURFACE_CALL_UTILS_H diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h index 9d207ae5f2c..7976fd00858 100644 --- a/src/core/lib/surface/channel.h +++ b/src/core/lib/surface/channel.h @@ -44,6 +44,7 @@ #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/call_destination.h" #include "src/core/lib/transport/connectivity_state.h" // Forward declaration to avoid dependency loop. @@ -54,7 +55,7 @@ namespace grpc_core { // Forward declaration to avoid dependency loop. class Transport; -class Channel : public InternallyRefCounted, +class Channel : public UnstartedCallDestination, public CppImplOf { public: struct RegisteredCall { @@ -68,18 +69,6 @@ class Channel : public InternallyRefCounted, ~RegisteredCall(); }; - // 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; // TODO(roth): This should return a C++ type. @@ -164,7 +153,7 @@ class Channel : public InternallyRefCounted, /// The same as grpc_channel_destroy, but doesn't create an ExecCtx, and so /// is safe to use from within core. inline void grpc_channel_destroy_internal(grpc_channel* channel) { - grpc_core::Channel::FromC(channel)->Orphan(); + grpc_core::Channel::FromC(channel)->Unref(); } // Return the channel's compression options. diff --git a/src/core/lib/surface/channel_create.cc b/src/core/lib/surface/channel_create.cc index 6a22eeec630..5a10e783523 100644 --- a/src/core/lib/surface/channel_create.cc +++ b/src/core/lib/surface/channel_create.cc @@ -14,6 +14,8 @@ // limitations under the License. // +#include "src/core/lib/surface/channel_create.h" + #include "absl/log/check.h" #include @@ -34,7 +36,7 @@ namespace grpc_core { -absl::StatusOr> ChannelCreate( +absl::StatusOr> ChannelCreate( std::string target, ChannelArgs args, grpc_channel_stack_type channel_stack_type, Transport* optional_transport) { global_stats().IncrementClientChannelsCreated(); @@ -80,7 +82,7 @@ absl::StatusOr> ChannelCreate( args = args.SetObject(optional_transport); } // Delegate to appropriate channel impl. - if (!IsCallV3Enabled()) { + if (!args.GetBool(GRPC_ARG_USE_V3_STACK).value_or(false)) { return LegacyChannel::Create(std::move(target), std::move(args), channel_stack_type); } diff --git a/src/core/lib/surface/channel_create.h b/src/core/lib/surface/channel_create.h index dcdb1dc9e96..0295eb92bc3 100644 --- a/src/core/lib/surface/channel_create.h +++ b/src/core/lib/surface/channel_create.h @@ -24,16 +24,17 @@ #include #include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/gprpp/orphanable.h" #include "src/core/lib/surface/channel.h" #include "src/core/lib/surface/channel_stack_type.h" +#define GRPC_ARG_USE_V3_STACK "grpc.internal.use_v3_stack" + namespace grpc_core { class Transport; // Creates a client channel. -absl::StatusOr> ChannelCreate( +absl::StatusOr> ChannelCreate( std::string target, ChannelArgs args, grpc_channel_stack_type channel_stack_type, Transport* optional_transport); diff --git a/src/core/lib/surface/channel_init.cc b/src/core/lib/surface/channel_init.cc index da694aa59be..47863090030 100644 --- a/src/core/lib/surface/channel_init.cc +++ b/src/core/lib/surface/channel_init.cc @@ -251,8 +251,8 @@ ChannelInit::StackConfig ChannelInit::BuildStackConfig( MutexLock lock(m); // List the channel stack type (since we'll be repeatedly printing graphs in // this loop). - gpr_log(GPR_INFO, - "ORDERED CHANNEL STACK %s:", grpc_channel_stack_type_string(type)); + LOG(INFO) << "ORDERED CHANNEL STACK " + << grpc_channel_stack_type_string(type) << ":"; // First build up a map of filter -> file:line: strings, because it helps // the readability of this log to get later fields aligned vertically. std::map loc_strs; diff --git a/src/core/lib/surface/client_call.cc b/src/core/lib/surface/client_call.cc new file mode 100644 index 00000000000..af7f34c9c60 --- /dev/null +++ b/src/core/lib/surface/client_call.cc @@ -0,0 +1,423 @@ +// 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/lib/surface/client_call.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "absl/log/check.h" +#include "absl/status/status.h" +#include "absl/strings/string_view.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "src/core/lib/gprpp/bitset.h" +#include "src/core/lib/gprpp/crash.h" +#include "src/core/lib/gprpp/ref_counted.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" +#include "src/core/lib/promise/all_ok.h" +#include "src/core/lib/promise/status_flag.h" +#include "src/core/lib/promise/try_seq.h" +#include "src/core/lib/resource_quota/arena.h" +#include "src/core/lib/slice/slice_buffer.h" +#include "src/core/lib/surface/call_trace.h" +#include "src/core/lib/surface/completion_queue.h" +#include "src/core/lib/transport/metadata.h" +#include "src/core/telemetry/stats.h" +#include "src/core/telemetry/stats_data.h" + +namespace grpc_core { + +namespace { + +grpc_call_error ValidateClientBatch(const grpc_op* ops, size_t nops) { + BitSet<8> got_ops; + for (size_t op_idx = 0; op_idx < nops; op_idx++) { + const grpc_op& op = ops[op_idx]; + switch (op.op) { + case GRPC_OP_SEND_INITIAL_METADATA: + if (!AreInitialMetadataFlagsValid(op.flags)) { + return GRPC_CALL_ERROR_INVALID_FLAGS; + } + if (!ValidateMetadata(op.data.send_initial_metadata.count, + op.data.send_initial_metadata.metadata)) { + return GRPC_CALL_ERROR_INVALID_METADATA; + } + break; + case GRPC_OP_SEND_MESSAGE: + if (!AreWriteFlagsValid(op.flags)) { + return GRPC_CALL_ERROR_INVALID_FLAGS; + } + break; + case GRPC_OP_SEND_CLOSE_FROM_CLIENT: + case GRPC_OP_RECV_INITIAL_METADATA: + case GRPC_OP_RECV_MESSAGE: + case GRPC_OP_RECV_STATUS_ON_CLIENT: + if (op.flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; + break; + case GRPC_OP_RECV_CLOSE_ON_SERVER: + case GRPC_OP_SEND_STATUS_FROM_SERVER: + return GRPC_CALL_ERROR_NOT_ON_CLIENT; + } + if (got_ops.is_set(op.op)) return GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; + got_ops.set(op.op); + } + return GRPC_CALL_OK; +} + +} // namespace + +ClientCall::ClientCall( + grpc_call*, uint32_t, grpc_completion_queue* cq, Slice path, + absl::optional authority, bool registered_method, Timestamp deadline, + grpc_compression_options compression_options, + grpc_event_engine::experimental::EventEngine* event_engine, + RefCountedPtr arena, + RefCountedPtr destination) + : Call(false, deadline, std::move(arena), event_engine), + cq_(cq), + call_destination_(std::move(destination)), + compression_options_(compression_options) { + global_stats().IncrementClientCallsCreated(); + send_initial_metadata_->Set(HttpPathMetadata(), std::move(path)); + if (authority.has_value()) { + send_initial_metadata_->Set(HttpAuthorityMetadata(), std::move(*authority)); + } + send_initial_metadata_->Set( + GrpcRegisteredMethod(), + reinterpret_cast(static_cast(registered_method))); + if (deadline != Timestamp::InfFuture()) { + send_initial_metadata_->Set(GrpcTimeoutMetadata(), deadline); + UpdateDeadline(deadline); + } +} + +grpc_call_error ClientCall::StartBatch(const grpc_op* ops, size_t nops, + void* notify_tag, + bool is_notify_tag_closure) { + if (nops == 0) { + EndOpImmediately(cq_, notify_tag, is_notify_tag_closure); + return GRPC_CALL_OK; + } + const grpc_call_error validation_result = ValidateClientBatch(ops, nops); + if (validation_result != GRPC_CALL_OK) { + return validation_result; + } + CommitBatch(ops, nops, notify_tag, is_notify_tag_closure); + return GRPC_CALL_OK; +} + +void ClientCall::CancelWithError(grpc_error_handle error) { + cancel_status_.Set(new absl::Status(error)); + auto cur_state = call_state_.load(std::memory_order_acquire); + while (true) { + if (grpc_call_trace.enabled()) { + LOG(INFO) << DebugTag() << "CancelWithError " + << GRPC_DUMP_ARGS(cur_state, error); + } + switch (cur_state) { + case kCancelled: + return; + case kUnstarted: + if (call_state_.compare_exchange_strong(cur_state, kCancelled, + std::memory_order_acq_rel, + std::memory_order_acquire)) { + return; + } + break; + case kStarted: + started_call_initiator_.SpawnInfallible( + "CancelWithError", [self = WeakRefAsSubclass(), + error = std::move(error)]() mutable { + self->started_call_initiator_.Cancel(std::move(error)); + return Empty{}; + }); + return; + default: + if (call_state_.compare_exchange_strong(cur_state, kCancelled, + std::memory_order_acq_rel, + std::memory_order_acquire)) { + auto* unordered_start = reinterpret_cast(cur_state); + while (unordered_start != nullptr) { + auto next = unordered_start->next; + delete unordered_start; + unordered_start = next; + } + return; + } + } + } +} + +template +void ClientCall::ScheduleCommittedBatch(Batch batch) { + auto cur_state = call_state_.load(std::memory_order_acquire); + while (true) { + switch (cur_state) { + case kUnstarted: + default: { // UnorderedStart + auto pending = std::make_unique(); + pending->start_pending_batch = [this, + batch = std::move(batch)]() mutable { + started_call_initiator_.SpawnInfallible("batch", std::move(batch)); + }; + while (true) { + pending->next = reinterpret_cast(cur_state); + if (call_state_.compare_exchange_strong( + cur_state, reinterpret_cast(pending.get()), + std::memory_order_acq_rel, std::memory_order_acquire)) { + std::ignore = pending.release(); + return; + } + if (cur_state == kStarted) { + pending->start_pending_batch(); + return; + } + if (cur_state == kCancelled) { + return; + } + } + } + case kStarted: + started_call_initiator_.SpawnInfallible("batch", std::move(batch)); + return; + case kCancelled: + return; + } + } +} + +void ClientCall::StartCall(const grpc_op& send_initial_metadata_op) { + auto cur_state = call_state_.load(std::memory_order_acquire); + CToMetadata(send_initial_metadata_op.data.send_initial_metadata.metadata, + send_initial_metadata_op.data.send_initial_metadata.count, + send_initial_metadata_.get()); + PrepareOutgoingInitialMetadata(send_initial_metadata_op, + *send_initial_metadata_); + auto call = MakeCallPair(std::move(send_initial_metadata_), event_engine(), + arena()->Ref()); + started_call_initiator_ = std::move(call.initiator); + call_destination_->StartCall(std::move(call.handler)); + while (true) { + switch (cur_state) { + case kUnstarted: + if (call_state_.compare_exchange_strong(cur_state, kStarted, + std::memory_order_acq_rel, + std::memory_order_acquire)) { + return; + } + break; + case kStarted: + Crash("StartCall called twice"); // probably we crash earlier... + case kCancelled: + return; + default: { // UnorderedStart + if (call_state_.compare_exchange_strong(cur_state, kStarted, + std::memory_order_acq_rel, + std::memory_order_acquire)) { + auto unordered_start = reinterpret_cast(cur_state); + while (unordered_start->next != nullptr) { + unordered_start->start_pending_batch(); + auto next = unordered_start->next; + delete unordered_start; + unordered_start = next; + } + return; + } + break; + } + } + } +} + +void ClientCall::CommitBatch(const grpc_op* ops, size_t nops, void* notify_tag, + bool is_notify_tag_closure) { + if (nops == 1 && ops[0].op == GRPC_OP_SEND_INITIAL_METADATA) { + StartCall(ops[0]); + EndOpImmediately(cq_, notify_tag, is_notify_tag_closure); + return; + } + if (!is_notify_tag_closure) grpc_cq_begin_op(cq_, notify_tag); + BatchOpIndex op_index(ops, nops); + auto send_message = + op_index.OpHandler([this](const grpc_op& op) { + SliceBuffer send; + grpc_slice_buffer_swap( + &op.data.send_message.send_message->data.raw.slice_buffer, + send.c_slice_buffer()); + auto msg = arena()->MakePooled(std::move(send), op.flags); + return [this, msg = std::move(msg)]() mutable { + return started_call_initiator_.PushMessage(std::move(msg)); + }; + }); + auto send_close_from_client = + op_index.OpHandler( + [this](const grpc_op&) { + return [this]() { + started_call_initiator_.FinishSends(); + return Success{}; + }; + }); + auto recv_message = + op_index.OpHandler([this](const grpc_op& op) { + return message_receiver_.MakeBatchOp(op, &started_call_initiator_); + }); + auto recv_initial_metadata = + op_index.OpHandler([this]( + const grpc_op& op) { + return [this, + array = op.data.recv_initial_metadata.recv_initial_metadata]() { + return Map( + started_call_initiator_.PullServerInitialMetadata(), + [this, + array](ValueOrFailure> md) { + ServerMetadataHandle metadata; + if (!md.ok() || !md->has_value()) { + is_trailers_only_ = true; + metadata = Arena::MakePooled(); + } else { + metadata = std::move(md->value()); + is_trailers_only_ = + metadata->get(GrpcTrailersOnly()).value_or(false); + } + ProcessIncomingInitialMetadata(*metadata); + PublishMetadataArray(metadata.get(), array, true); + received_initial_metadata_ = std::move(metadata); + return Success{}; + }); + }; + }); + auto primary_ops = AllOk( + TrySeq(std::move(send_message), std::move(send_close_from_client)), + TrySeq(std::move(recv_initial_metadata), std::move(recv_message))); + if (const grpc_op* op = op_index.op(GRPC_OP_SEND_INITIAL_METADATA)) { + StartCall(*op); + } + if (const grpc_op* op = op_index.op(GRPC_OP_RECV_STATUS_ON_CLIENT)) { + auto out_status = op->data.recv_status_on_client.status; + auto out_status_details = op->data.recv_status_on_client.status_details; + auto out_error_string = op->data.recv_status_on_client.error_string; + auto out_trailing_metadata = + op->data.recv_status_on_client.trailing_metadata; + auto make_read_trailing_metadata = [this, out_status, out_status_details, + out_error_string, + out_trailing_metadata]() { + return Map( + started_call_initiator_.PullServerTrailingMetadata(), + [this, out_status, out_status_details, out_error_string, + out_trailing_metadata]( + ServerMetadataHandle server_trailing_metadata) { + if (grpc_call_trace.enabled()) { + LOG(INFO) << DebugTag() << "RecvStatusOnClient " + << server_trailing_metadata->DebugString(); + } + const auto status = + server_trailing_metadata->get(GrpcStatusMetadata()) + .value_or(GRPC_STATUS_UNKNOWN); + *out_status = status; + Slice message_slice; + if (Slice* message = server_trailing_metadata->get_pointer( + GrpcMessageMetadata())) { + message_slice = message->Ref(); + } + *out_status_details = message_slice.TakeCSlice(); + if (out_error_string != nullptr) { + if (status != GRPC_STATUS_OK) { + *out_error_string = gpr_strdup( + MakeErrorString(server_trailing_metadata.get()).c_str()); + } else { + *out_error_string = nullptr; + } + } + PublishMetadataArray(server_trailing_metadata.get(), + out_trailing_metadata, true); + received_trailing_metadata_ = std::move(server_trailing_metadata); + return Success{}; + }); + }; + ScheduleCommittedBatch(InfallibleBatch( + std::move(primary_ops), + OpHandler(OnCancelFactory( + std::move(make_read_trailing_metadata), + [this, out_status, out_status_details, out_error_string, + out_trailing_metadata]() { + auto* status = cancel_status_.Get(); + CHECK_NE(status, nullptr); + *out_status = static_cast(status->code()); + *out_status_details = + Slice::FromCopiedString(status->message()).TakeCSlice(); + if (out_error_string != nullptr) { + *out_error_string = nullptr; + } + out_trailing_metadata->count = 0; + })), + is_notify_tag_closure, notify_tag, cq_)); + } else { + ScheduleCommittedBatch(FallibleBatch( + std::move(primary_ops), is_notify_tag_closure, notify_tag, cq_)); + } +} + +char* ClientCall::GetPeer() { + Slice peer_slice = GetPeerString(); + if (!peer_slice.empty()) { + absl::string_view peer_string_view = peer_slice.as_string_view(); + char* peer_string = + static_cast(gpr_malloc(peer_string_view.size() + 1)); + memcpy(peer_string, peer_string_view.data(), peer_string_view.size()); + peer_string[peer_string_view.size()] = '\0'; + return peer_string; + } + return gpr_strdup("unknown"); +} + +grpc_call* MakeClientCall( + grpc_call* parent_call, uint32_t propagation_mask, + grpc_completion_queue* cq, Slice path, absl::optional authority, + bool registered_method, Timestamp deadline, + grpc_compression_options compression_options, + grpc_event_engine::experimental::EventEngine* event_engine, + RefCountedPtr arena, + RefCountedPtr destination) { + return arena + ->New(parent_call, propagation_mask, cq, std::move(path), + std::move(authority), registered_method, deadline, + compression_options, event_engine, arena, destination) + ->c_ptr(); +} + +} // namespace grpc_core diff --git a/src/core/lib/surface/client_call.h b/src/core/lib/surface/client_call.h new file mode 100644 index 00000000000..dd9964f391c --- /dev/null +++ b/src/core/lib/surface/client_call.h @@ -0,0 +1,179 @@ +// 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_LIB_SURFACE_CLIENT_CALL_H +#define GRPC_SRC_CORE_LIB_SURFACE_CLIENT_CALL_H + +#include +#include +#include +#include + +#include +#include +#include + +#include "absl/status/status.h" +#include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "src/core/lib/gprpp/crash.h" +#include "src/core/lib/gprpp/ref_counted.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" +#include "src/core/lib/gprpp/single_set_ptr.h" +#include "src/core/lib/promise/status_flag.h" +#include "src/core/lib/resource_quota/arena.h" +#include "src/core/lib/surface/call.h" +#include "src/core/lib/surface/call_utils.h" +#include "src/core/lib/transport/metadata.h" + +namespace grpc_core { + +class ClientCall final + : public Call, + public DualRefCounted { + public: + ClientCall(grpc_call* parent_call, uint32_t propagation_mask, + grpc_completion_queue* cq, Slice path, + absl::optional authority, bool registered_method, + Timestamp deadline, grpc_compression_options compression_options, + grpc_event_engine::experimental::EventEngine* event_engine, + RefCountedPtr arena, + RefCountedPtr destination); + + void CancelWithError(grpc_error_handle error) override; + bool is_trailers_only() const override { return is_trailers_only_; } + absl::string_view GetServerAuthority() const override { + Crash("unimplemented"); + } + grpc_call_error StartBatch(const grpc_op* ops, size_t nops, void* notify_tag, + bool is_notify_tag_closure) override; + + void ExternalRef() override { Ref().release(); } + void ExternalUnref() override { Unref(); } + void InternalRef(const char*) override { WeakRef().release(); } + void InternalUnref(const char*) override { WeakUnref(); } + + void Orphaned() override { + // TODO(ctiller): only when we're not already finished + CancelWithError(absl::CancelledError()); + } + + void SetCompletionQueue(grpc_completion_queue*) override { + Crash("unimplemented"); + } + + grpc_compression_options compression_options() override { + return compression_options_; + } + + grpc_call_stack* call_stack() override { return nullptr; } + + char* GetPeer() override; + + bool Completed() final { Crash("unimplemented"); } + bool failed_before_recv_message() const final { Crash("unimplemented"); } + + grpc_compression_algorithm incoming_compression_algorithm() override { + return message_receiver_.incoming_compression_algorithm(); + } + + void SetIncomingCompressionAlgorithm( + grpc_compression_algorithm algorithm) override { + message_receiver_.SetIncomingCompressionAlgorithm(algorithm); + } + + uint32_t test_only_message_flags() override { + return message_receiver_.last_message_flags(); + } + + void Destroy() { + auto arena = this->arena()->Ref(); + this->~ClientCall(); + } + + private: + struct UnorderedStart { + absl::AnyInvocable start_pending_batch; + UnorderedStart* next; + }; + + void CommitBatch(const grpc_op* ops, size_t nops, void* notify_tag, + bool is_notify_tag_closure); + template + void ScheduleCommittedBatch(Batch batch); + void StartCall(const grpc_op& send_initial_metadata_op); + + std::string DebugTag() { return absl::StrFormat("CLIENT_CALL[%p]: ", this); } + + // call_state_ is one of: + // 1. kUnstarted - call has not yet been started + // 2. pointer to an UnorderedStart - call has ops started, but no send initial + // metadata yet + // 3. kStarted - call has been started and call_initiator_ is ready + // 4. kCancelled - call was cancelled before starting + // In cases (1) and (2) send_initial_metadata_ is used to store the initial + // but unsent metadata. + // In case (3) started_call_initiator_ is used to store the call initiator. + // In case (4) no other state is used. + enum CallState : uintptr_t { + kUnstarted = 0, + kStarted = 1, + kCancelled = 2, + }; + std::atomic call_state_{kUnstarted}; + ClientMetadataHandle send_initial_metadata_{ + Arena::MakePooled()}; + CallInitiator started_call_initiator_; + // Status passed to CancelWithError; + // if call_state_ == kCancelled then this is the authoritative status, + // otherwise the server trailing metadata from started_call_initiator_ is + // authoritative. + SingleSetPtr cancel_status_; + MessageReceiver message_receiver_; + grpc_completion_queue* const cq_; + const RefCountedPtr call_destination_; + const grpc_compression_options compression_options_; + ServerMetadataHandle received_initial_metadata_; + ServerMetadataHandle received_trailing_metadata_; + bool is_trailers_only_; +}; + +grpc_call* MakeClientCall( + grpc_call* parent_call, uint32_t propagation_mask, + grpc_completion_queue* cq, Slice path, absl::optional authority, + bool registered_method, Timestamp deadline, + grpc_compression_options compression_options, + grpc_event_engine::experimental::EventEngine* event_engine, + RefCountedPtr arena, + RefCountedPtr destination); + +} // namespace grpc_core + +#endif // GRPC_SRC_CORE_LIB_SURFACE_CLIENT_CALL_H diff --git a/src/core/lib/surface/filter_stack_call.cc b/src/core/lib/surface/filter_stack_call.cc new file mode 100644 index 00000000000..973c3cb85ff --- /dev/null +++ b/src/core/lib/surface/filter_stack_call.cc @@ -0,0 +1,1164 @@ +// 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/lib/surface/filter_stack_call.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "absl/log/check.h" +#include "absl/log/log.h" +#include "absl/status/status.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "src/core/channelz/channelz.h" +#include "src/core/lib/channel/channel_stack.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/ref_counted.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" +#include "src/core/lib/gprpp/status_helper.h" +#include "src/core/lib/iomgr/call_combiner.h" +#include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/iomgr/polling_entity.h" +#include "src/core/lib/resource_quota/arena.h" +#include "src/core/lib/slice/slice_buffer.h" +#include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/surface/api_trace.h" +#include "src/core/lib/surface/call_utils.h" +#include "src/core/lib/surface/channel.h" +#include "src/core/lib/surface/completion_queue.h" +#include "src/core/lib/surface/validate_metadata.h" +#include "src/core/lib/transport/error_utils.h" +#include "src/core/lib/transport/metadata_batch.h" +#include "src/core/lib/transport/transport.h" +#include "src/core/server/server_interface.h" +#include "src/core/telemetry/call_tracer.h" +#include "src/core/telemetry/stats.h" +#include "src/core/telemetry/stats_data.h" +#include "src/core/util/alloc.h" +#include "src/core/util/time_precise.h" + +namespace grpc_core { + +// Alias to make this type available in Call implementation without a grpc_core +// prefix. +using GrpcClosure = Closure; + +FilterStackCall::FilterStackCall(RefCountedPtr arena, + const grpc_call_create_args& args) + : Call(args.server_transport_data == nullptr, args.send_deadline, + std::move(arena), args.channel->event_engine()), + channel_(args.channel->RefAsSubclass()), + cq_(args.cq), + stream_op_payload_{} {} + +grpc_error_handle FilterStackCall::Create(grpc_call_create_args* args, + grpc_call** out_call) { + Channel* channel = args->channel.get(); + + auto add_init_error = [](grpc_error_handle* composite, + grpc_error_handle new_err) { + if (new_err.ok()) return; + if (composite->ok()) { + *composite = GRPC_ERROR_CREATE("Call creation failed"); + } + *composite = grpc_error_add_child(*composite, new_err); + }; + + FilterStackCall* call; + grpc_error_handle error; + grpc_channel_stack* channel_stack = channel->channel_stack(); + size_t call_alloc_size = + GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(FilterStackCall)) + + channel_stack->call_stack_size; + + 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); + *out_call = call->c_ptr(); + grpc_slice path = grpc_empty_slice(); + ScopedContext ctx(call); + if (call->is_client()) { + call->final_op_.client.status_details = nullptr; + call->final_op_.client.status = nullptr; + call->final_op_.client.error_string = nullptr; + global_stats().IncrementClientCallsCreated(); + path = CSliceRef(args->path->c_slice()); + call->send_initial_metadata_.Set(HttpPathMetadata(), + std::move(*args->path)); + if (args->authority.has_value()) { + call->send_initial_metadata_.Set(HttpAuthorityMetadata(), + std::move(*args->authority)); + } + call->send_initial_metadata_.Set( + GrpcRegisteredMethod(), reinterpret_cast(static_cast( + args->registered_method))); + channel_stack->stats_plugin_group->AddClientCallTracers( + Slice(CSliceRef(path)), args->registered_method, arena.get()); + } else { + global_stats().IncrementServerCallsCreated(); + call->final_op_.server.cancelled = nullptr; + call->final_op_.server.core_server = args->server; + // TODO(yashykt): In the future, we want to also enable stats and trace + // collecting from when the call is created at the transport. The idea is + // that the transport would create the call tracer and pass it in as part of + // the metadata. + // TODO(yijiem): OpenCensus and internal Census is still using this way to + // set server call tracer. We need to refactor them to stats plugins + // (including removing the client channel filters). + if (args->server != nullptr && + args->server->server_call_tracer_factory() != nullptr) { + auto* server_call_tracer = + args->server->server_call_tracer_factory()->CreateNewServerCallTracer( + arena.get(), args->server->channel_args()); + if (server_call_tracer != nullptr) { + // Note that we are setting both + // GRPC_CONTEXT_CALL_TRACER_ANNOTATION_INTERFACE and + // GRPC_CONTEXT_CALL_TRACER as a matter of convenience. In the future + // promise-based world, we would just a single tracer object for each + // stack (call, subchannel_call, server_call.) + arena->SetContext(server_call_tracer); + arena->SetContext(server_call_tracer); + } + } + channel_stack->stats_plugin_group->AddServerCallTracers(arena.get()); + } + + Call* parent = Call::FromC(args->parent); + if (parent != nullptr) { + add_init_error(&error, absl_status_to_grpc_error(call->InitParent( + parent, args->propagation_mask))); + } + // initial refcount dropped by grpc_call_unref + grpc_call_element_args call_args = { + call->call_stack(), args->server_transport_data, path, + call->start_time(), call->send_deadline(), call->arena(), + &call->call_combiner_}; + add_init_error(&error, grpc_call_stack_init(channel_stack, 1, DestroyCall, + call, &call_args)); + // Publish this call to parent only after the call stack has been initialized. + if (parent != nullptr) { + call->PublishToParent(parent); + } + + if (!error.ok()) { + call->CancelWithError(error); + } + if (args->cq != nullptr) { + CHECK(args->pollset_set_alternative == nullptr) + << "Only one of 'cq' and 'pollset_set_alternative' should be " + "non-nullptr."; + GRPC_CQ_INTERNAL_REF(args->cq, "bind"); + call->pollent_ = + grpc_polling_entity_create_from_pollset(grpc_cq_pollset(args->cq)); + } + if (args->pollset_set_alternative != nullptr) { + call->pollent_ = grpc_polling_entity_create_from_pollset_set( + args->pollset_set_alternative); + } + if (!grpc_polling_entity_is_empty(&call->pollent_)) { + grpc_call_stack_set_pollset_or_pollset_set(call->call_stack(), + &call->pollent_); + } + + if (call->is_client()) { + channelz::ChannelNode* channelz_channel = channel->channelz_node(); + if (channelz_channel != nullptr) { + channelz_channel->RecordCallStarted(); + } + } else if (call->final_op_.server.core_server != nullptr) { + channelz::ServerNode* channelz_node = + call->final_op_.server.core_server->channelz_node(); + if (channelz_node != nullptr) { + channelz_node->RecordCallStarted(); + } + } + + if (args->send_deadline != Timestamp::InfFuture()) { + call->UpdateDeadline(args->send_deadline); + } + + CSliceUnref(path); + + return error; +} + +void FilterStackCall::SetCompletionQueue(grpc_completion_queue* cq) { + CHECK(cq); + + if (grpc_polling_entity_pollset_set(&pollent_) != nullptr) { + Crash("A pollset_set is already registered for this call."); + } + cq_ = cq; + GRPC_CQ_INTERNAL_REF(cq, "bind"); + pollent_ = grpc_polling_entity_create_from_pollset(grpc_cq_pollset(cq)); + grpc_call_stack_set_pollset_or_pollset_set(call_stack(), &pollent_); +} + +void FilterStackCall::ReleaseCall(void* call, grpc_error_handle /*error*/) { + static_cast(call)->DeleteThis(); +} + +void FilterStackCall::DestroyCall(void* call, grpc_error_handle /*error*/) { + auto* c = static_cast(call); + c->recv_initial_metadata_.Clear(); + c->recv_trailing_metadata_.Clear(); + c->receiving_slice_buffer_.reset(); + ParentCall* pc = c->parent_call(); + if (pc != nullptr) { + pc->~ParentCall(); + } + if (c->cq_) { + GRPC_CQ_INTERNAL_UNREF(c->cq_, "bind"); + } + + grpc_error_handle status_error = c->status_error_.get(); + grpc_error_get_status(status_error, c->send_deadline(), + &c->final_info_.final_status, nullptr, nullptr, + &(c->final_info_.error_string)); + c->status_error_.set(absl::OkStatus()); + c->final_info_.stats.latency = + gpr_cycle_counter_sub(gpr_get_cycle_counter(), c->start_time()); + grpc_call_stack_destroy(c->call_stack(), &c->final_info_, + GRPC_CLOSURE_INIT(&c->release_call_, ReleaseCall, c, + grpc_schedule_on_exec_ctx)); +} + +void FilterStackCall::ExternalUnref() { + if (GPR_LIKELY(!ext_ref_.Unref())) return; + + ApplicationCallbackExecCtx callback_exec_ctx; + ExecCtx exec_ctx; + + GRPC_API_TRACE("grpc_call_unref(c=%p)", 1, (this)); + + MaybeUnpublishFromParent(); + + CHECK(!destroy_called_); + destroy_called_ = true; + bool cancel = gpr_atm_acq_load(&received_final_op_atm_) == 0; + if (cancel) { + CancelWithError(absl::CancelledError()); + } else { + // Unset the call combiner cancellation closure. This has the + // effect of scheduling the previously set cancellation closure, if + // any, so that it can release any internal references it may be + // holding to the call stack. + call_combiner_.SetNotifyOnCancel(nullptr); + } + InternalUnref("destroy"); +} + +// start_batch_closure points to a caller-allocated closure to be used +// for entering the call combiner. +void FilterStackCall::ExecuteBatch(grpc_transport_stream_op_batch* batch, + grpc_closure* start_batch_closure) { + // This is called via the call combiner to start sending a batch down + // the filter stack. + auto execute_batch_in_call_combiner = [](void* arg, grpc_error_handle) { + grpc_transport_stream_op_batch* batch = + static_cast(arg); + auto* call = + static_cast(batch->handler_private.extra_arg); + grpc_call_element* elem = call->call_elem(0); + GRPC_CALL_LOG_OP(GPR_INFO, elem, batch); + elem->filter->start_transport_stream_op_batch(elem, batch); + }; + batch->handler_private.extra_arg = this; + GRPC_CLOSURE_INIT(start_batch_closure, execute_batch_in_call_combiner, batch, + grpc_schedule_on_exec_ctx); + GRPC_CALL_COMBINER_START(call_combiner(), start_batch_closure, + absl::OkStatus(), "executing batch"); +} + +namespace { +struct CancelState { + FilterStackCall* call; + grpc_closure start_batch; + grpc_closure finish_batch; +}; +} // namespace + +// The on_complete callback used when sending a cancel_stream batch down +// the filter stack. Yields the call combiner when the batch is done. +static void done_termination(void* arg, grpc_error_handle /*error*/) { + CancelState* state = static_cast(arg); + GRPC_CALL_COMBINER_STOP(state->call->call_combiner(), + "on_complete for cancel_stream op"); + state->call->InternalUnref("termination"); + delete state; +} + +void FilterStackCall::CancelWithError(grpc_error_handle error) { + if (!gpr_atm_rel_cas(&cancelled_with_error_, 0, 1)) { + return; + } + if (GRPC_TRACE_FLAG_ENABLED(grpc_call_error_trace)) { + gpr_log(GPR_INFO, "CancelWithError %s %s", is_client() ? "CLI" : "SVR", + StatusToString(error).c_str()); + } + ClearPeerString(); + InternalRef("termination"); + ResetDeadline(); + // Inform the call combiner of the cancellation, so that it can cancel + // any in-flight asynchronous actions that may be holding the call + // combiner. This ensures that the cancel_stream batch can be sent + // down the filter stack in a timely manner. + call_combiner_.Cancel(error); + CancelState* state = new CancelState; + state->call = this; + GRPC_CLOSURE_INIT(&state->finish_batch, done_termination, state, + grpc_schedule_on_exec_ctx); + grpc_transport_stream_op_batch* op = + grpc_make_transport_stream_op(&state->finish_batch); + op->cancel_stream = true; + op->payload->cancel_stream.cancel_error = error; + ExecuteBatch(op, &state->start_batch); +} + +void FilterStackCall::SetFinalStatus(grpc_error_handle error) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_call_error_trace)) { + gpr_log(GPR_INFO, "set_final_status %s %s", is_client() ? "CLI" : "SVR", + StatusToString(error).c_str()); + } + ResetDeadline(); + if (is_client()) { + std::string status_details; + grpc_error_get_status(error, send_deadline(), final_op_.client.status, + &status_details, nullptr, + final_op_.client.error_string); + *final_op_.client.status_details = + grpc_slice_from_cpp_string(std::move(status_details)); + status_error_.set(error); + channelz::ChannelNode* channelz_channel = channel()->channelz_node(); + if (channelz_channel != nullptr) { + if (*final_op_.client.status != GRPC_STATUS_OK) { + channelz_channel->RecordCallFailed(); + } else { + channelz_channel->RecordCallSucceeded(); + } + } + } else { + *final_op_.server.cancelled = + !error.ok() || !sent_server_trailing_metadata_; + channelz::ServerNode* channelz_node = + final_op_.server.core_server->channelz_node(); + if (channelz_node != nullptr) { + if (*final_op_.server.cancelled || !status_error_.ok()) { + channelz_node->RecordCallFailed(); + } else { + channelz_node->RecordCallSucceeded(); + } + } + } +} + +bool FilterStackCall::PrepareApplicationMetadata(size_t count, + grpc_metadata* metadata, + bool is_trailing) { + grpc_metadata_batch* batch = + is_trailing ? &send_trailing_metadata_ : &send_initial_metadata_; + for (size_t i = 0; i < count; i++) { + grpc_metadata* md = &metadata[i]; + if (!GRPC_LOG_IF_ERROR("validate_metadata", + grpc_validate_header_key_is_legal(md->key))) { + return false; + } else if (!grpc_is_binary_header_internal(md->key) && + !GRPC_LOG_IF_ERROR( + "validate_metadata", + grpc_validate_header_nonbin_value_is_legal(md->value))) { + return false; + } else if (GRPC_SLICE_LENGTH(md->value) >= UINT32_MAX) { + // HTTP2 hpack encoding has a maximum limit. + return false; + } else if (grpc_slice_str_cmp(md->key, "content-length") == 0) { + // Filter "content-length metadata" + continue; + } + batch->Append(StringViewFromSlice(md->key), Slice(CSliceRef(md->value)), + [md](absl::string_view error, const Slice& value) { + gpr_log(GPR_DEBUG, "Append error: %s", + absl::StrCat("key=", StringViewFromSlice(md->key), + " error=", error, + " value=", value.as_string_view()) + .c_str()); + }); + } + + return true; +} + +void FilterStackCall::PublishAppMetadata(grpc_metadata_batch* b, + bool is_trailing) { + if (b->count() == 0) return; + if (!is_client() && is_trailing) return; + if (is_trailing && buffered_metadata_[1] == nullptr) return; + grpc_metadata_array* dest; + dest = buffered_metadata_[is_trailing]; + if (dest->count + b->count() > dest->capacity) { + dest->capacity = + std::max(dest->capacity + b->count(), dest->capacity * 3 / 2); + dest->metadata = static_cast( + gpr_realloc(dest->metadata, sizeof(grpc_metadata) * dest->capacity)); + } + PublishToAppEncoder encoder(dest, b, is_client()); + b->Encode(&encoder); +} + +void FilterStackCall::RecvInitialFilter(grpc_metadata_batch* b) { + ProcessIncomingInitialMetadata(*b); + PublishAppMetadata(b, false); +} + +void FilterStackCall::RecvTrailingFilter(grpc_metadata_batch* b, + grpc_error_handle batch_error) { + if (!batch_error.ok()) { + SetFinalStatus(batch_error); + } else { + absl::optional grpc_status = + b->Take(GrpcStatusMetadata()); + if (grpc_status.has_value()) { + grpc_status_code status_code = *grpc_status; + grpc_error_handle error; + if (status_code != GRPC_STATUS_OK) { + Slice peer = GetPeerString(); + error = grpc_error_set_int( + GRPC_ERROR_CREATE(absl::StrCat("Error received from peer ", + peer.as_string_view())), + StatusIntProperty::kRpcStatus, static_cast(status_code)); + } + auto grpc_message = b->Take(GrpcMessageMetadata()); + if (grpc_message.has_value()) { + error = grpc_error_set_str(error, StatusStrProperty::kGrpcMessage, + grpc_message->as_string_view()); + } else if (!error.ok()) { + error = grpc_error_set_str(error, StatusStrProperty::kGrpcMessage, ""); + } + SetFinalStatus(error); + } else if (!is_client()) { + SetFinalStatus(absl::OkStatus()); + } else { + VLOG(2) << "Received trailing metadata with no error and no status"; + SetFinalStatus(grpc_error_set_int(GRPC_ERROR_CREATE("No status received"), + StatusIntProperty::kRpcStatus, + GRPC_STATUS_UNKNOWN)); + } + } + PublishAppMetadata(b, true); +} + +namespace { +size_t BatchSlotForOp(grpc_op_type type) { + switch (type) { + case GRPC_OP_SEND_INITIAL_METADATA: + return 0; + case GRPC_OP_SEND_MESSAGE: + return 1; + case GRPC_OP_SEND_CLOSE_FROM_CLIENT: + case GRPC_OP_SEND_STATUS_FROM_SERVER: + return 2; + case GRPC_OP_RECV_INITIAL_METADATA: + return 3; + case GRPC_OP_RECV_MESSAGE: + return 4; + case GRPC_OP_RECV_CLOSE_ON_SERVER: + case GRPC_OP_RECV_STATUS_ON_CLIENT: + return 5; + } + GPR_UNREACHABLE_CODE(return 123456789); +} +} // namespace + +FilterStackCall::BatchControl* FilterStackCall::ReuseOrAllocateBatchControl( + const grpc_op* ops) { + size_t slot_idx = BatchSlotForOp(ops[0].op); + BatchControl** pslot = &active_batches_[slot_idx]; + BatchControl* bctl; + if (*pslot != nullptr) { + bctl = *pslot; + if (bctl->call_ != nullptr) { + return nullptr; + } + bctl->~BatchControl(); + bctl->op_ = {}; + new (&bctl->batch_error_) AtomicError(); + } else { + bctl = arena()->New(); + *pslot = bctl; + } + bctl->call_ = this; + bctl->call_tracer_ = arena()->GetContext(); + bctl->op_.payload = &stream_op_payload_; + return bctl; +} + +void FilterStackCall::BatchControl::PostCompletion() { + FilterStackCall* call = call_; + grpc_error_handle error = batch_error_.get(); + + if (IsCallStatusOverrideOnCancellationEnabled()) { + // On the client side, if final call status is already known (i.e if this op + // includes recv_trailing_metadata) and if the call status is known to be + // OK, then disregard the batch error to ensure call->receiving_buffer_ is + // not cleared. + if (op_.recv_trailing_metadata && call->is_client() && + call->status_error_.ok()) { + error = absl::OkStatus(); + } + } + + if (grpc_call_trace.enabled()) { + gpr_log(GPR_DEBUG, "tag:%p batch_error=%s op:%s", + completion_data_.notify_tag.tag, error.ToString().c_str(), + grpc_transport_stream_op_batch_string(&op_, false).c_str()); + } + + if (op_.send_initial_metadata) { + call->send_initial_metadata_.Clear(); + } + if (op_.send_message) { + if (op_.payload->send_message.stream_write_closed && error.ok()) { + error = grpc_error_add_child( + error, GRPC_ERROR_CREATE( + "Attempt to send message after stream was closed.")); + } + call->sending_message_ = false; + call->send_slice_buffer_.Clear(); + } + if (op_.send_trailing_metadata) { + call->send_trailing_metadata_.Clear(); + } + + if (!error.ok() && op_.recv_message && *call->receiving_buffer_ != nullptr) { + grpc_byte_buffer_destroy(*call->receiving_buffer_); + *call->receiving_buffer_ = nullptr; + } + if (op_.recv_trailing_metadata) { + // propagate cancellation to any interested children + gpr_atm_rel_store(&call->received_final_op_atm_, 1); + call->PropagateCancellationToChildren(); + error = absl::OkStatus(); + } + batch_error_.set(absl::OkStatus()); + + if (completion_data_.notify_tag.is_closure) { + call_ = nullptr; + GrpcClosure::Run( + DEBUG_LOCATION, + static_cast(completion_data_.notify_tag.tag), error); + call->InternalUnref("completion"); + } else { + grpc_cq_end_op( + call->cq_, completion_data_.notify_tag.tag, error, + [](void* user_data, grpc_cq_completion* /*storage*/) { + BatchControl* bctl = static_cast(user_data); + Call* call = bctl->call_; + bctl->call_ = nullptr; + call->InternalUnref("completion"); + }, + this, &completion_data_.cq_completion); + } +} + +void FilterStackCall::BatchControl::FinishStep(PendingOp op) { + if (GPR_UNLIKELY(completed_batch_step(op))) { + PostCompletion(); + } +} + +void FilterStackCall::BatchControl::ProcessDataAfterMetadata() { + FilterStackCall* call = call_; + if (!call->receiving_slice_buffer_.has_value()) { + *call->receiving_buffer_ = nullptr; + call->receiving_message_ = false; + FinishStep(PendingOp::kRecvMessage); + } else { + call->test_only_last_message_flags_ = call->receiving_stream_flags_; + if ((call->receiving_stream_flags_ & GRPC_WRITE_INTERNAL_COMPRESS) && + (call->incoming_compression_algorithm() != GRPC_COMPRESS_NONE)) { + *call->receiving_buffer_ = grpc_raw_compressed_byte_buffer_create( + nullptr, 0, call->incoming_compression_algorithm()); + } else { + *call->receiving_buffer_ = grpc_raw_byte_buffer_create(nullptr, 0); + } + grpc_slice_buffer_move_into( + call->receiving_slice_buffer_->c_slice_buffer(), + &(*call->receiving_buffer_)->data.raw.slice_buffer); + call->receiving_message_ = false; + call->receiving_slice_buffer_.reset(); + FinishStep(PendingOp::kRecvMessage); + } +} + +void FilterStackCall::BatchControl::ReceivingStreamReady( + grpc_error_handle error) { + if (grpc_call_trace.enabled()) { + gpr_log(GPR_DEBUG, + "tag:%p ReceivingStreamReady error=%s " + "receiving_slice_buffer.has_value=%d recv_state=%" PRIdPTR, + completion_data_.notify_tag.tag, error.ToString().c_str(), + call_->receiving_slice_buffer_.has_value(), + gpr_atm_no_barrier_load(&call_->recv_state_)); + } + FilterStackCall* call = call_; + if (!error.ok()) { + call->receiving_slice_buffer_.reset(); + if (batch_error_.ok()) { + batch_error_.set(error); + } + call->CancelWithError(error); + } + // If recv_state is kRecvNone, we will save the batch_control + // object with rel_cas, and will not use it after the cas. Its corresponding + // acq_load is in receiving_initial_metadata_ready() + if (!error.ok() || !call->receiving_slice_buffer_.has_value() || + !gpr_atm_rel_cas(&call->recv_state_, kRecvNone, + reinterpret_cast(this))) { + ProcessDataAfterMetadata(); + } +} + +void FilterStackCall::BatchControl::ReceivingInitialMetadataReady( + grpc_error_handle error) { + FilterStackCall* call = call_; + + GRPC_CALL_COMBINER_STOP(call->call_combiner(), "recv_initial_metadata_ready"); + + if (error.ok()) { + grpc_metadata_batch* md = &call->recv_initial_metadata_; + call->RecvInitialFilter(md); + + absl::optional deadline = md->get(GrpcTimeoutMetadata()); + if (deadline.has_value() && !call->is_client()) { + call_->set_send_deadline(*deadline); + } + } else { + if (batch_error_.ok()) { + batch_error_.set(error); + } + call->CancelWithError(error); + } + + grpc_closure* saved_rsr_closure = nullptr; + while (true) { + gpr_atm rsr_bctlp = gpr_atm_acq_load(&call->recv_state_); + // Should only receive initial metadata once + CHECK_NE(rsr_bctlp, 1); + if (rsr_bctlp == 0) { + // We haven't seen initial metadata and messages before, thus initial + // metadata is received first. + // no_barrier_cas is used, as this function won't access the batch_control + // object saved by receiving_stream_ready() if the initial metadata is + // received first. + if (gpr_atm_no_barrier_cas(&call->recv_state_, kRecvNone, + kRecvInitialMetadataFirst)) { + break; + } + } else { + // Already received messages + saved_rsr_closure = GRPC_CLOSURE_CREATE( + [](void* bctl, grpc_error_handle error) { + static_cast(bctl)->ReceivingStreamReady(error); + }, + reinterpret_cast(rsr_bctlp), + grpc_schedule_on_exec_ctx); + // No need to modify recv_state + break; + } + } + if (saved_rsr_closure != nullptr) { + GrpcClosure::Run(DEBUG_LOCATION, saved_rsr_closure, error); + } + + FinishStep(PendingOp::kRecvInitialMetadata); +} + +void FilterStackCall::BatchControl::ReceivingTrailingMetadataReady( + grpc_error_handle error) { + GRPC_CALL_COMBINER_STOP(call_->call_combiner(), + "recv_trailing_metadata_ready"); + grpc_metadata_batch* md = &call_->recv_trailing_metadata_; + call_->RecvTrailingFilter(md, error); + FinishStep(PendingOp::kRecvTrailingMetadata); +} + +void FilterStackCall::BatchControl::FinishBatch(grpc_error_handle error) { + GRPC_CALL_COMBINER_STOP(call_->call_combiner(), "on_complete"); + if (batch_error_.ok()) { + batch_error_.set(error); + } + if (!error.ok()) { + call_->CancelWithError(error); + } + FinishStep(PendingOp::kSends); +} + +grpc_call_error FilterStackCall::StartBatch(const grpc_op* ops, size_t nops, + void* notify_tag, + bool is_notify_tag_closure) { + size_t i; + const grpc_op* op; + BatchControl* bctl; + grpc_call_error error = GRPC_CALL_OK; + grpc_transport_stream_op_batch* stream_op; + grpc_transport_stream_op_batch_payload* stream_op_payload; + uint32_t seen_ops = 0; + intptr_t pending_ops = 0; + + for (i = 0; i < nops; i++) { + if (seen_ops & (1u << ops[i].op)) { + return GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; + } + seen_ops |= (1u << ops[i].op); + } + + if (!is_client() && + (seen_ops & (1u << GRPC_OP_SEND_STATUS_FROM_SERVER)) != 0 && + (seen_ops & (1u << GRPC_OP_RECV_MESSAGE)) != 0) { + gpr_log(GPR_ERROR, + "******************* SEND_STATUS WITH RECV_MESSAGE " + "*******************"); + return GRPC_CALL_ERROR; + } + + GRPC_CALL_LOG_BATCH(GPR_INFO, ops, nops); + + if (nops == 0) { + EndOpImmediately(cq_, notify_tag, is_notify_tag_closure); + error = GRPC_CALL_OK; + goto done; + } + + bctl = ReuseOrAllocateBatchControl(ops); + if (bctl == nullptr) { + return GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; + } + bctl->completion_data_.notify_tag.tag = notify_tag; + bctl->completion_data_.notify_tag.is_closure = + static_cast(is_notify_tag_closure != 0); + + stream_op = &bctl->op_; + stream_op_payload = &stream_op_payload_; + + // rewrite batch ops into a transport op + for (i = 0; i < nops; i++) { + op = &ops[i]; + if (op->reserved != nullptr) { + error = GRPC_CALL_ERROR; + goto done_with_error; + } + switch (op->op) { + case GRPC_OP_SEND_INITIAL_METADATA: { + // Flag validation: currently allow no flags + if (!AreInitialMetadataFlagsValid(op->flags)) { + error = GRPC_CALL_ERROR_INVALID_FLAGS; + goto done_with_error; + } + if (sent_initial_metadata_) { + error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; + goto done_with_error; + } + if (op->data.send_initial_metadata.count > INT_MAX) { + error = GRPC_CALL_ERROR_INVALID_METADATA; + goto done_with_error; + } + stream_op->send_initial_metadata = true; + sent_initial_metadata_ = true; + if (!PrepareApplicationMetadata(op->data.send_initial_metadata.count, + op->data.send_initial_metadata.metadata, + false)) { + error = GRPC_CALL_ERROR_INVALID_METADATA; + goto done_with_error; + } + PrepareOutgoingInitialMetadata(*op, send_initial_metadata_); + // TODO(ctiller): just make these the same variable? + if (is_client() && send_deadline() != Timestamp::InfFuture()) { + send_initial_metadata_.Set(GrpcTimeoutMetadata(), send_deadline()); + } + if (is_client()) { + send_initial_metadata_.Set( + WaitForReady(), + WaitForReady::ValueType{ + (op->flags & GRPC_INITIAL_METADATA_WAIT_FOR_READY) != 0, + (op->flags & + GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET) != 0}); + } + stream_op_payload->send_initial_metadata.send_initial_metadata = + &send_initial_metadata_; + pending_ops |= PendingOpMask(PendingOp::kSends); + break; + } + case GRPC_OP_SEND_MESSAGE: { + if (!AreWriteFlagsValid(op->flags)) { + error = GRPC_CALL_ERROR_INVALID_FLAGS; + goto done_with_error; + } + if (op->data.send_message.send_message == nullptr) { + error = GRPC_CALL_ERROR_INVALID_MESSAGE; + goto done_with_error; + } + if (sending_message_) { + error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; + goto done_with_error; + } + uint32_t flags = op->flags; + // If the outgoing buffer is already compressed, mark it as so in the + // flags. These will be picked up by the compression filter and further + // (wasteful) attempts at compression skipped. + if (op->data.send_message.send_message->data.raw.compression > + GRPC_COMPRESS_NONE) { + flags |= GRPC_WRITE_INTERNAL_COMPRESS; + } + stream_op->send_message = true; + sending_message_ = true; + send_slice_buffer_.Clear(); + grpc_slice_buffer_move_into( + &op->data.send_message.send_message->data.raw.slice_buffer, + send_slice_buffer_.c_slice_buffer()); + stream_op_payload->send_message.flags = flags; + stream_op_payload->send_message.send_message = &send_slice_buffer_; + pending_ops |= PendingOpMask(PendingOp::kSends); + break; + } + case GRPC_OP_SEND_CLOSE_FROM_CLIENT: { + // Flag validation: currently allow no flags + if (op->flags != 0) { + error = GRPC_CALL_ERROR_INVALID_FLAGS; + goto done_with_error; + } + if (!is_client()) { + error = GRPC_CALL_ERROR_NOT_ON_SERVER; + goto done_with_error; + } + if (sent_final_op_) { + error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; + goto done_with_error; + } + stream_op->send_trailing_metadata = true; + sent_final_op_ = true; + stream_op_payload->send_trailing_metadata.send_trailing_metadata = + &send_trailing_metadata_; + pending_ops |= PendingOpMask(PendingOp::kSends); + break; + } + case GRPC_OP_SEND_STATUS_FROM_SERVER: { + // Flag validation: currently allow no flags + if (op->flags != 0) { + error = GRPC_CALL_ERROR_INVALID_FLAGS; + goto done_with_error; + } + if (is_client()) { + error = GRPC_CALL_ERROR_NOT_ON_CLIENT; + goto done_with_error; + } + if (sent_final_op_) { + error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; + goto done_with_error; + } + if (op->data.send_status_from_server.trailing_metadata_count > + INT_MAX) { + error = GRPC_CALL_ERROR_INVALID_METADATA; + goto done_with_error; + } + stream_op->send_trailing_metadata = true; + sent_final_op_ = true; + + if (!PrepareApplicationMetadata( + op->data.send_status_from_server.trailing_metadata_count, + op->data.send_status_from_server.trailing_metadata, true)) { + error = GRPC_CALL_ERROR_INVALID_METADATA; + goto done_with_error; + } + + grpc_error_handle status_error = + op->data.send_status_from_server.status == GRPC_STATUS_OK + ? absl::OkStatus() + : grpc_error_set_int( + GRPC_ERROR_CREATE("Server returned error"), + StatusIntProperty::kRpcStatus, + static_cast( + op->data.send_status_from_server.status)); + if (op->data.send_status_from_server.status_details != nullptr) { + send_trailing_metadata_.Set( + GrpcMessageMetadata(), + Slice(grpc_slice_copy( + *op->data.send_status_from_server.status_details))); + if (!status_error.ok()) { + status_error = grpc_error_set_str( + status_error, StatusStrProperty::kGrpcMessage, + StringViewFromSlice( + *op->data.send_status_from_server.status_details)); + } + } + + status_error_.set(status_error); + + send_trailing_metadata_.Set(GrpcStatusMetadata(), + op->data.send_status_from_server.status); + + // Ignore any te metadata key value pairs specified. + send_trailing_metadata_.Remove(TeMetadata()); + stream_op_payload->send_trailing_metadata.send_trailing_metadata = + &send_trailing_metadata_; + stream_op_payload->send_trailing_metadata.sent = + &sent_server_trailing_metadata_; + pending_ops |= PendingOpMask(PendingOp::kSends); + break; + } + case GRPC_OP_RECV_INITIAL_METADATA: { + // Flag validation: currently allow no flags + if (op->flags != 0) { + error = GRPC_CALL_ERROR_INVALID_FLAGS; + goto done_with_error; + } + if (received_initial_metadata_) { + error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; + goto done_with_error; + } + received_initial_metadata_ = true; + buffered_metadata_[0] = + op->data.recv_initial_metadata.recv_initial_metadata; + GRPC_CLOSURE_INIT( + &receiving_initial_metadata_ready_, + [](void* bctl, grpc_error_handle error) { + static_cast(bctl)->ReceivingInitialMetadataReady( + error); + }, + bctl, grpc_schedule_on_exec_ctx); + stream_op->recv_initial_metadata = true; + stream_op_payload->recv_initial_metadata.recv_initial_metadata = + &recv_initial_metadata_; + stream_op_payload->recv_initial_metadata.recv_initial_metadata_ready = + &receiving_initial_metadata_ready_; + if (is_client()) { + stream_op_payload->recv_initial_metadata.trailing_metadata_available = + &is_trailers_only_; + } + pending_ops |= PendingOpMask(PendingOp::kRecvInitialMetadata); + break; + } + case GRPC_OP_RECV_MESSAGE: { + // Flag validation: currently allow no flags + if (op->flags != 0) { + error = GRPC_CALL_ERROR_INVALID_FLAGS; + goto done_with_error; + } + if (receiving_message_) { + error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; + goto done_with_error; + } + receiving_message_ = true; + stream_op->recv_message = true; + receiving_slice_buffer_.reset(); + receiving_buffer_ = op->data.recv_message.recv_message; + stream_op_payload->recv_message.recv_message = &receiving_slice_buffer_; + receiving_stream_flags_ = 0; + stream_op_payload->recv_message.flags = &receiving_stream_flags_; + stream_op_payload->recv_message.call_failed_before_recv_message = + &call_failed_before_recv_message_; + GRPC_CLOSURE_INIT( + &receiving_stream_ready_, + [](void* bctlp, grpc_error_handle error) { + auto* bctl = static_cast(bctlp); + auto* call = bctl->call_; + // Yields the call combiner before processing the received + // message. + GRPC_CALL_COMBINER_STOP(call->call_combiner(), + "recv_message_ready"); + bctl->ReceivingStreamReady(error); + }, + bctl, grpc_schedule_on_exec_ctx); + stream_op_payload->recv_message.recv_message_ready = + &receiving_stream_ready_; + pending_ops |= PendingOpMask(PendingOp::kRecvMessage); + break; + } + case GRPC_OP_RECV_STATUS_ON_CLIENT: { + // Flag validation: currently allow no flags + if (op->flags != 0) { + error = GRPC_CALL_ERROR_INVALID_FLAGS; + goto done_with_error; + } + if (!is_client()) { + error = GRPC_CALL_ERROR_NOT_ON_SERVER; + goto done_with_error; + } + if (requested_final_op_) { + error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; + goto done_with_error; + } + requested_final_op_ = true; + buffered_metadata_[1] = + op->data.recv_status_on_client.trailing_metadata; + final_op_.client.status = op->data.recv_status_on_client.status; + final_op_.client.status_details = + op->data.recv_status_on_client.status_details; + final_op_.client.error_string = + op->data.recv_status_on_client.error_string; + stream_op->recv_trailing_metadata = true; + stream_op_payload->recv_trailing_metadata.recv_trailing_metadata = + &recv_trailing_metadata_; + stream_op_payload->recv_trailing_metadata.collect_stats = + &final_info_.stats.transport_stream_stats; + GRPC_CLOSURE_INIT( + &receiving_trailing_metadata_ready_, + [](void* bctl, grpc_error_handle error) { + static_cast(bctl)->ReceivingTrailingMetadataReady( + error); + }, + bctl, grpc_schedule_on_exec_ctx); + stream_op_payload->recv_trailing_metadata.recv_trailing_metadata_ready = + &receiving_trailing_metadata_ready_; + pending_ops |= PendingOpMask(PendingOp::kRecvTrailingMetadata); + break; + } + case GRPC_OP_RECV_CLOSE_ON_SERVER: { + // Flag validation: currently allow no flags + if (op->flags != 0) { + error = GRPC_CALL_ERROR_INVALID_FLAGS; + goto done_with_error; + } + if (is_client()) { + error = GRPC_CALL_ERROR_NOT_ON_CLIENT; + goto done_with_error; + } + if (requested_final_op_) { + error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; + goto done_with_error; + } + requested_final_op_ = true; + final_op_.server.cancelled = op->data.recv_close_on_server.cancelled; + stream_op->recv_trailing_metadata = true; + stream_op_payload->recv_trailing_metadata.recv_trailing_metadata = + &recv_trailing_metadata_; + stream_op_payload->recv_trailing_metadata.collect_stats = + &final_info_.stats.transport_stream_stats; + GRPC_CLOSURE_INIT( + &receiving_trailing_metadata_ready_, + [](void* bctl, grpc_error_handle error) { + static_cast(bctl)->ReceivingTrailingMetadataReady( + error); + }, + bctl, grpc_schedule_on_exec_ctx); + stream_op_payload->recv_trailing_metadata.recv_trailing_metadata_ready = + &receiving_trailing_metadata_ready_; + pending_ops |= PendingOpMask(PendingOp::kRecvTrailingMetadata); + break; + } + } + } + + InternalRef("completion"); + if (!is_notify_tag_closure) { + CHECK(grpc_cq_begin_op(cq_, notify_tag)); + } + bctl->set_pending_ops(pending_ops); + + if (pending_ops & PendingOpMask(PendingOp::kSends)) { + GRPC_CLOSURE_INIT( + &bctl->finish_batch_, + [](void* bctl, grpc_error_handle error) { + static_cast(bctl)->FinishBatch(error); + }, + bctl, grpc_schedule_on_exec_ctx); + stream_op->on_complete = &bctl->finish_batch_; + } + + if (grpc_call_trace.enabled()) { + gpr_log(GPR_DEBUG, "BATCH:%p START:%s BATCH:%s (tag:%p)", bctl, + PendingOpString(pending_ops).c_str(), + grpc_transport_stream_op_batch_string(stream_op, false).c_str(), + bctl->completion_data_.notify_tag.tag); + } + ExecuteBatch(stream_op, &bctl->start_batch_); + +done: + return error; + +done_with_error: + // reverse any mutations that occurred + if (stream_op->send_initial_metadata) { + sent_initial_metadata_ = false; + send_initial_metadata_.Clear(); + } + if (stream_op->send_message) { + sending_message_ = false; + } + if (stream_op->send_trailing_metadata) { + sent_final_op_ = false; + send_trailing_metadata_.Clear(); + } + if (stream_op->recv_initial_metadata) { + received_initial_metadata_ = false; + } + if (stream_op->recv_message) { + receiving_message_ = false; + } + if (stream_op->recv_trailing_metadata) { + requested_final_op_ = false; + } + goto done; +} + +char* FilterStackCall::GetPeer() { + Slice peer_slice = GetPeerString(); + if (!peer_slice.empty()) { + absl::string_view peer_string_view = peer_slice.as_string_view(); + char* peer_string = + static_cast(gpr_malloc(peer_string_view.size() + 1)); + memcpy(peer_string, peer_string_view.data(), peer_string_view.size()); + peer_string[peer_string_view.size()] = '\0'; + return peer_string; + } + char* peer_string = grpc_channel_get_target(channel_->c_ptr()); + if (peer_string != nullptr) return peer_string; + return gpr_strdup("unknown"); +} + +} // namespace grpc_core + +grpc_error_handle grpc_call_create(grpc_call_create_args* args, + grpc_call** out_call) { + return grpc_core::FilterStackCall::Create(args, out_call); +} + +grpc_call* grpc_call_from_top_element(grpc_call_element* surface_element) { + return grpc_core::FilterStackCall::FromTopElem(surface_element)->c_ptr(); +} diff --git a/src/core/lib/surface/filter_stack_call.h b/src/core/lib/surface/filter_stack_call.h new file mode 100644 index 00000000000..8ff00bfc357 --- /dev/null +++ b/src/core/lib/surface/filter_stack_call.h @@ -0,0 +1,370 @@ +// 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_LIB_SURFACE_FILTER_STACK_CALL_H +#define GRPC_SRC_CORE_LIB_SURFACE_FILTER_STACK_CALL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "src/core/lib/channel/channel_stack.h" +#include "src/core/lib/gprpp/ref_counted.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" +#include "src/core/lib/iomgr/call_combiner.h" +#include "src/core/lib/iomgr/polling_entity.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/surface/call.h" +#include "src/core/lib/surface/call_trace.h" +#include "src/core/lib/surface/channel.h" +#include "src/core/lib/surface/completion_queue.h" +#include "src/core/lib/transport/metadata_batch.h" +#include "src/core/lib/transport/transport.h" +#include "src/core/server/server_interface.h" +#include "src/core/telemetry/call_tracer.h" +#include "src/core/util/alloc.h" +#include "absl/log/check.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_join.h" +#include "absl/strings/string_view.h" + +namespace grpc_core { + +/////////////////////////////////////////////////////////////////////////////// +// FilterStackCall +// To be removed once promise conversion is complete + +class FilterStackCall final : public Call { + public: + ~FilterStackCall() override { + gpr_free(static_cast(const_cast(final_info_.error_string))); + } + + bool Completed() override { + return gpr_atm_acq_load(&received_final_op_atm_) != 0; + } + + // TODO(ctiller): return absl::StatusOr>? + static grpc_error_handle Create(grpc_call_create_args* args, + grpc_call** out_call); + + static Call* FromTopElem(grpc_call_element* elem) { + return FromCallStack(grpc_call_stack_from_top_element(elem)); + } + + grpc_call_stack* call_stack() override { + return reinterpret_cast( + reinterpret_cast(this) + + GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(*this))); + } + + grpc_call_element* call_elem(size_t idx) { + return grpc_call_stack_element(call_stack(), idx); + } + + CallCombiner* call_combiner() { return &call_combiner_; } + + void CancelWithError(grpc_error_handle error) override; + void SetCompletionQueue(grpc_completion_queue* cq) override; + grpc_call_error StartBatch(const grpc_op* ops, size_t nops, void* notify_tag, + bool is_notify_tag_closure) override; + void ExternalRef() override { ext_ref_.Ref(); } + void ExternalUnref() override; + void InternalRef(const char* reason) override { + GRPC_CALL_STACK_REF(call_stack(), reason); + } + void InternalUnref(const char* reason) override { + GRPC_CALL_STACK_UNREF(call_stack(), reason); + } + + bool is_trailers_only() const override { + bool result = is_trailers_only_; + DCHECK(!result || recv_initial_metadata_.TransportSize() == 0); + return result; + } + + bool failed_before_recv_message() const override { + return call_failed_before_recv_message_; + } + + uint32_t test_only_message_flags() override { + return test_only_last_message_flags_; + } + + absl::string_view GetServerAuthority() const override { + const Slice* authority_metadata = + recv_initial_metadata_.get_pointer(HttpAuthorityMetadata()); + if (authority_metadata == nullptr) return ""; + return authority_metadata->as_string_view(); + } + + static size_t InitialSizeEstimate() { + return sizeof(FilterStackCall) + + sizeof(BatchControl) * kMaxConcurrentBatches; + } + + char* GetPeer() final; + + grpc_compression_options compression_options() override { + return channel_->compression_options(); + } + + void DeleteThis() { + auto arena = this->arena()->Ref(); + this->~FilterStackCall(); + } + + Channel* channel() const { return channel_.get(); } + + private: + class ScopedContext : public promise_detail::Context { + public: + explicit ScopedContext(FilterStackCall* call) + : promise_detail::Context(call->arena()) {} + }; + + static constexpr gpr_atm kRecvNone = 0; + static constexpr gpr_atm kRecvInitialMetadataFirst = 1; + + enum class PendingOp { + kRecvMessage, + kRecvInitialMetadata, + kRecvTrailingMetadata, + kSends + }; + static intptr_t PendingOpMask(PendingOp op) { + return static_cast(1) << static_cast(op); + } + static std::string PendingOpString(intptr_t pending_ops) { + std::vector pending_op_strings; + if (pending_ops & PendingOpMask(PendingOp::kRecvMessage)) { + pending_op_strings.push_back("kRecvMessage"); + } + if (pending_ops & PendingOpMask(PendingOp::kRecvInitialMetadata)) { + pending_op_strings.push_back("kRecvInitialMetadata"); + } + if (pending_ops & PendingOpMask(PendingOp::kRecvTrailingMetadata)) { + pending_op_strings.push_back("kRecvTrailingMetadata"); + } + if (pending_ops & PendingOpMask(PendingOp::kSends)) { + pending_op_strings.push_back("kSends"); + } + return absl::StrCat("{", absl::StrJoin(pending_op_strings, ","), "}"); + } + struct BatchControl { + FilterStackCall* call_ = nullptr; + CallTracerAnnotationInterface* call_tracer_ = nullptr; + grpc_transport_stream_op_batch op_; + // Share memory for cq_completion and notify_tag as they are never needed + // simultaneously. Each byte used in this data structure count as six bytes + // per call, so any savings we can make are worthwhile, + + // We use notify_tag to determine whether or not to send notification to the + // completion queue. Once we've made that determination, we can reuse the + // memory for cq_completion. + union { + grpc_cq_completion cq_completion; + struct { + // Any given op indicates completion by either (a) calling a closure or + // (b) sending a notification on the call's completion queue. If + // \a is_closure is true, \a tag indicates a closure to be invoked; + // otherwise, \a tag indicates the tag to be used in the notification to + // be sent to the completion queue. + void* tag; + bool is_closure; + } notify_tag; + } completion_data_; + grpc_closure start_batch_; + grpc_closure finish_batch_; + std::atomic ops_pending_{0}; + AtomicError batch_error_; + void set_pending_ops(uintptr_t ops) { + ops_pending_.store(ops, std::memory_order_release); + } + bool completed_batch_step(PendingOp op) { + auto mask = PendingOpMask(op); + auto r = ops_pending_.fetch_sub(mask, std::memory_order_acq_rel); + if (grpc_call_trace.enabled()) { + gpr_log(GPR_DEBUG, "BATCH:%p COMPLETE:%s REMAINING:%s (tag:%p)", this, + PendingOpString(mask).c_str(), + PendingOpString(r & ~mask).c_str(), + completion_data_.notify_tag.tag); + } + CHECK_NE((r & mask), 0); + return r == mask; + } + + void PostCompletion(); + void FinishStep(PendingOp op); + void ProcessDataAfterMetadata(); + void ReceivingStreamReady(grpc_error_handle error); + void ReceivingInitialMetadataReady(grpc_error_handle error); + void ReceivingTrailingMetadataReady(grpc_error_handle error); + void FinishBatch(grpc_error_handle error); + }; + + FilterStackCall(RefCountedPtr arena, + const grpc_call_create_args& args); + + static void ReleaseCall(void* call, grpc_error_handle); + static void DestroyCall(void* call, grpc_error_handle); + + static FilterStackCall* FromCallStack(grpc_call_stack* call_stack) { + return reinterpret_cast( + reinterpret_cast(call_stack) - + GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(FilterStackCall))); + } + + void ExecuteBatch(grpc_transport_stream_op_batch* batch, + grpc_closure* start_batch_closure); + void SetFinalStatus(grpc_error_handle error); + BatchControl* ReuseOrAllocateBatchControl(const grpc_op* ops); + bool PrepareApplicationMetadata(size_t count, grpc_metadata* metadata, + bool is_trailing); + void PublishAppMetadata(grpc_metadata_batch* b, bool is_trailing); + void RecvInitialFilter(grpc_metadata_batch* b); + void RecvTrailingFilter(grpc_metadata_batch* b, + grpc_error_handle batch_error); + + grpc_compression_algorithm incoming_compression_algorithm() override { + return incoming_compression_algorithm_; + } + void SetIncomingCompressionAlgorithm( + grpc_compression_algorithm algorithm) override { + incoming_compression_algorithm_ = algorithm; + } + + RefCountedPtr channel_; + RefCount ext_ref_; + CallCombiner call_combiner_; + grpc_completion_queue* cq_; + grpc_polling_entity pollent_; + + /// has grpc_call_unref been called + bool destroy_called_ = false; + // Trailers-only response status + bool is_trailers_only_ = false; + /// which ops are in-flight + bool sent_initial_metadata_ = false; + bool sending_message_ = false; + bool sent_final_op_ = false; + bool received_initial_metadata_ = false; + bool receiving_message_ = false; + bool requested_final_op_ = false; + gpr_atm received_final_op_atm_ = 0; + + BatchControl* active_batches_[kMaxConcurrentBatches] = {}; + grpc_transport_stream_op_batch_payload stream_op_payload_; + + // first idx: is_receiving, second idx: is_trailing + grpc_metadata_batch send_initial_metadata_; + grpc_metadata_batch send_trailing_metadata_; + grpc_metadata_batch recv_initial_metadata_; + grpc_metadata_batch recv_trailing_metadata_; + + // Buffered read metadata waiting to be returned to the application. + // Element 0 is initial metadata, element 1 is trailing metadata. + grpc_metadata_array* buffered_metadata_[2] = {}; + + // Call data useful used for reporting. Only valid after the call has + // completed + grpc_call_final_info final_info_; + + SliceBuffer send_slice_buffer_; + absl::optional receiving_slice_buffer_; + uint32_t receiving_stream_flags_; + uint32_t test_only_last_message_flags_ = 0; + // Compression algorithm for *incoming* data + grpc_compression_algorithm incoming_compression_algorithm_ = + GRPC_COMPRESS_NONE; + + bool call_failed_before_recv_message_ = false; + grpc_byte_buffer** receiving_buffer_ = nullptr; + grpc_slice receiving_slice_ = grpc_empty_slice(); + grpc_closure receiving_stream_ready_; + grpc_closure receiving_initial_metadata_ready_; + grpc_closure receiving_trailing_metadata_ready_; + // Status about operation of call + bool sent_server_trailing_metadata_ = false; + gpr_atm cancelled_with_error_ = 0; + + grpc_closure release_call_; + + union { + struct { + grpc_status_code* status; + grpc_slice* status_details; + const char** error_string; + } client; + struct { + int* cancelled; + // backpointer to owning server if this is a server side call. + ServerInterface* core_server; + } server; + } final_op_; + AtomicError status_error_; + + // recv_state can contain one of the following values: + // RECV_NONE : : no initial metadata and messages received + // RECV_INITIAL_METADATA_FIRST : received initial metadata first + // a batch_control* : received messages first + + // +------1------RECV_NONE------3-----+ + // | | + // | | + // v v + // RECV_INITIAL_METADATA_FIRST receiving_stream_ready_bctlp + // | ^ | ^ + // | | | | + // +-----2-----+ +-----4-----+ + + // For 1, 4: See receiving_initial_metadata_ready() function + // For 2, 3: See receiving_stream_ready() function + gpr_atm recv_state_ = 0; +}; + +// Create a new call based on \a args. +// Regardless of success or failure, always returns a valid new call into *call +// +grpc_error_handle grpc_call_create(grpc_call_create_args* args, + grpc_call** call); + +// Given the top call_element, get the call object. +grpc_call* grpc_call_from_top_element(grpc_call_element* surface_element); + +} // namespace grpc_core + +#endif // GRPC_SRC_CORE_LIB_SURFACE_FILTER_STACK_CALL_H diff --git a/src/core/lib/surface/legacy_channel.cc b/src/core/lib/surface/legacy_channel.cc index c35e0158c51..fc4c855950d 100644 --- a/src/core/lib/surface/legacy_channel.cc +++ b/src/core/lib/surface/legacy_channel.cc @@ -60,7 +60,7 @@ namespace grpc_core { -absl::StatusOr> LegacyChannel::Create( +absl::StatusOr> LegacyChannel::Create( std::string target, ChannelArgs args, grpc_channel_stack_type channel_stack_type) { if (grpc_channel_stack_type_is_client(channel_stack_type)) { @@ -101,18 +101,16 @@ absl::StatusOr> LegacyChannel::Create( GlobalStatsPluginRegistry::GetStatsPluginsForChannel( experimental::StatsPluginChannelScope(target, authority)); } - return MakeOrphanable( + return MakeRefCounted( grpc_channel_stack_type_is_client(builder.channel_stack_type()), - builder.IsPromising(), std::move(target), args, std::move(*r)); + std::move(target), args, std::move(*r)); } -LegacyChannel::LegacyChannel(bool is_client, bool is_promising, - std::string target, +LegacyChannel::LegacyChannel(bool is_client, std::string target, const ChannelArgs& channel_args, RefCountedPtr channel_stack) : Channel(std::move(target), channel_args), is_client_(is_client), - is_promising_(is_promising), 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 @@ -144,13 +142,12 @@ LegacyChannel::LegacyChannel(bool is_client, bool is_promising, }; } -void LegacyChannel::Orphan() { +void LegacyChannel::Orphaned() { grpc_transport_op* op = grpc_make_transport_op(nullptr); op->disconnect_with_error = GRPC_ERROR_CREATE("Channel Destroyed"); grpc_channel_element* elem = grpc_channel_stack_element(channel_stack_.get(), 0); elem->filter->start_transport_op(elem, op); - Unref(); } bool LegacyChannel::IsLame() const { @@ -167,7 +164,7 @@ grpc_call* LegacyChannel::CreateCall( CHECK(is_client_); CHECK(!(cq != nullptr && pollset_set_alternative != nullptr)); grpc_call_create_args args; - args.channel = Ref(); + args.channel = RefAsSubclass(); args.server = nullptr; args.parent = parent_call; args.propagation_mask = propagation_mask; @@ -204,9 +201,9 @@ bool LegacyChannel::SupportsConnectivityWatcher() const { // A fire-and-forget object to handle external connectivity state watches. class LegacyChannel::StateWatcher final : public DualRefCounted { public: - StateWatcher(RefCountedPtr channel, grpc_completion_queue* cq, - void* tag, grpc_connectivity_state last_observed_state, - Timestamp deadline) + StateWatcher(WeakRefCountedPtr channel, + grpc_completion_queue* cq, void* tag, + grpc_connectivity_state last_observed_state, Timestamp deadline) : channel_(std::move(channel)), cq_(cq), tag_(tag), @@ -313,7 +310,7 @@ class LegacyChannel::StateWatcher final : public DualRefCounted { self->WeakUnref(); } - RefCountedPtr channel_; + WeakRefCountedPtr channel_; grpc_completion_queue* cq_; void* tag_; @@ -333,8 +330,8 @@ class LegacyChannel::StateWatcher final : public DualRefCounted { void LegacyChannel::WatchConnectivityState( grpc_connectivity_state last_observed_state, Timestamp deadline, grpc_completion_queue* cq, void* tag) { - new StateWatcher(RefAsSubclass(), cq, tag, last_observed_state, - deadline); + new StateWatcher(WeakRefAsSubclass(), cq, tag, + last_observed_state, deadline); } void LegacyChannel::AddConnectivityWatcher( @@ -401,8 +398,7 @@ void LegacyChannel::Ping(grpc_completion_queue* cq, void* tag) { ClientChannelFilter* LegacyChannel::GetClientChannelFilter() const { grpc_channel_element* elem = grpc_channel_stack_last_element(channel_stack_.get()); - if (elem->filter != &ClientChannelFilter::kFilterVtableWithPromises && - elem->filter != &ClientChannelFilter::kFilterVtableWithoutPromises) { + if (elem->filter != &ClientChannelFilter::kFilter) { return nullptr; } return static_cast(elem->channel_data); diff --git a/src/core/lib/surface/legacy_channel.h b/src/core/lib/surface/legacy_channel.h index b5199e80939..ed5938437a5 100644 --- a/src/core/lib/surface/legacy_channel.h +++ b/src/core/lib/surface/legacy_channel.h @@ -46,16 +46,16 @@ namespace grpc_core { class LegacyChannel final : public Channel { public: - static absl::StatusOr> Create( + static absl::StatusOr> Create( std::string target, ChannelArgs args, grpc_channel_stack_type channel_stack_type); // Do not instantiate directly -- use Create() instead. - LegacyChannel(bool is_client, bool is_promising, std::string target, + LegacyChannel(bool is_client, std::string target, const ChannelArgs& channel_args, RefCountedPtr channel_stack); - void Orphan() override; + void Orphaned() override; bool IsLame() const override; @@ -65,6 +65,10 @@ class LegacyChannel final : public Channel { absl::optional authority, Timestamp deadline, bool registered_method) override; + void StartCall(UnstartedCallHandler) override { + Crash("StartCall() not supported on LegacyChannel"); + } + grpc_event_engine::experimental::EventEngine* event_engine() const override { return channel_stack_->EventEngine(); } @@ -90,7 +94,6 @@ class LegacyChannel final : public Channel { void Ping(grpc_completion_queue* cq, void* tag) override; bool is_client() const override { return is_client_; } - bool is_promising() const override { return is_promising_; } grpc_channel_stack* channel_stack() const override { return channel_stack_.get(); } @@ -103,7 +106,6 @@ class LegacyChannel final : public Channel { ClientChannelFilter* GetClientChannelFilter() const; const bool is_client_; - const bool is_promising_; RefCountedPtr channel_stack_; }; diff --git a/src/core/lib/surface/server_call.cc b/src/core/lib/surface/server_call.cc new file mode 100644 index 00000000000..9affa893ab8 --- /dev/null +++ b/src/core/lib/surface/server_call.cc @@ -0,0 +1,224 @@ +// 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/lib/surface/server_call.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include "absl/log/check.h" +#include "absl/strings/string_view.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "src/core/lib/gprpp/bitset.h" +#include "src/core/lib/promise/all_ok.h" +#include "src/core/lib/promise/map.h" +#include "src/core/lib/promise/poll.h" +#include "src/core/lib/promise/status_flag.h" +#include "src/core/lib/promise/try_seq.h" +#include "src/core/lib/resource_quota/arena.h" +#include "src/core/lib/slice/slice_buffer.h" +#include "src/core/lib/surface/completion_queue.h" +#include "src/core/lib/transport/metadata.h" +#include "src/core/lib/transport/metadata_batch.h" +#include "src/core/server/server_interface.h" + +namespace grpc_core { + +namespace { + +grpc_call_error ValidateServerBatch(const grpc_op* ops, size_t nops) { + BitSet<8> got_ops; + for (size_t op_idx = 0; op_idx < nops; op_idx++) { + const grpc_op& op = ops[op_idx]; + switch (op.op) { + case GRPC_OP_SEND_INITIAL_METADATA: + if (!AreInitialMetadataFlagsValid(op.flags)) { + return GRPC_CALL_ERROR_INVALID_FLAGS; + } + if (!ValidateMetadata(op.data.send_initial_metadata.count, + op.data.send_initial_metadata.metadata)) { + return GRPC_CALL_ERROR_INVALID_METADATA; + } + break; + case GRPC_OP_SEND_MESSAGE: + if (!AreWriteFlagsValid(op.flags)) { + return GRPC_CALL_ERROR_INVALID_FLAGS; + } + break; + case GRPC_OP_SEND_STATUS_FROM_SERVER: + if (op.flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; + if (!ValidateMetadata( + op.data.send_status_from_server.trailing_metadata_count, + op.data.send_status_from_server.trailing_metadata)) { + return GRPC_CALL_ERROR_INVALID_METADATA; + } + break; + case GRPC_OP_RECV_MESSAGE: + case GRPC_OP_RECV_CLOSE_ON_SERVER: + if (op.flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; + break; + case GRPC_OP_RECV_INITIAL_METADATA: + case GRPC_OP_SEND_CLOSE_FROM_CLIENT: + case GRPC_OP_RECV_STATUS_ON_CLIENT: + return GRPC_CALL_ERROR_NOT_ON_SERVER; + } + if (got_ops.is_set(op.op)) return GRPC_CALL_ERROR_TOO_MANY_OPERATIONS; + got_ops.set(op.op); + } + return GRPC_CALL_OK; +} + +} // namespace + +grpc_call_error ServerCall::StartBatch(const grpc_op* ops, size_t nops, + void* notify_tag, + bool is_notify_tag_closure) { + if (nops == 0) { + EndOpImmediately(cq_, notify_tag, is_notify_tag_closure); + return GRPC_CALL_OK; + } + const grpc_call_error validation_result = ValidateServerBatch(ops, nops); + if (validation_result != GRPC_CALL_OK) { + return validation_result; + } + CommitBatch(ops, nops, notify_tag, is_notify_tag_closure); + return GRPC_CALL_OK; +} + +void ServerCall::CommitBatch(const grpc_op* ops, size_t nops, void* notify_tag, + bool is_notify_tag_closure) { + BatchOpIndex op_index(ops, nops); + if (!is_notify_tag_closure) grpc_cq_begin_op(cq_, notify_tag); + auto send_initial_metadata = + op_index.OpHandler([this]( + const grpc_op& op) { + auto metadata = arena()->MakePooled(); + PrepareOutgoingInitialMetadata(op, *metadata); + CToMetadata(op.data.send_initial_metadata.metadata, + op.data.send_initial_metadata.count, metadata.get()); + if (grpc_call_trace.enabled()) { + gpr_log(GPR_INFO, "%s[call] Send initial metadata", + DebugTag().c_str()); + } + return [this, metadata = std::move(metadata)]() mutable { + return call_handler_.PushServerInitialMetadata(std::move(metadata)); + }; + }); + auto send_message = + op_index.OpHandler([this](const grpc_op& op) { + SliceBuffer send; + grpc_slice_buffer_swap( + &op.data.send_message.send_message->data.raw.slice_buffer, + send.c_slice_buffer()); + auto msg = arena()->MakePooled(std::move(send), op.flags); + return [this, msg = std::move(msg)]() mutable { + return call_handler_.PushMessage(std::move(msg)); + }; + }); + auto send_trailing_metadata = + op_index.OpHandler( + [this](const grpc_op& op) { + auto metadata = arena()->MakePooled(); + CToMetadata(op.data.send_status_from_server.trailing_metadata, + op.data.send_status_from_server.trailing_metadata_count, + metadata.get()); + metadata->Set(GrpcStatusMetadata(), + op.data.send_status_from_server.status); + if (auto* details = + op.data.send_status_from_server.status_details) { + // TODO(ctiller): this should not be a copy, but we have + // callers that allocate and pass in a slice created with + // grpc_slice_from_static_string and then delete the string + // after passing it in, which shouldn't be a supported API. + metadata->Set(GrpcMessageMetadata(), + Slice(grpc_slice_copy(*details))); + } + CHECK(metadata != nullptr); + return [this, metadata = std::move(metadata)]() mutable { + CHECK(metadata != nullptr); + return [this, metadata = std::move( + metadata)]() mutable -> Poll { + CHECK(metadata != nullptr); + call_handler_.PushServerTrailingMetadata(std::move(metadata)); + return Success{}; + }; + }; + }); + auto recv_message = + op_index.OpHandler([this](const grpc_op& op) { + return message_receiver_.MakeBatchOp(op, &call_handler_); + }); + auto primary_ops = AllOk( + TrySeq(AllOk(std::move(send_initial_metadata), + std::move(send_message)), + std::move(send_trailing_metadata)), + std::move(recv_message)); + if (auto* op = op_index.op(GRPC_OP_RECV_CLOSE_ON_SERVER)) { + auto recv_trailing_metadata = OpHandler( + [this, cancelled = op->data.recv_close_on_server.cancelled]() { + return Map(call_handler_.WasCancelled(), + [cancelled, this](bool result) -> Success { + ResetDeadline(); + *cancelled = result ? 1 : 0; + return Success{}; + }); + }); + call_handler_.SpawnInfallible( + "final-batch", InfallibleBatch(std::move(primary_ops), + std::move(recv_trailing_metadata), + is_notify_tag_closure, notify_tag, cq_)); + } else { + call_handler_.SpawnInfallible( + "batch", FallibleBatch(std::move(primary_ops), is_notify_tag_closure, + notify_tag, cq_)); + } +} + +grpc_call* MakeServerCall(CallHandler call_handler, + ClientMetadataHandle client_initial_metadata, + ServerInterface* server, grpc_completion_queue* cq, + grpc_metadata_array* publish_initial_metadata) { + PublishMetadataArray(client_initial_metadata.get(), publish_initial_metadata, + false); + // TODO(ctiller): ideally we'd put this in the arena with the CallHandler, + // but there's an ownership problem: CallHandler owns the arena, and so would + // get destroyed before the base class Call destructor runs, leading to + // UB/crash. Investigate another path. + return (new ServerCall(std::move(client_initial_metadata), + std::move(call_handler), server, cq)) + ->c_ptr(); +} + +} // namespace grpc_core diff --git a/src/core/lib/surface/server_call.h b/src/core/lib/surface/server_call.h new file mode 100644 index 00000000000..9d571d111ac --- /dev/null +++ b/src/core/lib/surface/server_call.h @@ -0,0 +1,167 @@ +// 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_LIB_SURFACE_SERVER_CALL_H +#define GRPC_SRC_CORE_LIB_SURFACE_SERVER_CALL_H + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "absl/log/check.h" +#include "absl/status/status.h" +#include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "src/core/lib/gprpp/crash.h" +#include "src/core/lib/gprpp/ref_counted.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" +#include "src/core/lib/promise/poll.h" +#include "src/core/lib/resource_quota/arena.h" +#include "src/core/lib/surface/call.h" +#include "src/core/lib/surface/call_utils.h" +#include "src/core/lib/transport/metadata.h" +#include "src/core/lib/transport/metadata_batch.h" +#include "src/core/server/server_interface.h" +#include "src/core/telemetry/stats.h" +#include "src/core/telemetry/stats_data.h" + +namespace grpc_core { + +class ServerCall final : public Call, public DualRefCounted { + public: + ServerCall(ClientMetadataHandle client_initial_metadata, + CallHandler call_handler, ServerInterface* server, + grpc_completion_queue* cq) + : Call(false, + client_initial_metadata->get(GrpcTimeoutMetadata()) + .value_or(Timestamp::InfFuture()), + call_handler.arena()->Ref(), call_handler.event_engine()), + call_handler_(std::move(call_handler)), + client_initial_metadata_stored_(std::move(client_initial_metadata)), + cq_(cq), + server_(server) { + global_stats().IncrementServerCallsCreated(); + } + + void CancelWithError(grpc_error_handle error) override { + call_handler_.SpawnInfallible( + "CancelWithError", + [self = WeakRefAsSubclass(), error = std::move(error)] { + auto status = ServerMetadataFromStatus(error); + status->Set(GrpcCallWasCancelled(), true); + self->call_handler_.PushServerTrailingMetadata(std::move(status)); + return Empty{}; + }); + } + bool is_trailers_only() const override { + Crash("is_trailers_only not implemented for server calls"); + } + absl::string_view GetServerAuthority() const override { + Crash("unimplemented"); + } + grpc_call_error StartBatch(const grpc_op* ops, size_t nops, void* notify_tag, + bool is_notify_tag_closure) override; + + void ExternalRef() override { Ref().release(); } + void ExternalUnref() override { Unref(); } + void InternalRef(const char*) override { WeakRef().release(); } + void InternalUnref(const char*) override { WeakUnref(); } + + void Orphaned() override { + // TODO(ctiller): only when we're not already finished + CancelWithError(absl::CancelledError()); + } + + void SetCompletionQueue(grpc_completion_queue*) override { + Crash("unimplemented"); + } + + grpc_compression_options compression_options() override { + return server_->compression_options(); + } + + grpc_call_stack* call_stack() override { return nullptr; } + + char* GetPeer() override { + Slice peer_slice = GetPeerString(); + if (!peer_slice.empty()) { + absl::string_view peer_string_view = peer_slice.as_string_view(); + char* peer_string = + static_cast(gpr_malloc(peer_string_view.size() + 1)); + memcpy(peer_string, peer_string_view.data(), peer_string_view.size()); + peer_string[peer_string_view.size()] = '\0'; + return peer_string; + } + return gpr_strdup("unknown"); + } + + bool Completed() final { Crash("unimplemented"); } + bool failed_before_recv_message() const final { Crash("unimplemented"); } + + uint32_t test_only_message_flags() override { + return message_receiver_.last_message_flags(); + } + + grpc_compression_algorithm incoming_compression_algorithm() override { + return message_receiver_.incoming_compression_algorithm(); + } + + void SetIncomingCompressionAlgorithm( + grpc_compression_algorithm algorithm) override { + message_receiver_.SetIncomingCompressionAlgorithm(algorithm); + } + + private: + void CommitBatch(const grpc_op* ops, size_t nops, void* notify_tag, + bool is_notify_tag_closure); + + std::string DebugTag() { return absl::StrFormat("SERVER_CALL[%p]: ", this); } + + CallHandler call_handler_; + MessageReceiver message_receiver_; + ClientMetadataHandle client_initial_metadata_stored_; + grpc_completion_queue* const cq_; + ServerInterface* const server_; +}; + +grpc_call* MakeServerCall(CallHandler call_handler, + ClientMetadataHandle client_initial_metadata, + ServerInterface* server, grpc_completion_queue* cq, + grpc_metadata_array* publish_initial_metadata); + +} // namespace grpc_core + +#endif // GRPC_SRC_CORE_LIB_SURFACE_SERVER_CALL_H diff --git a/src/core/lib/surface/wait_for_cq_end_op.cc b/src/core/lib/surface/wait_for_cq_end_op.cc deleted file mode 100644 index ed8191618e7..00000000000 --- a/src/core/lib/surface/wait_for_cq_end_op.cc +++ /dev/null @@ -1,75 +0,0 @@ -// 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/lib/surface/wait_for_cq_end_op.h" - -#include - -#include - -#include "src/core/lib/gprpp/match.h" -#include "src/core/lib/promise/trace.h" - -namespace grpc_core { -Poll WaitForCqEndOp::operator()() { - if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_INFO, "%sWaitForCqEndOp[%p] %s", - Activity::current()->DebugTag().c_str(), this, - StateString(state_).c_str()); - } - if (auto* n = absl::get_if(&state_)) { - if (n->is_closure) { - ExecCtx::Run(DEBUG_LOCATION, static_cast(n->tag), - std::move(n->error)); - return Empty{}; - } else { - auto not_started = std::move(*n); - auto& started = - state_.emplace(GetContext()->MakeOwningWaker()); - grpc_cq_end_op( - not_started.cq, not_started.tag, std::move(not_started.error), - [](void* p, grpc_cq_completion*) { - auto started = static_cast(p); - auto wakeup = std::move(started->waker); - started->done.store(true, std::memory_order_release); - wakeup.Wakeup(); - }, - &started, &started.completion); - } - } - auto& started = absl::get(state_); - if (started.done.load(std::memory_order_acquire)) { - return Empty{}; - } else { - return Pending{}; - } -} - -std::string WaitForCqEndOp::StateString(const State& state) { - return Match( - state, - [](const NotStarted& x) { - return absl::StrFormat( - "NotStarted{is_closure=%s, tag=%p, error=%s, cq=%p}", - x.is_closure ? "true" : "false", x.tag, x.error.ToString(), x.cq); - }, - [](const Started& x) { - return absl::StrFormat( - "Started{completion=%p, done=%s}", &x.completion, - x.done.load(std::memory_order_relaxed) ? "true" : "false"); - }, - [](const Invalid&) -> std::string { return "Invalid{}"; }); -} - -} // namespace grpc_core \ No newline at end of file diff --git a/src/core/lib/surface/wait_for_cq_end_op.h b/src/core/lib/surface/wait_for_cq_end_op.h deleted file mode 100644 index b76cefc657f..00000000000 --- a/src/core/lib/surface/wait_for_cq_end_op.h +++ /dev/null @@ -1,72 +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. - -#ifndef GRPC_SRC_CORE_LIB_SURFACE_WAIT_FOR_CQ_END_OP_H -#define GRPC_SRC_CORE_LIB_SURFACE_WAIT_FOR_CQ_END_OP_H - -#include - -#include "src/core/lib/iomgr/exec_ctx.h" -#include "src/core/lib/promise/activity.h" -#include "src/core/lib/surface/completion_queue.h" - -namespace grpc_core { - -// Defines a promise that calls grpc_cq_end_op() (on first poll) and then waits -// for the callback supplied to grpc_cq_end_op() to be called, before resolving -// to Empty{} -class WaitForCqEndOp { - public: - WaitForCqEndOp(bool is_closure, void* tag, grpc_error_handle error, - grpc_completion_queue* cq) - : state_{NotStarted{is_closure, tag, std::move(error), cq}} {} - - Poll operator()(); - - WaitForCqEndOp(const WaitForCqEndOp&) = delete; - WaitForCqEndOp& operator=(const WaitForCqEndOp&) = delete; - WaitForCqEndOp(WaitForCqEndOp&& other) noexcept - : state_(std::move(absl::get(other.state_))) { - other.state_.emplace(); - } - WaitForCqEndOp& operator=(WaitForCqEndOp&& other) noexcept { - state_ = std::move(absl::get(other.state_)); - other.state_.emplace(); - return *this; - } - - private: - struct NotStarted { - bool is_closure; - void* tag; - grpc_error_handle error; - grpc_completion_queue* cq; - }; - struct Started { - explicit Started(Waker waker) : waker(std::move(waker)) {} - Waker waker; - grpc_cq_completion completion; - std::atomic done{false}; - }; - struct Invalid {}; - using State = absl::variant; - - static std::string StateString(const State& state); - - State state_{Invalid{}}; -}; - -} // namespace grpc_core - -#endif // GRPC_SRC_CORE_LIB_SURFACE_WAIT_FOR_CQ_END_OP_H diff --git a/src/core/lib/transport/batch_builder.cc b/src/core/lib/transport/batch_builder.cc deleted file mode 100644 index 85dadf55d85..00000000000 --- a/src/core/lib/transport/batch_builder.cc +++ /dev/null @@ -1,171 +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. - -#include "src/core/lib/transport/batch_builder.h" - -#include - -#include "absl/log/check.h" - -#include - -#include "src/core/lib/promise/poll.h" -#include "src/core/lib/slice/slice.h" -#include "src/core/lib/surface/call_trace.h" -#include "src/core/lib/transport/metadata_batch.h" -#include "src/core/lib/transport/transport.h" - -namespace grpc_core { - -BatchBuilder::BatchBuilder(grpc_transport_stream_op_batch_payload* payload) - : payload_(payload) {} - -void BatchBuilder::PendingCompletion::CompletionCallback( - void* self, grpc_error_handle error) { - auto* pc = static_cast(self); - auto* party = pc->batch->party.get(); - if (grpc_call_trace.enabled()) { - gpr_log(GPR_DEBUG, "%sFinish batch-component %s: status=%s", - pc->batch->DebugPrefix(party).c_str(), - std::string(pc->name()).c_str(), error.ToString().c_str()); - } - party->Spawn( - "batch-completion", - [pc, error = std::move(error)]() mutable { - RefCountedPtr batch = std::exchange(pc->batch, nullptr); - pc->done_latch.Set(std::move(error)); - return Empty{}; - }, - [](Empty) {}); -} - -BatchBuilder::PendingCompletion::PendingCompletion(RefCountedPtr batch) - : batch(std::move(batch)) { - GRPC_CLOSURE_INIT(&on_done_closure, CompletionCallback, this, nullptr); -} - -BatchBuilder::Batch::Batch(grpc_transport_stream_op_batch_payload* payload, - grpc_stream_refcount* stream_refcount) - : party(GetContext()->Ref()), stream_refcount(stream_refcount) { - batch.payload = payload; - batch.is_traced = GetContext()->traced(); -#ifndef NDEBUG - grpc_stream_ref(stream_refcount, "pending-batch"); -#else - grpc_stream_ref(stream_refcount); -#endif -} - -BatchBuilder::Batch::~Batch() { - if (grpc_call_trace.enabled()) { - gpr_log(GPR_DEBUG, "%s[connected] [batch %p] Destroy", - GetContext()->DebugTag().c_str(), this); - } - delete pending_receive_message; - delete pending_receive_initial_metadata; - delete pending_receive_trailing_metadata; - delete pending_sends; - if (batch.cancel_stream) { - delete batch.payload; - } -#ifndef NDEBUG - grpc_stream_unref(stream_refcount, "pending-batch"); -#else - grpc_stream_unref(stream_refcount); -#endif -} - -BatchBuilder::Batch* BatchBuilder::GetBatch(Target target) { - if (target_.has_value() && - (target_->stream != target.stream || - target.transport->filter_stack_transport() - ->HackyDisableStreamOpBatchCoalescingInConnectedChannel())) { - FlushBatch(); - } - if (!target_.has_value()) { - target_ = target; - batch_ = GetContext()->NewPooled(payload_, - target_->stream_refcount); - } - CHECK_NE(batch_, nullptr); - return batch_; -} - -void BatchBuilder::FlushBatch() { - CHECK_NE(batch_, nullptr); - CHECK(target_.has_value()); - if (grpc_call_trace.enabled()) { - gpr_log( - GPR_DEBUG, "%sPerform transport stream op batch: %p %s", - batch_->DebugPrefix().c_str(), &batch_->batch, - grpc_transport_stream_op_batch_string(&batch_->batch, false).c_str()); - } - std::exchange(batch_, nullptr)->PerformWith(*target_); - target_.reset(); -} - -void BatchBuilder::Batch::PerformWith(Target target) { - target.transport->filter_stack_transport()->PerformStreamOp(target.stream, - &batch); -} - -ServerMetadataHandle BatchBuilder::CompleteSendServerTrailingMetadata( - Batch* batch, ServerMetadataHandle sent_metadata, absl::Status send_result, - bool actually_sent) { - if (!send_result.ok()) { - if (grpc_call_trace.enabled()) { - gpr_log(GPR_DEBUG, - "%sSend metadata failed with error: %s, fabricating trailing " - "metadata", - batch->DebugPrefix().c_str(), send_result.ToString().c_str()); - } - sent_metadata->Clear(); - sent_metadata->Set(GrpcStatusMetadata(), - static_cast(send_result.code())); - sent_metadata->Set(GrpcMessageMetadata(), - Slice::FromCopiedString(send_result.message())); - sent_metadata->Set(GrpcCallWasCancelled(), true); - } - if (!sent_metadata->get(GrpcCallWasCancelled()).has_value()) { - if (grpc_call_trace.enabled()) { - gpr_log( - GPR_DEBUG, - "%sTagging trailing metadata with cancellation status from " - "transport: %s", - batch->DebugPrefix().c_str(), - actually_sent ? "sent => not-cancelled" : "not-sent => cancelled"); - } - sent_metadata->Set(GrpcCallWasCancelled(), !actually_sent); - } - return sent_metadata; -} - -BatchBuilder::Batch* BatchBuilder::MakeCancel( - grpc_stream_refcount* stream_refcount, absl::Status status) { - auto* arena = GetContext(); - auto* payload = arena->NewPooled(); - auto* batch = arena->NewPooled(payload, stream_refcount); - batch->batch.cancel_stream = true; - payload->cancel_stream.cancel_error = std::move(status); - return batch; -} - -void BatchBuilder::Cancel(Target target, absl::Status status) { - auto* batch = MakeCancel(target.stream_refcount, std::move(status)); - batch->batch.on_complete = - NewClosure([batch](absl::Status) { delete batch; }); - batch->PerformWith(target); -} - -} // namespace grpc_core diff --git a/src/core/lib/transport/batch_builder.h b/src/core/lib/transport/batch_builder.h deleted file mode 100644 index 68a65ba25be..00000000000 --- a/src/core/lib/transport/batch_builder.h +++ /dev/null @@ -1,474 +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. - -#ifndef GRPC_SRC_CORE_LIB_TRANSPORT_BATCH_BUILDER_H -#define GRPC_SRC_CORE_LIB_TRANSPORT_BATCH_BUILDER_H - -#include - -#include -#include -#include - -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/str_format.h" -#include "absl/strings/string_view.h" -#include "absl/types/optional.h" - -#include -#include -#include - -#include "src/core/lib/channel/channel_stack.h" -#include "src/core/lib/debug/trace.h" -#include "src/core/lib/gprpp/ref_counted_ptr.h" -#include "src/core/lib/gprpp/status_helper.h" -#include "src/core/lib/iomgr/closure.h" -#include "src/core/lib/iomgr/error.h" -#include "src/core/lib/promise/activity.h" -#include "src/core/lib/promise/context.h" -#include "src/core/lib/promise/latch.h" -#include "src/core/lib/promise/map.h" -#include "src/core/lib/promise/party.h" -#include "src/core/lib/resource_quota/arena.h" -#include "src/core/lib/slice/slice_buffer.h" -#include "src/core/lib/surface/call.h" -#include "src/core/lib/surface/call_trace.h" -#include "src/core/lib/transport/metadata_batch.h" -#include "src/core/lib/transport/transport.h" - -namespace grpc_core { - -// Build up a transport stream op batch for a stream for a promise based -// connected channel. -// Offered as a context from Call, so that it can collect ALL the updates during -// a single party round, and then push them down to the transport as a single -// transaction. -class BatchBuilder { - public: - explicit BatchBuilder(grpc_transport_stream_op_batch_payload* payload); - ~BatchBuilder() { - if (batch_ != nullptr) FlushBatch(); - } - - struct Target { - Transport* transport; - grpc_stream* stream; - grpc_stream_refcount* stream_refcount; - }; - - BatchBuilder(const BatchBuilder&) = delete; - BatchBuilder& operator=(const BatchBuilder&) = delete; - - // Returns a promise that will resolve to a Status when the send is completed. - auto SendMessage(Target target, MessageHandle message); - - // Returns a promise that will resolve to a Status when the send is completed. - auto SendClientInitialMetadata(Target target, ClientMetadataHandle metadata); - - // Returns a promise that will resolve to a Status when the send is completed. - auto SendClientTrailingMetadata(Target target); - - // Returns a promise that will resolve to a Status when the send is completed. - auto SendServerInitialMetadata(Target target, ServerMetadataHandle metadata); - - // Returns a promise that will resolve to a ServerMetadataHandle when the send - // is completed. - // - // If convert_to_cancellation is true, then the status will be converted to a - // cancellation batch instead of a trailing metadata op in a coalesced batch. - // - // This quirk exists as in the filter based stack upon which our transports - // were written if a trailing metadata op were sent it always needed to be - // paired with an initial op batch, and the transports would wait for the - // initial metadata batch to arrive (in case of reordering up the stack). - auto SendServerTrailingMetadata(Target target, ServerMetadataHandle metadata, - bool convert_to_cancellation); - - // Returns a promise that will resolve to a StatusOr> - // when a message is received. - // Error => non-ok status - // End of stream => Ok, nullopt (no message) - // Message => Ok, message - auto ReceiveMessage(Target target); - - // Returns a promise that will resolve to a StatusOr - // when the receive is complete. - auto ReceiveClientInitialMetadata(Target target); - - // Returns a promise that will resolve to a StatusOr - // when the receive is complete. - auto ReceiveClientTrailingMetadata(Target target); - - // Returns a promise that will resolve to a StatusOr - // when the receive is complete. - auto ReceiveServerInitialMetadata(Target target); - - // Returns a promise that will resolve to a StatusOr - // when the receive is complete. - auto ReceiveServerTrailingMetadata(Target target); - - // Send a cancellation: does not occupy the same payload, nor does it - // coalesce with other ops. - void Cancel(Target target, absl::Status status); - - private: - struct Batch; - - // Base pending operation - struct PendingCompletion { - explicit PendingCompletion(RefCountedPtr batch); - virtual absl::string_view name() const = 0; - static void CompletionCallback(void* self, grpc_error_handle error); - grpc_closure on_done_closure; - Latch done_latch; - RefCountedPtr batch; - - protected: - ~PendingCompletion() = default; - }; - - // A pending receive message. - struct PendingReceiveMessage final : public PendingCompletion { - using PendingCompletion::PendingCompletion; - - absl::string_view name() const override { return "receive_message"; } - - MessageHandle IntoMessageHandle() { - return Arena::MakePooled(std::move(*payload), flags); - } - - absl::optional payload; - uint32_t flags; - bool call_failed_before_recv_message = false; - }; - - // A pending receive metadata. - struct PendingReceiveMetadata : public PendingCompletion { - using PendingCompletion::PendingCompletion; - - Arena::PoolPtr metadata = - Arena::MakePooled(); - - protected: - ~PendingReceiveMetadata() = default; - }; - - struct PendingReceiveInitialMetadata final : public PendingReceiveMetadata { - using PendingReceiveMetadata::PendingReceiveMetadata; - absl::string_view name() const override { - return "receive_initial_metadata"; - } - }; - - struct PendingReceiveTrailingMetadata final : public PendingReceiveMetadata { - using PendingReceiveMetadata::PendingReceiveMetadata; - absl::string_view name() const override { - return "receive_trailing_metadata"; - } - }; - - // Pending sends in a batch - struct PendingSends final : public PendingCompletion { - using PendingCompletion::PendingCompletion; - - absl::string_view name() const override { return "sends"; } - - MessageHandle send_message; - Arena::PoolPtr send_initial_metadata; - Arena::PoolPtr send_trailing_metadata; - bool trailing_metadata_sent = false; - }; - - // One outstanding batch. - struct Batch final { - Batch(grpc_transport_stream_op_batch_payload* payload, - grpc_stream_refcount* stream_refcount); - ~Batch(); - Batch(const Batch&) = delete; - Batch& operator=(const Batch&) = delete; - std::string DebugPrefix(Activity* activity = GetContext()) const { - return absl::StrFormat("%s[connected] [batch %p] ", activity->DebugTag(), - this); - } - - void IncrementRefCount() { ++refs; } - void Unref() { - if (--refs == 0) delete this; - } - RefCountedPtr Ref() { - IncrementRefCount(); - return RefCountedPtr(this); - } - // Get an initialized pending completion. - // There are four pending completions potentially contained within a batch. - // They can be rather large so we don't create all of them always. Instead, - // we dynamically create them on the arena as needed. - // This method either returns the existing completion in a batch if that - // completion has already been initialized, or it creates a new completion - // and returns that. - template - T* GetInitializedCompletion(T*(Batch::*field)) { - if (this->*field != nullptr) return this->*field; - this->*field = new T(Ref()); - if (grpc_call_trace.enabled()) { - gpr_log(GPR_DEBUG, "%sAdd batch closure for %s @ %s", - DebugPrefix().c_str(), - std::string((this->*field)->name()).c_str(), - (this->*field)->on_done_closure.DebugString().c_str()); - } - return this->*field; - } - // grpc_transport_perform_stream_op on target.stream - void PerformWith(Target target); - // Take a promise, and return a promise that holds a ref on this batch until - // the promise completes or is cancelled. - template - auto RefUntil(P promise) { - return [self = Ref(), promise = std::move(promise)]() mutable { - return promise(); - }; - } - - grpc_transport_stream_op_batch batch; - PendingReceiveMessage* pending_receive_message = nullptr; - PendingReceiveInitialMetadata* pending_receive_initial_metadata = nullptr; - PendingReceiveTrailingMetadata* pending_receive_trailing_metadata = nullptr; - PendingSends* pending_sends = nullptr; - const RefCountedPtr party; - grpc_stream_refcount* const stream_refcount; - uint8_t refs = 0; - }; - - // Get a batch for the given target. - // Currently: if the current batch is for this target, return it - otherwise - // flush the batch and start a new one (and return that). - // This function may change in the future to allow multiple batches to be - // building at once (if that turns out to be useful for hedging). - Batch* GetBatch(Target target); - // Flush the current batch down to the transport. - void FlushBatch(); - // Create a cancel batch with its own payload. - Batch* MakeCancel(grpc_stream_refcount* stream_refcount, absl::Status status); - - // Note: we don't distinguish between client and server metadata here. - // At the time of writing they're both the same thing - and it's unclear - // whether we'll get to separate them prior to batches going away or not. - // So for now we claim YAGNI and just do the simplest possible implementation. - auto SendInitialMetadata(Target target, - Arena::PoolPtr md); - auto ReceiveInitialMetadata(Target target); - auto ReceiveTrailingMetadata(Target target); - - // Combine send status and server metadata into a final status to report back - // to the containing call. - static ServerMetadataHandle CompleteSendServerTrailingMetadata( - Batch* batch, ServerMetadataHandle sent_metadata, - absl::Status send_result, bool actually_sent); - - grpc_transport_stream_op_batch_payload* const payload_; - absl::optional target_; - Batch* batch_ = nullptr; -}; - -inline auto BatchBuilder::SendMessage(Target target, MessageHandle message) { - auto* batch = GetBatch(target); - if (grpc_call_trace.enabled()) { - gpr_log(GPR_DEBUG, "%sQueue send message: %s", batch->DebugPrefix().c_str(), - message->DebugString().c_str()); - } - auto* pc = batch->GetInitializedCompletion(&Batch::pending_sends); - batch->batch.on_complete = &pc->on_done_closure; - batch->batch.send_message = true; - payload_->send_message.send_message = message->payload(); - payload_->send_message.flags = message->flags(); - pc->send_message = std::move(message); - return batch->RefUntil(pc->done_latch.WaitAndCopy()); -} - -inline auto BatchBuilder::SendInitialMetadata( - Target target, Arena::PoolPtr md) { - auto* batch = GetBatch(target); - if (grpc_call_trace.enabled()) { - gpr_log(GPR_DEBUG, "%sQueue send initial metadata: %s", - batch->DebugPrefix().c_str(), md->DebugString().c_str()); - } - auto* pc = batch->GetInitializedCompletion(&Batch::pending_sends); - batch->batch.on_complete = &pc->on_done_closure; - batch->batch.send_initial_metadata = true; - payload_->send_initial_metadata.send_initial_metadata = md.get(); - pc->send_initial_metadata = std::move(md); - return batch->RefUntil(pc->done_latch.WaitAndCopy()); -} - -inline auto BatchBuilder::SendClientInitialMetadata( - Target target, ClientMetadataHandle metadata) { - return SendInitialMetadata(target, std::move(metadata)); -} - -inline auto BatchBuilder::SendClientTrailingMetadata(Target target) { - auto* batch = GetBatch(target); - if (grpc_call_trace.enabled()) { - gpr_log(GPR_DEBUG, "%sQueue send trailing metadata", - batch->DebugPrefix().c_str()); - } - auto* pc = batch->GetInitializedCompletion(&Batch::pending_sends); - batch->batch.on_complete = &pc->on_done_closure; - batch->batch.send_trailing_metadata = true; - auto metadata = Arena::MakePooled(); - payload_->send_trailing_metadata.send_trailing_metadata = metadata.get(); - payload_->send_trailing_metadata.sent = nullptr; - pc->send_trailing_metadata = std::move(metadata); - return batch->RefUntil(pc->done_latch.WaitAndCopy()); -} - -inline auto BatchBuilder::SendServerInitialMetadata( - Target target, ServerMetadataHandle metadata) { - return SendInitialMetadata(target, std::move(metadata)); -} - -inline auto BatchBuilder::SendServerTrailingMetadata( - Target target, ServerMetadataHandle metadata, - bool convert_to_cancellation) { - Batch* batch; - PendingSends* pc; - if (convert_to_cancellation) { - const auto status_code = - metadata->get(GrpcStatusMetadata()).value_or(GRPC_STATUS_UNKNOWN); - auto status = grpc_error_set_int( - absl::Status(static_cast(status_code), - metadata->GetOrCreatePointer(GrpcMessageMetadata()) - ->as_string_view()), - StatusIntProperty::kRpcStatus, status_code); - batch = MakeCancel(target.stream_refcount, std::move(status)); - pc = batch->GetInitializedCompletion(&Batch::pending_sends); - } else { - batch = GetBatch(target); - pc = batch->GetInitializedCompletion(&Batch::pending_sends); - batch->batch.send_trailing_metadata = true; - payload_->send_trailing_metadata.send_trailing_metadata = metadata.get(); - payload_->send_trailing_metadata.sent = &pc->trailing_metadata_sent; - } - if (grpc_call_trace.enabled()) { - gpr_log(GPR_DEBUG, "%s%s: %s", batch->DebugPrefix().c_str(), - convert_to_cancellation ? "Send trailing metadata as cancellation" - : "Queue send trailing metadata", - metadata->DebugString().c_str()); - } - batch->batch.on_complete = &pc->on_done_closure; - pc->send_trailing_metadata = std::move(metadata); - auto promise = Map(pc->done_latch.WaitAndCopy(), - [pc, batch = batch->Ref()](absl::Status status) { - return CompleteSendServerTrailingMetadata( - batch.get(), std::move(pc->send_trailing_metadata), - std::move(status), pc->trailing_metadata_sent); - }); - if (convert_to_cancellation) { - batch->PerformWith(target); - } - return promise; -} - -inline auto BatchBuilder::ReceiveMessage(Target target) { - auto* batch = GetBatch(target); - if (grpc_call_trace.enabled()) { - gpr_log(GPR_DEBUG, "%sQueue receive message", batch->DebugPrefix().c_str()); - } - auto* pc = batch->GetInitializedCompletion(&Batch::pending_receive_message); - batch->batch.recv_message = true; - payload_->recv_message.recv_message_ready = &pc->on_done_closure; - payload_->recv_message.recv_message = &pc->payload; - payload_->recv_message.flags = &pc->flags; - payload_->recv_message.call_failed_before_recv_message = - &pc->call_failed_before_recv_message; - return batch->RefUntil( - Map(pc->done_latch.Wait(), - [pc](absl::Status status) - -> absl::StatusOr> { - if (!status.ok()) return status; - if (!pc->payload.has_value()) { - if (pc->call_failed_before_recv_message) { - return absl::CancelledError(); - } - return absl::nullopt; - } - return pc->IntoMessageHandle(); - })); -} - -inline auto BatchBuilder::ReceiveInitialMetadata(Target target) { - auto* batch = GetBatch(target); - if (grpc_call_trace.enabled()) { - gpr_log(GPR_DEBUG, "%sQueue receive initial metadata", - batch->DebugPrefix().c_str()); - } - auto* pc = - batch->GetInitializedCompletion(&Batch::pending_receive_initial_metadata); - batch->batch.recv_initial_metadata = true; - payload_->recv_initial_metadata.recv_initial_metadata_ready = - &pc->on_done_closure; - payload_->recv_initial_metadata.recv_initial_metadata = pc->metadata.get(); - return batch->RefUntil( - Map(pc->done_latch.Wait(), - [pc](absl::Status status) -> absl::StatusOr { - if (!status.ok()) return status; - return std::move(pc->metadata); - })); -} - -inline auto BatchBuilder::ReceiveClientInitialMetadata(Target target) { - return ReceiveInitialMetadata(target); -} - -inline auto BatchBuilder::ReceiveServerInitialMetadata(Target target) { - return ReceiveInitialMetadata(target); -} - -inline auto BatchBuilder::ReceiveTrailingMetadata(Target target) { - auto* batch = GetBatch(target); - if (grpc_call_trace.enabled()) { - gpr_log(GPR_DEBUG, "%sQueue receive trailing metadata", - batch->DebugPrefix().c_str()); - } - auto* pc = batch->GetInitializedCompletion( - &Batch::pending_receive_trailing_metadata); - batch->batch.recv_trailing_metadata = true; - payload_->recv_trailing_metadata.recv_trailing_metadata_ready = - &pc->on_done_closure; - payload_->recv_trailing_metadata.recv_trailing_metadata = pc->metadata.get(); - payload_->recv_trailing_metadata.collect_stats = - &GetContext()->call_stats()->transport_stream_stats; - return batch->RefUntil( - Map(pc->done_latch.Wait(), - [pc](absl::Status status) -> absl::StatusOr { - if (!status.ok()) return status; - return std::move(pc->metadata); - })); -} - -inline auto BatchBuilder::ReceiveClientTrailingMetadata(Target target) { - return ReceiveTrailingMetadata(target); -} - -inline auto BatchBuilder::ReceiveServerTrailingMetadata(Target target) { - return ReceiveTrailingMetadata(target); -} - -template <> -struct ContextType {}; - -} // namespace grpc_core - -#endif // GRPC_SRC_CORE_LIB_TRANSPORT_BATCH_BUILDER_H diff --git a/src/core/lib/transport/call_filters.cc b/src/core/lib/transport/call_filters.cc index c4b18721c86..64b8c418d33 100644 --- a/src/core/lib/transport/call_filters.cc +++ b/src/core/lib/transport/call_filters.cc @@ -230,8 +230,8 @@ void CallFilters::CancelDueToFailedPipeOperation(SourceLocation but_where) { "Cancelling due to failed pipe operation: %s", DebugString().c_str()); } - server_trailing_metadata_ = - ServerMetadataFromStatus(absl::CancelledError("Failed pipe operation")); + PushServerTrailingMetadata( + ServerMetadataFromStatus(absl::CancelledError("Failed pipe operation"))); server_trailing_metadata_waiter_.Wake(); } diff --git a/src/core/lib/transport/call_spine.h b/src/core/lib/transport/call_spine.h index 327fc5da6ae..6bfcd979292 100644 --- a/src/core/lib/transport/call_spine.h +++ b/src/core/lib/transport/call_spine.h @@ -40,13 +40,23 @@ namespace grpc_core { // The common middle part of a call - a reference is held by each of // CallInitiator and CallHandler - which provide interfaces that are appropriate // for each side of a call. -// The spine will ultimately host the pipes, filters, and context for one part -// of a call: ie top-half client channel, sub channel call, server call. -// TODO(ctiller): eventually drop this when we don't need to reference into -// legacy promise calls anymore -class CallSpineInterface { +// Hosts context, call filters, and the arena. +class CallSpine final : public Party { public: - virtual ~CallSpineInterface() = default; + static RefCountedPtr Create( + ClientMetadataHandle client_initial_metadata, + grpc_event_engine::experimental::EventEngine* event_engine, + RefCountedPtr arena) { + Arena* arena_ptr = arena.get(); + return RefCountedPtr(arena_ptr->New( + std::move(client_initial_metadata), event_engine, std::move(arena))); + } + + ~CallSpine() override {} + + CallFilters& call_filters() { return call_filters_; } + Arena* arena() { return arena_.get(); } + // Add a callback to be called when server trailing metadata is received. void OnDone(absl::AnyInvocable fn) { if (on_done_ == nullptr) { @@ -61,38 +71,70 @@ class CallSpineInterface { void CallOnDone() { if (on_done_ != nullptr) std::exchange(on_done_, nullptr)(); } - virtual Party& party() = 0; - virtual Arena* arena() = 0; - virtual void IncrementRefCount() = 0; - virtual void Unref() = 0; - - virtual Promise>> - PullServerInitialMetadata() = 0; - virtual Promise PullServerTrailingMetadata() = 0; - virtual Promise PushClientToServerMessage( - MessageHandle message) = 0; - virtual Promise>> - PullClientToServerMessage() = 0; - virtual Promise PushServerToClientMessage( - MessageHandle message) = 0; - virtual Promise>> - PullServerToClientMessage() = 0; - virtual void PushServerTrailingMetadata(ServerMetadataHandle md) = 0; - virtual void FinishSends() = 0; - virtual Promise> - PullClientInitialMetadata() = 0; - virtual Promise PushServerInitialMetadata( - absl::optional md) = 0; - virtual Promise WasCancelled() = 0; - virtual ClientMetadata& UnprocessedClientInitialMetadata() = 0; - virtual void V2HackToStartCallWithoutACallFilterStack() = 0; + + auto PullServerInitialMetadata() { + return call_filters().PullServerInitialMetadata(); + } + + auto PullServerTrailingMetadata() { + return call_filters().PullServerTrailingMetadata(); + } + + auto PushClientToServerMessage(MessageHandle message) { + return call_filters().PushClientToServerMessage(std::move(message)); + } + + auto PullClientToServerMessage() { + return call_filters().PullClientToServerMessage(); + } + + auto PushServerToClientMessage(MessageHandle message) { + return call_filters().PushServerToClientMessage(std::move(message)); + } + + auto PullServerToClientMessage() { + return call_filters().PullServerToClientMessage(); + } + + void PushServerTrailingMetadata(ServerMetadataHandle md) { + call_filters().PushServerTrailingMetadata(std::move(md)); + } + + void FinishSends() { call_filters().FinishClientToServerSends(); } + + auto PullClientInitialMetadata() { + return call_filters().PullClientInitialMetadata(); + } + + auto PushServerInitialMetadata(absl::optional md) { + bool has_md = md.has_value(); + return If( + has_md, + [this, md = std::move(md)]() mutable { + return call_filters().PushServerInitialMetadata(std::move(*md)); + }, + [this]() { + call_filters().NoServerInitialMetadata(); + return Immediate(Success{}); + }); + } + + auto WasCancelled() { return call_filters().WasCancelled(); } + + ClientMetadata& UnprocessedClientInitialMetadata() { + return *call_filters().unprocessed_client_initial_metadata(); + } + + grpc_event_engine::experimental::EventEngine* event_engine() const override { + return event_engine_; + } // Wrap a promise so that if it returns failure it automatically cancels // the rest of the call. // The resulting (returned) promise will resolve to Empty. template auto CancelIfFails(Promise promise) { - DCHECK(GetContext() == &party()); + DCHECK(GetContext() == this); using P = promise_detail::PromiseLike; using ResultType = typename P::Result; return Map(std::move(promise), [this](ResultType r) { @@ -107,7 +149,7 @@ class CallSpineInterface { // that detail. template void SpawnInfallible(absl::string_view name, PromiseFactory promise_factory) { - party().Spawn(name, std::move(promise_factory), [](Empty) {}); + Spawn(name, std::move(promise_factory), [](Empty) {}); } // Spawn a promise that returns some status-like type; if the status @@ -123,18 +165,17 @@ class CallSpineInterface { std::is_same()))>::value, "SpawnGuarded promise must return a status-like object"); - party().Spawn( - name, std::move(promise_factory), [this, whence](ResultType r) { - if (!IsStatusOk(r)) { - if (grpc_trace_promise_primitives.enabled()) { - gpr_log(GPR_INFO, "SpawnGuarded sees failure: %s (source: %s:%d)", - r.ToString().c_str(), whence.file(), whence.line()); - } - auto status = StatusCast(std::move(r)); - status->Set(GrpcCallWasCancelled(), true); - PushServerTrailingMetadata(std::move(status)); - } - }); + Spawn(name, std::move(promise_factory), [this, whence](ResultType r) { + if (!IsStatusOk(r)) { + if (grpc_trace_promise_primitives.enabled()) { + gpr_log(GPR_INFO, "SpawnGuarded sees failure: %s (source: %s:%d)", + r.ToString().c_str(), whence.file(), whence.line()); + } + auto status = StatusCast(std::move(r)); + status->Set(GrpcCallWasCancelled(), true); + PushServerTrailingMetadata(std::move(status)); + } + }); } // Wrap a promise so that if the call completes that promise is cancelled. @@ -154,217 +195,6 @@ class CallSpineInterface { }); } - private: - absl::AnyInvocable on_done_{nullptr}; -}; - -// Implementation of CallSpine atop the v2 Pipe based arrangement. -// This implementation will go away in favor of an implementation atop -// CallFilters by the time v3 lands. -class PipeBasedCallSpine : public CallSpineInterface { - public: - virtual Pipe& client_initial_metadata() = 0; - virtual Pipe& server_initial_metadata() = 0; - virtual Pipe& client_to_server_messages() = 0; - virtual Pipe& server_to_client_messages() = 0; - virtual Latch& cancel_latch() = 0; - virtual Latch& was_cancelled_latch() = 0; - - Promise>> - PullServerInitialMetadata() final { - DCHECK(GetContext() == &party()); - return Map(server_initial_metadata().receiver.Next(), - [](NextResult md) - -> ValueOrFailure> { - if (!md.has_value()) { - if (md.cancelled()) return Failure{}; - return absl::optional(); - } - return absl::optional(std::move(*md)); - }); - } - - Promise PullServerTrailingMetadata() final { - DCHECK(GetContext() == &party()); - return cancel_latch().Wait(); - } - - Promise>> - PullServerToClientMessage() final { - DCHECK(GetContext() == &party()); - return Map(server_to_client_messages().receiver.Next(), MapNextMessage); - } - - Promise PushClientToServerMessage(MessageHandle message) final { - DCHECK(GetContext() == &party()); - return Map(client_to_server_messages().sender.Push(std::move(message)), - [](bool r) { return StatusFlag(r); }); - } - - Promise>> - PullClientToServerMessage() final { - DCHECK(GetContext() == &party()); - return Map(client_to_server_messages().receiver.Next(), MapNextMessage); - } - - Promise PushServerToClientMessage(MessageHandle message) final { - DCHECK(GetContext() == &party()); - return Map(server_to_client_messages().sender.Push(std::move(message)), - [](bool r) { return StatusFlag(r); }); - } - - void FinishSends() final { - DCHECK(GetContext() == &party()); - client_to_server_messages().sender.Close(); - } - - void PushServerTrailingMetadata(ServerMetadataHandle metadata) final { - DCHECK(GetContext() == &party()); - auto& c = cancel_latch(); - if (c.is_set()) return; - const bool was_cancelled = - metadata->get(GrpcCallWasCancelled()).value_or(false); - c.Set(std::move(metadata)); - CallOnDone(); - was_cancelled_latch().Set(was_cancelled); - client_initial_metadata().sender.CloseWithError(); - server_initial_metadata().sender.Close(); - client_to_server_messages().sender.CloseWithError(); - server_to_client_messages().sender.Close(); - } - - Promise WasCancelled() final { - DCHECK(GetContext() == &party()); - return was_cancelled_latch().Wait(); - } - - Promise> PullClientInitialMetadata() - final { - DCHECK(GetContext() == &party()); - return Map(client_initial_metadata().receiver.Next(), - [](NextResult md) - -> ValueOrFailure { - if (!md.has_value()) return Failure{}; - return std::move(*md); - }); - } - - Promise PushServerInitialMetadata( - absl::optional md) final { - DCHECK(GetContext() == &party()); - return If( - md.has_value(), - [&md, this]() { - return Map(server_initial_metadata().sender.Push(std::move(*md)), - [](bool ok) { return StatusFlag(ok); }); - }, - [this]() { - server_initial_metadata().sender.Close(); - return []() -> StatusFlag { return Success{}; }; - }); - } - - private: - static ValueOrFailure> MapNextMessage( - NextResult r) { - if (!r.has_value()) { - if (r.cancelled()) return Failure{}; - return absl::optional(); - } - return absl::optional(std::move(*r)); - } -}; - -class CallSpine final : public CallSpineInterface, public Party { - public: - static RefCountedPtr Create( - ClientMetadataHandle client_initial_metadata, - grpc_event_engine::experimental::EventEngine* event_engine, - RefCountedPtr arena) { - auto* arena_ptr = arena.get(); - return RefCountedPtr(arena_ptr->New( - std::move(client_initial_metadata), event_engine, std::move(arena))); - } - - ~CallSpine() override {} - - CallFilters& call_filters() { return call_filters_; } - - Party& party() override { return *this; } - - Arena* arena() override { return arena_.get(); } - - void IncrementRefCount() override { Party::IncrementRefCount(); } - - void Unref() override { Party::Unref(); } - - Promise>> - PullServerInitialMetadata() override { - return call_filters().PullServerInitialMetadata(); - } - - Promise PullServerTrailingMetadata() override { - return call_filters().PullServerTrailingMetadata(); - } - - Promise PushClientToServerMessage( - MessageHandle message) override { - return call_filters().PushClientToServerMessage(std::move(message)); - } - - Promise>> - PullClientToServerMessage() override { - return call_filters().PullClientToServerMessage(); - } - - Promise PushServerToClientMessage( - MessageHandle message) override { - return call_filters().PushServerToClientMessage(std::move(message)); - } - - Promise>> - PullServerToClientMessage() override { - return call_filters().PullServerToClientMessage(); - } - - void PushServerTrailingMetadata(ServerMetadataHandle md) override { - call_filters().PushServerTrailingMetadata(std::move(md)); - } - - void FinishSends() override { call_filters().FinishClientToServerSends(); } - - Promise> PullClientInitialMetadata() - override { - return call_filters().PullClientInitialMetadata(); - } - - Promise PushServerInitialMetadata( - absl::optional md) override { - if (md.has_value()) { - return call_filters().PushServerInitialMetadata(std::move(*md)); - } else { - call_filters().NoServerInitialMetadata(); - return Immediate(Success{}); - } - } - - Promise WasCancelled() override { - return call_filters().WasCancelled(); - } - - ClientMetadata& UnprocessedClientInitialMetadata() override { - return *call_filters().unprocessed_client_initial_metadata(); - } - - grpc_event_engine::experimental::EventEngine* event_engine() const override { - return event_engine_; - } - - void V2HackToStartCallWithoutACallFilterStack() override { - CallFilters::StackBuilder empty_stack_builder; - call_filters().SetStack(empty_stack_builder.Build()); - } - private: friend class Arena; CallSpine(ClientMetadataHandle client_initial_metadata, @@ -407,11 +237,13 @@ class CallSpine final : public CallSpineInterface, public Party { CallFilters call_filters_; // Event engine associated with this call grpc_event_engine::experimental::EventEngine* const event_engine_; + absl::AnyInvocable on_done_{nullptr}; }; class CallInitiator { public: - explicit CallInitiator(RefCountedPtr spine) + CallInitiator() = default; + explicit CallInitiator(RefCountedPtr spine) : spine_(std::move(spine)) {} template @@ -435,8 +267,9 @@ class CallInitiator { return spine_->PullServerTrailingMetadata(); } - void Cancel() { - auto status = ServerMetadataFromStatus(absl::CancelledError()); + void Cancel(absl::Status error = absl::CancelledError()) { + CHECK(!error.ok()); + auto status = ServerMetadataFromStatus(error); status->Set(GrpcCallWasCancelled(), true); spine_->PushServerTrailingMetadata(std::move(status)); } @@ -461,18 +294,22 @@ class CallInitiator { template auto SpawnWaitable(absl::string_view name, PromiseFactory promise_factory) { - return spine_->party().SpawnWaitable(name, std::move(promise_factory)); + return spine_->SpawnWaitable(name, std::move(promise_factory)); } Arena* arena() { return spine_->arena(); } + grpc_event_engine::experimental::EventEngine* event_engine() const { + return spine_->event_engine(); + } + private: - RefCountedPtr spine_; + RefCountedPtr spine_; }; class CallHandler { public: - explicit CallHandler(RefCountedPtr spine) + explicit CallHandler(RefCountedPtr spine) : spine_(std::move(spine)) {} auto PullClientInitialMetadata() { @@ -521,22 +358,22 @@ class CallHandler { template auto SpawnWaitable(absl::string_view name, PromiseFactory promise_factory) { - return spine_->party().SpawnWaitable(name, std::move(promise_factory)); + return spine_->SpawnWaitable(name, std::move(promise_factory)); } Arena* arena() { return spine_->arena(); } grpc_event_engine::experimental::EventEngine* event_engine() const { - return DownCast(spine_.get())->event_engine(); + return spine_->event_engine(); } private: - RefCountedPtr spine_; + RefCountedPtr spine_; }; class UnstartedCallHandler { public: - explicit UnstartedCallHandler(RefCountedPtr spine) + explicit UnstartedCallHandler(RefCountedPtr spine) : spine_(std::move(spine)) {} void PushServerTrailingMetadata(ServerMetadataHandle status) { @@ -569,29 +406,28 @@ class UnstartedCallHandler { template auto SpawnWaitable(absl::string_view name, PromiseFactory promise_factory) { - return spine_->party().SpawnWaitable(name, std::move(promise_factory)); + return spine_->SpawnWaitable(name, std::move(promise_factory)); } ClientMetadata& UnprocessedClientInitialMetadata() { return spine_->UnprocessedClientInitialMetadata(); } - CallHandler V2HackToStartCallWithoutACallFilterStack() { - spine_->V2HackToStartCallWithoutACallFilterStack(); - return CallHandler(std::move(spine_)); + // Helper for the very common situation in tests where we want to start a call + // with an empty filter stack. + CallHandler StartWithEmptyFilterStack() { + return StartCall(CallFilters::StackBuilder().Build()); } CallHandler StartCall(RefCountedPtr call_filters) { - DownCast(spine_.get()) - ->call_filters() - .SetStack(std::move(call_filters)); + spine_->call_filters().SetStack(std::move(call_filters)); return CallHandler(std::move(spine_)); } Arena* arena() { return spine_->arena(); } private: - RefCountedPtr spine_; + RefCountedPtr spine_; }; struct CallInitiatorAndHandler { diff --git a/src/core/load_balancing/grpclb/grpclb.cc b/src/core/load_balancing/grpclb/grpclb.cc index e4aadff0d90..6c495a6a787 100644 --- a/src/core/load_balancing/grpclb/grpclb.cc +++ b/src/core/load_balancing/grpclb/grpclb.cc @@ -550,7 +550,7 @@ class GrpcLb final : public LoadBalancingPolicy { bool shutting_down_ = false; // The channel for communicating with the LB server. - OrphanablePtr lb_channel_; + RefCountedPtr lb_channel_; StateWatcher* watcher_ = nullptr; // Response generator to inject address updates into lb_channel_. RefCountedPtr response_generator_; diff --git a/src/core/load_balancing/lb_policy.h b/src/core/load_balancing/lb_policy.h index 1ac1deb2055..43ea6f00765 100644 --- a/src/core/load_balancing/lb_policy.h +++ b/src/core/load_balancing/lb_policy.h @@ -456,6 +456,19 @@ class LoadBalancingPolicy : public InternallyRefCounted { absl::Status status_; }; + // A picker that returns PickResult::Drop for all picks. + class DropPicker final : public SubchannelPicker { + public: + explicit DropPicker(absl::Status status) : status_(status) {} + + PickResult Pick(PickArgs /*args*/) override { + return PickResult::Drop(status_); + } + + private: + absl::Status status_; + }; + protected: std::shared_ptr work_serializer() const { return work_serializer_; diff --git a/src/core/load_balancing/rls/rls.cc b/src/core/load_balancing/rls/rls.cc index 57caea01739..30be3c912cb 100644 --- a/src/core/load_balancing/rls/rls.cc +++ b/src/core/load_balancing/rls/rls.cc @@ -687,7 +687,7 @@ class RlsLb final : public LoadBalancingPolicy { RefCountedPtr lb_policy_; bool is_shutdown_ = false; - OrphanablePtr channel_; + RefCountedPtr channel_; RefCountedPtr parent_channelz_node_; StateWatcher* watcher_ = nullptr; Throttle throttle_ ABSL_GUARDED_BY(&RlsLb::mu_); diff --git a/src/core/plugin_registry/grpc_plugin_registry.cc b/src/core/plugin_registry/grpc_plugin_registry.cc index 80b4010593e..0db484ac828 100644 --- a/src/core/plugin_registry/grpc_plugin_registry.cc +++ b/src/core/plugin_registry/grpc_plugin_registry.cc @@ -67,6 +67,8 @@ extern void RegisterWeightedRoundRobinLbPolicy( CoreConfiguration::Builder* builder); extern void RegisterHttpProxyMapper(CoreConfiguration::Builder* builder); extern void RegisterConnectedChannel(CoreConfiguration::Builder* builder); +extern void RegisterLoadBalancedCallDestination( + CoreConfiguration::Builder* builder); #ifndef GRPC_NO_RLS extern void RegisterRlsLbPolicy(CoreConfiguration::Builder* builder); #endif // !GRPC_NO_RLS @@ -119,6 +121,7 @@ void BuildCoreConfiguration(CoreConfiguration::Builder* builder) { RegisterSockaddrResolver(builder); RegisterFakeResolver(builder); RegisterHttpProxyMapper(builder); + RegisterLoadBalancedCallDestination(builder); #ifdef GPR_SUPPORT_BINDER_TRANSPORT RegisterBinderResolver(builder); #endif diff --git a/src/core/server/server.cc b/src/core/server/server.cc index 6397e03a62c..82e3f5b4f1f 100644 --- a/src/core/server/server.cc +++ b/src/core/server/server.cc @@ -74,11 +74,12 @@ #include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/surface/api_trace.h" #include "src/core/lib/surface/call.h" +#include "src/core/lib/surface/call_utils.h" #include "src/core/lib/surface/channel.h" #include "src/core/lib/surface/channel_stack_type.h" #include "src/core/lib/surface/completion_queue.h" #include "src/core/lib/surface/legacy_channel.h" -#include "src/core/lib/surface/wait_for_cq_end_op.h" +#include "src/core/lib/surface/server_call.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" @@ -770,10 +771,6 @@ class Server::TransportConnectivityWatcher const grpc_channel_filter Server::kServerTopFilter = { Server::CallData::StartTransportStreamOpBatch, - nullptr, - [](grpc_channel_element*, CallSpineInterface*) { - // TODO(ctiller): remove the server filter when call-v3 is finalized - }, grpc_channel_next_op, sizeof(Server::CallData), Server::CallData::InitCallElement, @@ -809,7 +806,7 @@ RefCountedPtr CreateChannelzNode( absl::StatusOr CheckClientMetadata( ValueOrFailure md) { if (!md.ok()) { - return absl::InternalError("Missing metadata"); + return absl::InternalError("Error reading metadata"); } if (!md.value()->get_pointer(HttpPathMetadata())) { return absl::InternalError("Missing :path header"); @@ -986,14 +983,16 @@ grpc_error_handle Server::SetupTransport( ++connections_open_; } else { CHECK(transport->filter_stack_transport() != nullptr); - absl::StatusOr> channel = LegacyChannel::Create( + absl::StatusOr> channel = LegacyChannel::Create( "", args.SetObject(transport), GRPC_SERVER_CHANNEL); if (!channel.ok()) { return absl_status_to_grpc_error(channel.status()); } + CHECK(*channel != nullptr); + auto* channel_stack = (*channel)->channel_stack(); + CHECK(channel_stack != nullptr); ChannelData* chand = static_cast( - grpc_channel_stack_element((*channel)->channel_stack(), 0) - ->channel_data); + grpc_channel_stack_element(channel_stack, 0)->channel_data); // Set up CQs. size_t cq_idx; for (cq_idx = 0; cq_idx < cqs_.size(); cq_idx++) { @@ -1135,7 +1134,7 @@ std::vector> Server::GetChannelsLocked() const { std::vector> channels; channels.reserve(channels_.size()); for (const ChannelData* chand : channels_) { - channels.push_back(chand->channel()->Ref()); + channels.push_back(chand->channel()->RefAsSubclass()); } return channels; } @@ -1342,7 +1341,7 @@ class Server::ChannelData::ConnectivityWatcher : public AsyncConnectivityStateWatcherInterface { public: explicit ConnectivityWatcher(ChannelData* chand) - : chand_(chand), channel_(chand_->channel_->Ref()) {} + : chand_(chand), channel_(chand_->channel_->RefAsSubclass()) {} private: void OnConnectivityStateChange(grpc_connectivity_state new_state, @@ -1379,7 +1378,7 @@ Server::ChannelData::~ChannelData() { } void Server::ChannelData::InitTransport(RefCountedPtr server, - OrphanablePtr channel, + RefCountedPtr channel, size_t cq_idx, Transport* transport, intptr_t channelz_socket_uuid) { server_ = std::move(server); @@ -1451,7 +1450,7 @@ void Server::ChannelData::AcceptStream(void* arg, Transport* /*transport*/, auto* chand = static_cast(arg); // create a call grpc_call_create_args args; - args.channel = chand->channel_->Ref(); + args.channel = chand->channel_->RefAsSubclass(); args.server = chand->server_.get(); args.parent = nullptr; args.propagation_mask = 0; diff --git a/src/core/server/server.h b/src/core/server/server.h index 279e1f8362b..72cffdfee9a 100644 --- a/src/core/server/server.h +++ b/src/core/server/server.h @@ -243,7 +243,7 @@ class Server : public ServerInterface, ~ChannelData(); void InitTransport(RefCountedPtr server, - OrphanablePtr channel, size_t cq_idx, + RefCountedPtr channel, size_t cq_idx, Transport* transport, intptr_t channelz_socket_uuid); RefCountedPtr server() const { return server_; } @@ -254,7 +254,6 @@ class Server : public ServerInterface, static grpc_error_handle InitChannelElement( grpc_channel_element* elem, grpc_channel_element_args* args); static void DestroyChannelElement(grpc_channel_element* elem); - void InitCall(RefCountedPtr call); private: class ConnectivityWatcher; @@ -267,7 +266,7 @@ class Server : public ServerInterface, static void FinishDestroy(void* arg, grpc_error_handle error); RefCountedPtr server_; - OrphanablePtr channel_; + RefCountedPtr channel_; // The index into Server::cqs_ of the CQ used as a starting point for // where to publish new incoming calls. size_t cq_idx_; diff --git a/src/core/server/server_call_tracer_filter.cc b/src/core/server/server_call_tracer_filter.cc index f6a02adefd5..1454a4f5e92 100644 --- a/src/core/server/server_call_tracer_filter.cc +++ b/src/core/server/server_call_tracer_filter.cc @@ -102,7 +102,6 @@ ServerCallTracerFilter::Create(const ChannelArgs& /*args*/, } // namespace void RegisterServerCallTracerFilter(CoreConfiguration::Builder* builder) { - if (IsChaoticGoodEnabled()) return; builder->channel_init()->RegisterFilter( GRPC_SERVER_CHANNEL); } diff --git a/src/core/xds/grpc/xds_transport_grpc.cc b/src/core/xds/grpc/xds_transport_grpc.cc index 3f2716bcdd0..4344f1f8d1f 100644 --- a/src/core/xds/grpc/xds_transport_grpc.cc +++ b/src/core/xds/grpc/xds_transport_grpc.cc @@ -253,12 +253,12 @@ class GrpcXdsTransportFactory::GrpcXdsTransport::StateWatcher final namespace { -OrphanablePtr CreateXdsChannel( +RefCountedPtr CreateXdsChannel( const ChannelArgs& args, const GrpcXdsBootstrap::GrpcXdsServer& server) { RefCountedPtr channel_creds = CoreConfiguration::Get().channel_creds_registry().CreateChannelCreds( server.channel_creds_config()); - return OrphanablePtr(Channel::FromC(grpc_channel_create( + return RefCountedPtr(Channel::FromC(grpc_channel_create( server.server_uri().c_str(), channel_creds.get(), args.ToC().get()))); } diff --git a/src/core/xds/grpc/xds_transport_grpc.h b/src/core/xds/grpc/xds_transport_grpc.h index d0c08aa3cd9..fc951f07594 100644 --- a/src/core/xds/grpc/xds_transport_grpc.h +++ b/src/core/xds/grpc/xds_transport_grpc.h @@ -83,7 +83,7 @@ class GrpcXdsTransportFactory::GrpcXdsTransport final class StateWatcher; GrpcXdsTransportFactory* factory_; // Not owned. - OrphanablePtr channel_; + RefCountedPtr channel_; StateWatcher* watcher_; }; diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index 4bbf8be728d..4e7f7b1dd9a 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -675,22 +675,24 @@ CORE_SOURCE_FILES = [ '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/call_utils.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/client_call.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/filter_stack_call.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_call.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_arena_allocator.cc', 'src/core/lib/transport/call_filters.cc', diff --git a/test/core/call/BUILD b/test/core/call/BUILD new file mode 100644 index 00000000000..6ca668d0251 --- /dev/null +++ b/test/core/call/BUILD @@ -0,0 +1,79 @@ +# 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("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_package") +load("//test/core/call/yodel:grpc_yodel_test.bzl", "grpc_yodel_simple_test") + +grpc_package(name = "test/core/call") + +grpc_yodel_simple_test( + name = "client_call", + srcs = [ + "client_call_test.cc", + ], + external_deps = ["gtest"], + language = "C++", + deps = [ + "batch_builder", + "//:grpc_base", + "//test/core/call/yodel:yodel_test", + ], +) + +grpc_yodel_simple_test( + name = "server_call", + srcs = [ + "server_call_test.cc", + ], + external_deps = ["gtest"], + language = "C++", + deps = [ + "batch_builder", + "//:grpc_base", + "//test/core/call/yodel:yodel_test", + ], +) + +grpc_cc_test( + name = "call_utils_test", + srcs = [ + "call_utils_test.cc", + ], + external_deps = ["gtest"], + language = "C++", + deps = [ + "//:grpc_base", + ], +) + +grpc_cc_library( + name = "batch_builder", + testonly = True, + srcs = [ + "batch_builder.cc", + ], + hdrs = [ + "batch_builder.h", + ], + external_deps = [ + "absl/strings", + "gtest", + ], + visibility = ["//test/core:__subpackages__"], + deps = [ + "//:grpc", + "//src/core:slice", + "//test/core/end2end:cq_verifier", + ], +) diff --git a/test/core/call/batch_builder.cc b/test/core/call/batch_builder.cc new file mode 100644 index 00000000000..552bd15ee8a --- /dev/null +++ b/test/core/call/batch_builder.cc @@ -0,0 +1,208 @@ +// 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 "test/core/call/batch_builder.h" + +#include + +#include "src/core/lib/compression/message_compress.h" + +namespace grpc_core { + +ByteBufferUniquePtr ByteBufferFromSlice(Slice slice) { + return ByteBufferUniquePtr( + grpc_raw_byte_buffer_create(const_cast(&slice.c_slice()), 1), + grpc_byte_buffer_destroy); +} + +absl::optional FindInMetadataArray(const grpc_metadata_array& md, + absl::string_view key) { + for (size_t i = 0; i < md.count; i++) { + if (key == StringViewFromSlice(md.metadata[i].key)) { + return std::string(StringViewFromSlice(md.metadata[i].value)); + } + } + return absl::nullopt; +} + +absl::optional IncomingMetadata::Get(absl::string_view key) const { + return FindInMetadataArray(*metadata_, key); +} + +grpc_op IncomingMetadata::MakeOp() { + grpc_op op; + memset(&op, 0, sizeof(op)); + op.op = GRPC_OP_RECV_INITIAL_METADATA; + op.data.recv_initial_metadata.recv_initial_metadata = metadata_.get(); + return op; +} + +std::string IncomingMetadata::GetSuccessfulStateString() { + std::string out = "incoming_metadata: {"; + for (size_t i = 0; i < metadata_->count; i++) { + absl::StrAppend(&out, StringViewFromSlice(metadata_->metadata[i].key), ":", + StringViewFromSlice(metadata_->metadata[i].value), ","); + } + return out + "}"; +} + +std::string IncomingMessage::payload() const { + Slice out; + if (payload_->data.raw.compression > GRPC_COMPRESS_NONE) { + grpc_slice_buffer decompressed_buffer; + grpc_slice_buffer_init(&decompressed_buffer); + CHECK(grpc_msg_decompress(payload_->data.raw.compression, + &payload_->data.raw.slice_buffer, + &decompressed_buffer)); + grpc_byte_buffer* rbb = grpc_raw_byte_buffer_create( + decompressed_buffer.slices, decompressed_buffer.count); + grpc_byte_buffer_reader reader; + CHECK(grpc_byte_buffer_reader_init(&reader, rbb)); + out = Slice(grpc_byte_buffer_reader_readall(&reader)); + grpc_byte_buffer_reader_destroy(&reader); + grpc_byte_buffer_destroy(rbb); + grpc_slice_buffer_destroy(&decompressed_buffer); + } else { + grpc_byte_buffer_reader reader; + CHECK(grpc_byte_buffer_reader_init(&reader, payload_)); + out = Slice(grpc_byte_buffer_reader_readall(&reader)); + grpc_byte_buffer_reader_destroy(&reader); + } + return std::string(out.begin(), out.end()); +} + +grpc_op IncomingMessage::MakeOp() { + grpc_op op; + memset(&op, 0, sizeof(op)); + op.op = GRPC_OP_RECV_MESSAGE; + op.data.recv_message.recv_message = &payload_; + return op; +} + +absl::optional IncomingStatusOnClient::GetTrailingMetadata( + absl::string_view key) const { + return FindInMetadataArray(data_->trailing_metadata, key); +} + +std::string IncomingStatusOnClient::GetSuccessfulStateString() { + std::string out = absl::StrCat( + "status_on_client: status=", data_->status, + " msg=", data_->status_details.as_string_view(), " trailing_metadata={"); + for (size_t i = 0; i < data_->trailing_metadata.count; i++) { + absl::StrAppend( + &out, StringViewFromSlice(data_->trailing_metadata.metadata[i].key), + ": ", StringViewFromSlice(data_->trailing_metadata.metadata[i].value), + ","); + } + return out + "}"; +} + +std::string IncomingMessage::GetSuccessfulStateString() { + if (payload_ == nullptr) return "message: empty"; + return absl::StrCat("message: ", payload().size(), "b uncompressed"); +} + +grpc_op IncomingStatusOnClient::MakeOp() { + grpc_op op; + memset(&op, 0, sizeof(op)); + op.op = GRPC_OP_RECV_STATUS_ON_CLIENT; + op.data.recv_status_on_client.trailing_metadata = &data_->trailing_metadata; + op.data.recv_status_on_client.status = &data_->status; + op.data.recv_status_on_client.status_details = + const_cast(&data_->status_details.c_slice()); + op.data.recv_status_on_client.error_string = &data_->error_string; + return op; +} + +grpc_op IncomingCloseOnServer::MakeOp() { + grpc_op op; + memset(&op, 0, sizeof(op)); + op.op = GRPC_OP_RECV_CLOSE_ON_SERVER; + op.data.recv_close_on_server.cancelled = &cancelled_; + return op; +} + +BatchBuilder& BatchBuilder::SendInitialMetadata( + std::initializer_list> md, + uint32_t flags, absl::optional compression_level) { + auto& v = Make>(); + for (const auto& p : md) { + grpc_metadata m; + m.key = Make(Slice::FromCopiedString(p.first)).c_slice(); + m.value = Make(Slice::FromCopiedString(p.second)).c_slice(); + v.push_back(m); + } + grpc_op op; + memset(&op, 0, sizeof(op)); + op.op = GRPC_OP_SEND_INITIAL_METADATA; + op.flags = flags; + op.data.send_initial_metadata.count = v.size(); + op.data.send_initial_metadata.metadata = v.data(); + if (compression_level.has_value()) { + op.data.send_initial_metadata.maybe_compression_level.is_set = 1; + op.data.send_initial_metadata.maybe_compression_level.level = + compression_level.value(); + } + ops_.push_back(op); + return *this; +} + +BatchBuilder& BatchBuilder::SendMessage(Slice payload, uint32_t flags) { + grpc_op op; + memset(&op, 0, sizeof(op)); + op.op = GRPC_OP_SEND_MESSAGE; + op.data.send_message.send_message = + Make(ByteBufferFromSlice(std::move(payload))).get(); + op.flags = flags; + ops_.push_back(op); + return *this; +} + +BatchBuilder& BatchBuilder::SendCloseFromClient() { + grpc_op op; + memset(&op, 0, sizeof(op)); + op.op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; + ops_.push_back(op); + return *this; +} + +BatchBuilder& BatchBuilder::SendStatusFromServer( + grpc_status_code status, absl::string_view message, + std::initializer_list> md) { + auto& v = Make>(); + for (const auto& p : md) { + grpc_metadata m; + m.key = Make(Slice::FromCopiedString(p.first)).c_slice(); + m.value = Make(Slice::FromCopiedString(p.second)).c_slice(); + v.push_back(m); + } + grpc_op op; + memset(&op, 0, sizeof(op)); + op.op = GRPC_OP_SEND_STATUS_FROM_SERVER; + op.data.send_status_from_server.trailing_metadata_count = v.size(); + op.data.send_status_from_server.trailing_metadata = v.data(); + op.data.send_status_from_server.status = status; + op.data.send_status_from_server.status_details = &Make( + Make(Slice::FromCopiedString(message)).c_slice()); + ops_.push_back(op); + return *this; +} + +BatchBuilder::~BatchBuilder() { + grpc_call_error err = grpc_call_start_batch(call_, ops_.data(), ops_.size(), + CqVerifier::tag(tag_), nullptr); + EXPECT_EQ(err, GRPC_CALL_OK) << grpc_call_error_to_string(err); +} + +} // namespace grpc_core diff --git a/test/core/call/batch_builder.h b/test/core/call/batch_builder.h new file mode 100644 index 00000000000..40202ea25dc --- /dev/null +++ b/test/core/call/batch_builder.h @@ -0,0 +1,261 @@ +// 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_TEST_CORE_CALL_BATCH_BUILDER_H +#define GRPC_TEST_CORE_CALL_BATCH_BUILDER_H + +#include "absl/strings/str_cat.h" +#include "gtest/gtest.h" + +#include "src/core/lib/slice/slice.h" +#include "test/core/end2end/cq_verifier.h" + +namespace grpc_core { + +using ByteBufferUniquePtr = + std::unique_ptr; +ByteBufferUniquePtr ByteBufferFromSlice(Slice slice); + +absl::optional FindInMetadataArray(const grpc_metadata_array& md, + absl::string_view key); + +// Receiving container for incoming metadata. +class IncomingMetadata final : public CqVerifier::SuccessfulStateString { + public: + IncomingMetadata() = default; + ~IncomingMetadata() { + if (metadata_ != nullptr) grpc_metadata_array_destroy(metadata_.get()); + } + + // Lookup a metadata value by key. + absl::optional Get(absl::string_view key) const; + + // Make a GRPC_RECV_INITIAL_METADATA op - intended for the framework, not + // for tests. + grpc_op MakeOp(); + + std::string GetSuccessfulStateString() override; + + private: + std::unique_ptr metadata_ = + std::make_unique(grpc_metadata_array{0, 0, nullptr}); +}; + +// Receiving container for one incoming message. +class IncomingMessage final : public CqVerifier::SuccessfulStateString { + public: + IncomingMessage() = default; + IncomingMessage(const IncomingMessage&) = delete; + IncomingMessage& operator=(const IncomingMessage&) = delete; + ~IncomingMessage() { + if (payload_ != nullptr) grpc_byte_buffer_destroy(payload_); + } + + // Get the payload of the message - concatenated together into a string for + // easy verification. + std::string payload() const; + // Check if the message is the end of the stream. + bool is_end_of_stream() const { return payload_ == nullptr; } + // Get the type of the message. + grpc_byte_buffer_type byte_buffer_type() const { return payload_->type; } + // Get the compression algorithm used for the message. + grpc_compression_algorithm compression() const { + return payload_->data.raw.compression; + } + std::string GetSuccessfulStateString() override; + + // Make a GRPC_OP_RECV_MESSAGE op - intended for the framework, not for + // tests. + grpc_op MakeOp(); + + // Accessor for CoreEnd2endTest::IncomingCall - get a pointer to the + // underlying payload. + // We don't want to use this in tests directly. + grpc_byte_buffer** raw_payload_ptr() { return &payload_; } + + private: + grpc_byte_buffer* payload_ = nullptr; +}; + +// Receiving container for incoming status on the client from the server. +class IncomingStatusOnClient final : public CqVerifier::SuccessfulStateString { + public: + IncomingStatusOnClient() = default; + IncomingStatusOnClient(const IncomingStatusOnClient&) = delete; + IncomingStatusOnClient& operator=(const IncomingStatusOnClient&) = delete; + IncomingStatusOnClient(IncomingStatusOnClient&& other) noexcept = default; + IncomingStatusOnClient& operator=(IncomingStatusOnClient&& other) noexcept = + default; + ~IncomingStatusOnClient() { + if (data_ != nullptr) { + grpc_metadata_array_destroy(&data_->trailing_metadata); + gpr_free(const_cast(data_->error_string)); + } + } + + // Get the status code. + grpc_status_code status() const { return data_->status; } + // Get the status details. + std::string message() const { + return std::string(data_->status_details.as_string_view()); + } + // Get the error string. + std::string error_string() const { + return data_->error_string == nullptr ? "" : data_->error_string; + } + // Get a trailing metadata value by key. + absl::optional GetTrailingMetadata(absl::string_view key) const; + + std::string GetSuccessfulStateString() override; + + // Make a GRPC_OP_RECV_STATUS_ON_CLIENT op - intended for the framework, not + // for tests. + grpc_op MakeOp(); + + private: + struct Data { + grpc_metadata_array trailing_metadata{0, 0, nullptr}; + grpc_status_code status; + Slice status_details; + const char* error_string = nullptr; + }; + std::unique_ptr data_ = std::make_unique(); +}; + +// Receiving container for incoming status on the server from the client. +class IncomingCloseOnServer final : public CqVerifier::SuccessfulStateString { + public: + IncomingCloseOnServer() = default; + IncomingCloseOnServer(const IncomingCloseOnServer&) = delete; + IncomingCloseOnServer& operator=(const IncomingCloseOnServer&) = delete; + + // Get the cancellation bit. + bool was_cancelled() const { return cancelled_ != 0; } + + // Make a GRPC_OP_RECV_CLOSE_ON_SERVER op - intended for the framework, not + // for tests. + grpc_op MakeOp(); + + std::string GetSuccessfulStateString() override { + return absl::StrCat("close_on_server: cancelled=", cancelled_); + } + + private: + int cancelled_; +}; + +// Build one batch. Returned from NewBatch (use that to instantiate this!) +// Upon destruction of the BatchBuilder, the batch will be executed with any +// added batches. +class BatchBuilder { + public: + BatchBuilder(grpc_call* call, CqVerifier* cq_verifier, int tag) + : call_(call), tag_(tag), cq_verifier_(cq_verifier) { + cq_verifier_->ClearSuccessfulStateStrings(CqVerifier::tag(tag_)); + } + ~BatchBuilder(); + + BatchBuilder(const BatchBuilder&) = delete; + BatchBuilder& operator=(const BatchBuilder&) = delete; + BatchBuilder(BatchBuilder&&) noexcept = default; + + // Add a GRPC_OP_SEND_INITIAL_METADATA op. + // Optionally specify flags, compression level. + BatchBuilder& SendInitialMetadata( + std::initializer_list> md, + uint32_t flags = 0, + absl::optional compression_level = absl::nullopt); + + // Add a GRPC_OP_SEND_MESSAGE op. + BatchBuilder& SendMessage(Slice payload, uint32_t flags = 0); + BatchBuilder& SendMessage(absl::string_view payload, uint32_t flags = 0) { + return SendMessage(Slice::FromCopiedString(payload), flags); + } + + // Add a GRPC_OP_SEND_CLOSE_FROM_CLIENT op. + BatchBuilder& SendCloseFromClient(); + + // Add a GRPC_OP_SEND_STATUS_FROM_SERVER op. + BatchBuilder& SendStatusFromServer( + grpc_status_code status, absl::string_view message, + std::initializer_list> + md); + + // Add a GRPC_OP_RECV_INITIAL_METADATA op. + BatchBuilder& RecvInitialMetadata(IncomingMetadata& md) { + cq_verifier_->AddSuccessfulStateString(CqVerifier::tag(tag_), &md); + ops_.emplace_back(md.MakeOp()); + return *this; + } + + // Add a GRPC_OP_RECV_MESSAGE op. + BatchBuilder& RecvMessage(IncomingMessage& msg) { + cq_verifier_->AddSuccessfulStateString(CqVerifier::tag(tag_), &msg); + ops_.emplace_back(msg.MakeOp()); + return *this; + } + + // Add a GRPC_OP_RECV_STATUS_ON_CLIENT op. + BatchBuilder& RecvStatusOnClient(IncomingStatusOnClient& status) { + cq_verifier_->AddSuccessfulStateString(CqVerifier::tag(tag_), &status); + ops_.emplace_back(status.MakeOp()); + return *this; + } + + // Add a GRPC_OP_RECV_CLOSE_ON_SERVER op. + BatchBuilder& RecvCloseOnServer(IncomingCloseOnServer& close) { + cq_verifier_->AddSuccessfulStateString(CqVerifier::tag(tag_), &close); + ops_.emplace_back(close.MakeOp()); + return *this; + } + + private: + // We need to track little bits of memory up until the batch is executed. + // One Thing is one such block of memory. + // We specialize it with SpecificThing to track a specific type of memory. + // These get placed on things_ and deleted when the batch is executed. + class Thing { + public: + virtual ~Thing() = default; + }; + template + class SpecificThing final : public Thing { + public: + template + explicit SpecificThing(Args&&... args) : t_(std::forward(args)...) {} + SpecificThing() = default; + + T& get() { return t_; } + + private: + T t_; + }; + + // Make a thing of type T, and return a reference to it. + template + T& Make(Args&&... args) { + things_.emplace_back(new SpecificThing(std::forward(args)...)); + return static_cast*>(things_.back().get())->get(); + } + + grpc_call* call_; + const int tag_; + std::vector ops_; + std::vector> things_; + CqVerifier* const cq_verifier_; +}; + +} // namespace grpc_core + +#endif // GRPC_TEST_CORE_CALL_BATCH_BUILDER_H diff --git a/test/core/call/call_utils_test.cc b/test/core/call/call_utils_test.cc new file mode 100644 index 00000000000..f9a8fdae345 --- /dev/null +++ b/test/core/call/call_utils_test.cc @@ -0,0 +1,72 @@ +// 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/lib/surface/call_utils.h" + +#include + +#include "gtest/gtest.h" + +#include + +namespace grpc_core { + +TEST(CallUtils, AreWriteFlagsValid) { + EXPECT_TRUE(AreWriteFlagsValid(0)); + EXPECT_TRUE(AreWriteFlagsValid(GRPC_WRITE_BUFFER_HINT)); + EXPECT_TRUE(AreWriteFlagsValid(GRPC_WRITE_NO_COMPRESS)); + EXPECT_FALSE(AreWriteFlagsValid(0xffffffff)); +} + +TEST(CallUtils, AreInitialMetadataFlagsValid) { + EXPECT_TRUE(AreInitialMetadataFlagsValid(0)); + EXPECT_TRUE( + AreInitialMetadataFlagsValid(GRPC_INITIAL_METADATA_WAIT_FOR_READY)); + EXPECT_TRUE(AreInitialMetadataFlagsValid(GRPC_WRITE_THROUGH)); + EXPECT_FALSE(AreInitialMetadataFlagsValid(0xffffffff)); +} + +namespace { +void do_these_things(std::initializer_list) {} + +template +std::vector TestOps(T... ops) { + std::vector out; + auto add_op = [&out](grpc_op_type type) { + grpc_op op; + op.op = type; + out.push_back(op); + return 1; + }; + do_these_things({add_op(ops)...}); + return out; +} +} // namespace + +TEST(BatchOpIndex, Basic) { + const auto ops = TestOps(GRPC_OP_SEND_INITIAL_METADATA, GRPC_OP_SEND_MESSAGE, + GRPC_OP_SEND_CLOSE_FROM_CLIENT); + BatchOpIndex idx(ops.data(), ops.size()); + EXPECT_EQ(idx.op(GRPC_OP_SEND_INITIAL_METADATA), &ops[0]); + EXPECT_EQ(idx.op(GRPC_OP_SEND_MESSAGE), &ops[1]); + EXPECT_EQ(idx.op(GRPC_OP_SEND_CLOSE_FROM_CLIENT), &ops[2]); + EXPECT_EQ(idx.op(GRPC_OP_SEND_STATUS_FROM_SERVER), nullptr); +} + +} // namespace grpc_core + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/core/call/client_call_test.cc b/test/core/call/client_call_test.cc new file mode 100644 index 00000000000..537e0b48db6 --- /dev/null +++ b/test/core/call/client_call_test.cc @@ -0,0 +1,251 @@ +// 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/lib/surface/client_call.h" + +#include "absl/status/status.h" + +#include +#include + +#include "src/core/lib/gprpp/debug_location.h" +#include "src/core/lib/resource_quota/arena.h" +#include "src/core/lib/transport/metadata.h" +#include "test/core/call/batch_builder.h" +#include "test/core/call/yodel/yodel_test.h" + +namespace grpc_core { + +namespace { +const absl::string_view kDefaultPath = "/foo/bar"; +} + +class ClientCallTest : public YodelTest { + protected: + using YodelTest::YodelTest; + + class CallOptions { + public: + Slice path() const { return path_.Copy(); } + absl::optional authority() const { + return authority_.has_value() ? absl::optional(authority_->Copy()) + : absl::nullopt; + } + bool registered_method() const { return registered_method_; } + Duration timeout() const { return timeout_; } + grpc_compression_options compression_options() const { + return compression_options_; + } + + CallOptions& SetTimeout(Duration timeout) { + timeout_ = timeout; + return *this; + } + + private: + Slice path_ = Slice::FromCopiedString(kDefaultPath); + absl::optional authority_; + bool registered_method_ = false; + Duration timeout_ = Duration::Infinity(); + grpc_compression_options compression_options_ = { + 1, + {0, GRPC_COMPRESS_LEVEL_NONE}, + {0, GRPC_COMPRESS_NONE}, + }; + }; + + grpc_call* InitCall(const CallOptions& options) { + CHECK_EQ(call_, nullptr); + call_ = MakeClientCall(nullptr, 0, cq_, options.path(), options.authority(), + options.registered_method(), + options.timeout() + Timestamp::Now(), + options.compression_options(), event_engine().get(), + SimpleArenaAllocator()->MakeArena(), destination_); + return call_; + } + + BatchBuilder NewBatch(int tag) { + return BatchBuilder(call_, cq_verifier_.get(), tag); + } + + // Pull in CqVerifier types for ergonomics + using ExpectedResult = CqVerifier::ExpectedResult; + using Maybe = CqVerifier::Maybe; + using PerformAction = CqVerifier::PerformAction; + using MaybePerformAction = CqVerifier::MaybePerformAction; + using AnyStatus = CqVerifier::AnyStatus; + void Expect(int tag, ExpectedResult result, SourceLocation whence = {}) { + expectations_++; + cq_verifier_->Expect(CqVerifier::tag(tag), std::move(result), whence); + } + + void TickThroughCqExpectations( + absl::optional timeout = absl::nullopt, + SourceLocation whence = {}) { + if (expectations_ == 0) { + cq_verifier_->VerifyEmpty(timeout.value_or(Duration::Seconds(1)), whence); + return; + } + expectations_ = 0; + cq_verifier_->Verify(timeout.value_or(Duration::Seconds(10)), whence); + } + + CallHandler& handler() { + CHECK(handler_.has_value()); + return *handler_; + } + + private: + class TestCallDestination final : public UnstartedCallDestination { + public: + explicit TestCallDestination(ClientCallTest* test) : test_(test) {} + + void Orphaned() override {} + void StartCall(UnstartedCallHandler handler) override { + CHECK(!test_->handler_.has_value()); + test_->handler_.emplace(handler.StartWithEmptyFilterStack()); + } + + private: + ClientCallTest* const test_; + }; + + void InitTest() override { + cq_ = grpc_completion_queue_create_for_next(nullptr); + cq_verifier_ = absl::make_unique( + cq_, CqVerifier::FailUsingGprCrash, + [this]( + grpc_event_engine::experimental::EventEngine::Duration max_step) { + event_engine()->Tick(max_step); + }); + } + + void Shutdown() override { + if (call_ != nullptr) { + grpc_call_unref(call_); + } + handler_.reset(); + grpc_completion_queue_shutdown(cq_); + auto ev = grpc_completion_queue_next( + cq_, gpr_inf_future(GPR_CLOCK_REALTIME), nullptr); + CHECK_EQ(ev.type, GRPC_QUEUE_SHUTDOWN); + grpc_completion_queue_destroy(cq_); + } + + grpc_completion_queue* cq_ = nullptr; + grpc_call* call_ = nullptr; + RefCountedPtr destination_ = + MakeRefCounted(this); + absl::optional handler_; + std::unique_ptr cq_verifier_; + int expectations_ = 0; +}; + +#define CLIENT_CALL_TEST(name) YODEL_TEST(ClientCallTest, name) + +CLIENT_CALL_TEST(NoOp) { InitCall(CallOptions()); } + +CLIENT_CALL_TEST(SendInitialMetadata) { + InitCall(CallOptions()); + NewBatch(1).SendInitialMetadata({ + {"foo", "bar"}, + }); + Expect(1, true); + TickThroughCqExpectations(); + SpawnTestSeq( + handler(), "pull-initial-metadata", + [this]() { return handler().PullClientInitialMetadata(); }, + [](ValueOrFailure md) { + CHECK(md.ok()); + CHECK_NE((*md)->get_pointer(HttpPathMetadata()), nullptr); + EXPECT_EQ((*md)->get_pointer(HttpPathMetadata())->as_string_view(), + kDefaultPath); + std::string buffer; + auto r = (*md)->GetStringValue("foo", &buffer); + EXPECT_EQ(r, "bar"); + return Immediate(Empty{}); + }); + WaitForAllPendingWork(); +} + +CLIENT_CALL_TEST(SendInitialMetadataAndReceiveStatusAfterCancellation) { + InitCall(CallOptions()); + IncomingStatusOnClient status; + NewBatch(1).SendInitialMetadata({}).RecvStatusOnClient(status); + SpawnTestSeq( + handler(), "pull-initial-metadata", + [this]() { return handler().PullClientInitialMetadata(); }, + [this](ValueOrFailure md) { + CHECK(md.ok()); + EXPECT_EQ((*md)->get_pointer(HttpPathMetadata())->as_string_view(), + kDefaultPath); + handler().PushServerTrailingMetadata( + ServerMetadataFromStatus(absl::InternalError("test error"))); + return Immediate(Empty{}); + }); + Expect(1, true); + TickThroughCqExpectations(); + EXPECT_EQ(status.status(), GRPC_STATUS_INTERNAL); + EXPECT_EQ(status.message(), "test error"); + WaitForAllPendingWork(); +} + +CLIENT_CALL_TEST(SendInitialMetadataAndReceiveStatusAfterTimeout) { + auto start = Timestamp::Now(); + InitCall(CallOptions().SetTimeout(Duration::Seconds(1))); + IncomingStatusOnClient status; + NewBatch(1).SendInitialMetadata({}).RecvStatusOnClient(status); + Expect(1, true); + TickThroughCqExpectations(); + EXPECT_EQ(status.status(), GRPC_STATUS_DEADLINE_EXCEEDED); + ExecCtx::Get()->InvalidateNow(); + auto now = Timestamp::Now(); + EXPECT_GE(now - start, Duration::Seconds(1)) << GRPC_DUMP_ARGS(now, start); + EXPECT_LE(now - start, Duration::Seconds(5)) << GRPC_DUMP_ARGS(now, start); + WaitForAllPendingWork(); +} + +CLIENT_CALL_TEST(CancelBeforeInvoke1) { + grpc_call_cancel(InitCall(CallOptions()), nullptr); + IncomingStatusOnClient status; + NewBatch(1).RecvStatusOnClient(status); + Expect(1, true); + TickThroughCqExpectations(); + EXPECT_EQ(status.status(), GRPC_STATUS_CANCELLED); +} + +CLIENT_CALL_TEST(CancelBeforeInvoke2) { + grpc_call_cancel(InitCall(CallOptions()), nullptr); + IncomingStatusOnClient status; + NewBatch(1).RecvStatusOnClient(status).SendInitialMetadata({}); + Expect(1, true); + TickThroughCqExpectations(); + EXPECT_EQ(status.status(), GRPC_STATUS_CANCELLED); +} + +CLIENT_CALL_TEST(NegativeDeadline) { + auto start = Timestamp::Now(); + InitCall(CallOptions().SetTimeout(Duration::Seconds(-1))); + IncomingStatusOnClient status; + NewBatch(1).SendInitialMetadata({}).RecvStatusOnClient(status); + Expect(1, true); + TickThroughCqExpectations(); + EXPECT_EQ(status.status(), GRPC_STATUS_DEADLINE_EXCEEDED); + auto now = Timestamp::Now(); + EXPECT_LE(now - start, Duration::Milliseconds(100)) + << GRPC_DUMP_ARGS(now, start); + WaitForAllPendingWork(); +} + +} // namespace grpc_core diff --git a/test/core/call/corpus/client_call/empty b/test/core/call/corpus/client_call/empty new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/test/core/call/corpus/client_call/empty @@ -0,0 +1 @@ + diff --git a/test/core/call/corpus/server_call/empty b/test/core/call/corpus/server_call/empty new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/test/core/call/corpus/server_call/empty @@ -0,0 +1 @@ + diff --git a/test/core/call/server_call_test.cc b/test/core/call/server_call_test.cc new file mode 100644 index 00000000000..5407a559c9c --- /dev/null +++ b/test/core/call/server_call_test.cc @@ -0,0 +1,138 @@ +// 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/lib/surface/server_call.h" + +#include + +#include "absl/status/status.h" + +#include +#include + +#include "src/core/channelz/channelz.h" +#include "src/core/lib/promise/promise.h" +#include "src/core/lib/resource_quota/arena.h" +#include "src/core/telemetry/call_tracer.h" +#include "test/core/call/batch_builder.h" +#include "test/core/call/yodel/yodel_test.h" + +namespace grpc_core { + +namespace { +const absl::string_view kDefaultPath = "/foo/bar"; +} + +class ServerCallTest : public YodelTest { + protected: + using YodelTest::YodelTest; + + grpc_call* InitCall(ClientMetadataHandle client_initial_metadata) { + CHECK_EQ(call_, nullptr); + auto call = + MakeCallPair(std::move(client_initial_metadata), event_engine().get(), + SimpleArenaAllocator()->MakeArena()); + call.initiator.SpawnGuarded( + "initial_metadata", + [this, handler = call.handler.StartWithEmptyFilterStack()]() mutable { + return TrySeq( + handler.PullClientInitialMetadata(), + [this, + handler](ClientMetadataHandle client_initial_metadata) mutable { + call_.store(MakeServerCall(std::move(handler), + std::move(client_initial_metadata), + &test_server_, cq_, + &publish_initial_metadata_), + std::memory_order_release); + return absl::OkStatus(); + }); + }); + while (true) { + auto* result = call_.load(std::memory_order_acquire); + if (result != nullptr) return result; + } + } + + ClientMetadataHandle MakeClientInitialMetadata( + std::initializer_list> + md) { + auto client_initial_metadata = Arena::MakePooled(); + client_initial_metadata->Set(HttpPathMetadata(), + Slice::FromCopiedString(kDefaultPath)); + for (const auto& pair : md) { + client_initial_metadata->Append( + pair.first, Slice::FromCopiedBuffer(pair.second), + [](absl::string_view error, const Slice&) { Crash(error); }); + } + return client_initial_metadata; + } + + absl::optional GetClientInitialMetadata(absl::string_view key) { + CHECK_NE(call_.load(std::memory_order_acquire), nullptr); + return FindInMetadataArray(publish_initial_metadata_, key); + } + + private: + class TestServer final : public ServerInterface { + public: + const ChannelArgs& channel_args() const override { return channel_args_; } + channelz::ServerNode* channelz_node() const override { return nullptr; } + ServerCallTracerFactory* server_call_tracer_factory() const override { + return nullptr; + } + grpc_compression_options compression_options() const override { + return { + 1, + {0, GRPC_COMPRESS_LEVEL_NONE}, + {0, GRPC_COMPRESS_NONE}, + }; + } + + private: + ChannelArgs channel_args_; + }; + + void InitTest() override { + cq_ = grpc_completion_queue_create_for_next(nullptr); + } + + void Shutdown() override { + auto* call = call_.load(std::memory_order_acquire); + if (call != nullptr) { + grpc_call_unref(call); + } + grpc_completion_queue_shutdown(cq_); + auto ev = grpc_completion_queue_next( + cq_, gpr_inf_future(GPR_CLOCK_REALTIME), nullptr); + CHECK_EQ(ev.type, GRPC_QUEUE_SHUTDOWN); + grpc_completion_queue_destroy(cq_); + } + + grpc_completion_queue* cq_{nullptr}; + std::atomic call_{nullptr}; + CallInitiator call_initiator_; + TestServer test_server_; + grpc_metadata_array publish_initial_metadata_{0, 0, nullptr}; +}; + +#define SERVER_CALL_TEST(name) YODEL_TEST(ServerCallTest, name) + +SERVER_CALL_TEST(NoOp) { InitCall(MakeClientInitialMetadata({})); } + +SERVER_CALL_TEST(InitialMetadataPassedThrough) { + InitCall(MakeClientInitialMetadata({{"foo", "bar"}})); + EXPECT_EQ(GetClientInitialMetadata("foo"), "bar"); +} + +} // namespace grpc_core diff --git a/test/core/call/yodel/BUILD b/test/core/call/yodel/BUILD index cdf6fd85a8c..1f679bdbabc 100644 --- a/test/core/call/yodel/BUILD +++ b/test/core/call/yodel/BUILD @@ -41,8 +41,10 @@ grpc_cc_library( ], visibility = ["//test:__subpackages__"], deps = [ + "//:config", "//:debug_location", "//:event_engine_base_hdrs", + "//:exec_ctx", "//:iomgr_timer", "//:promise", "//src/core:call_arena_allocator", @@ -51,6 +53,7 @@ grpc_cc_library( "//src/core:metadata", "//src/core:promise_factory", "//src/core:resource_quota", + "//test/core/event_engine:event_engine_test_utils", "//test/core/event_engine/fuzzing_event_engine", "//test/core/test_util:grpc_test_util", ], diff --git a/test/core/call/yodel/yodel_test.cc b/test/core/call/yodel/yodel_test.cc index bf9d5da8e82..5625aeefe54 100644 --- a/test/core/call/yodel/yodel_test.cc +++ b/test/core/call/yodel/yodel_test.cc @@ -22,6 +22,8 @@ #include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/iomgr/timer_manager.h" #include "src/core/lib/resource_quota/resource_quota.h" +#include "test/core/event_engine/event_engine_test_utils.h" +#include "test/core/test_util/build.h" namespace grpc_core { @@ -144,12 +146,13 @@ void YodelTest::RunTest() { state_->event_engine = std::make_shared( []() { - grpc_timer_manager_set_threading(false); + grpc_timer_manager_set_start_threaded(false); grpc_event_engine::experimental::FuzzingEventEngine::Options options; return options; }(), actions_); + grpc_init(); state_->call_arena_allocator = MakeRefCounted( ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator( "test-allocator"), @@ -168,6 +171,14 @@ void YodelTest::RunTest() { Shutdown(); state_->event_engine->TickUntilIdle(); state_->event_engine->UnsetGlobalHooks(); + grpc_event_engine::experimental::WaitForSingleOwner( + std::move(state_->event_engine)); + grpc_shutdown_blocking(); + if (!grpc_wait_until_shutdown(10)) { + LOG(FATAL) << "Timeout in waiting for gRPC shutdown"; + } + state_.reset(); + AsanAssertNoLeaks(); } void YodelTest::TickUntilTrue(absl::FunctionRef poll) { diff --git a/test/core/call/yodel/yodel_test.h b/test/core/call/yodel/yodel_test.h index 1ce31e051e6..a961ad41cb1 100644 --- a/test/core/call/yodel/yodel_test.h +++ b/test/core/call/yodel/yodel_test.h @@ -390,7 +390,6 @@ class YodelTest : public ::testing::Test { private: class WatchDog; struct State { - grpc::testing::TestGrpcScope grpc_scope; std::shared_ptr event_engine; RefCountedPtr call_arena_allocator; diff --git a/test/core/channel/channel_stack_builder_test.cc b/test/core/channel/channel_stack_builder_test.cc index c11c7496594..2c7dff9526e 100644 --- a/test/core/channel/channel_stack_builder_test.cc +++ b/test/core/channel/channel_stack_builder_test.cc @@ -59,14 +59,13 @@ const grpc_channel_filter* FilterNamed(const char* name) { auto it = filters->find(name); if (it != filters->end()) return it->second; return filters - ->emplace( - name, - new grpc_channel_filter{ - grpc_call_next_op, nullptr, nullptr, grpc_channel_next_op, 0, - CallInitFunc, grpc_call_stack_ignore_set_pollset_or_pollset_set, - CallDestroyFunc, 0, ChannelInitFunc, - [](grpc_channel_stack*, grpc_channel_element*) {}, - ChannelDestroyFunc, grpc_channel_next_get_info, name}) + ->emplace(name, + new grpc_channel_filter{ + grpc_call_next_op, grpc_channel_next_op, 0, CallInitFunc, + grpc_call_stack_ignore_set_pollset_or_pollset_set, + CallDestroyFunc, 0, ChannelInitFunc, + [](grpc_channel_stack*, grpc_channel_element*) {}, + ChannelDestroyFunc, grpc_channel_next_get_info, name}) .first->second; } diff --git a/test/core/channel/channel_stack_test.cc b/test/core/channel/channel_stack_test.cc index 54566934a2a..bc94f262aaf 100644 --- a/test/core/channel/channel_stack_test.cc +++ b/test/core/channel/channel_stack_test.cc @@ -82,8 +82,6 @@ static void free_call(void* arg, grpc_error_handle /*error*/) { TEST(ChannelStackTest, CreateChannelStack) { const grpc_channel_filter filter = { call_func, - nullptr, - nullptr, channel_func, sizeof(int), call_init_func, diff --git a/test/core/client_channel/client_channel_test.cc b/test/core/client_channel/client_channel_test.cc index 78b44db971c..1aa8c644816 100644 --- a/test/core/client_channel/client_channel_test.cc +++ b/test/core/client_channel/client_channel_test.cc @@ -46,7 +46,7 @@ class ClientChannelTest : public YodelTest { ClientChannel& InitChannel(const ChannelArgs& args) { auto channel = ClientChannel::Create(TestTarget(), CompleteArgs(args)); CHECK_OK(channel); - channel_ = OrphanablePtr( + channel_ = RefCountedPtr( DownCast(channel->release())); return *channel_; } @@ -114,8 +114,7 @@ class ClientChannelTest : public YodelTest { class TestCallDestination final : public UnstartedCallDestination { public: void StartCall(UnstartedCallHandler unstarted_call_handler) override { - handlers_.push( - unstarted_call_handler.V2HackToStartCallWithoutACallFilterStack()); + handlers_.push(unstarted_call_handler.StartWithEmptyFilterStack()); } absl::optional PopHandler() { @@ -217,6 +216,7 @@ class ClientChannelTest : public YodelTest { .SetObject(&client_channel_factory_) .SetObject(ResourceQuota::Default()) .SetObject(std::static_pointer_cast(event_engine())) + .SetIfUnset(GRPC_ARG_USE_LOCAL_SUBCHANNEL_POOL, true) // TODO(ctiller): remove once v3 supports retries? .SetIfUnset(GRPC_ARG_ENABLE_RETRIES, 0); } @@ -233,9 +233,10 @@ class ClientChannelTest : public YodelTest { ExecCtx exec_ctx; channel_.reset(); picker_.reset(); + call_destination_.reset(); } - OrphanablePtr channel_; + RefCountedPtr channel_; absl::optional picker_; TestCallDestinationFactory call_destination_factory_{this}; TestClientChannelFactory client_channel_factory_; @@ -251,26 +252,19 @@ class ClientChannelTest : public YodelTest { CLIENT_CHANNEL_TEST(NoOp) { InitChannel(ChannelArgs()); } -CLIENT_CHANNEL_TEST(CreateCall) { - auto& channel = InitChannel(ChannelArgs()); - auto call_initiator = channel.CreateCall(MakeClientInitialMetadata()); - SpawnTestSeq(call_initiator, "cancel", [call_initiator]() mutable { - call_initiator.Cancel(); - return Empty{}; - }); - WaitForAllPendingWork(); -} - CLIENT_CHANNEL_TEST(StartCall) { auto& channel = InitChannel(ChannelArgs()); - auto call_initiator = channel.CreateCall(MakeClientInitialMetadata()); + auto call = MakeCallPair(MakeClientInitialMetadata(), channel.event_engine(), + channel.call_arena_allocator()->MakeArena()); + channel.StartCall(std::move(call.handler)); QueueNameResolutionResult( MakeSuccessfulResolutionResult("ipv4:127.0.0.1:1234")); auto call_handler = TickUntilCallStarted(); - SpawnTestSeq(call_initiator, "cancel", [call_initiator]() mutable { - call_initiator.Cancel(); - return Empty{}; - }); + SpawnTestSeq(call.initiator, "cancel", + [call_initiator = call.initiator]() mutable { + call_initiator.Cancel(); + return Empty{}; + }); WaitForAllPendingWork(); } diff --git a/test/core/client_channel/load_balanced_call_destination_test.cc b/test/core/client_channel/load_balanced_call_destination_test.cc index ca4bfe8704c..b3d37c5e2ba 100644 --- a/test/core/client_channel/load_balanced_call_destination_test.cc +++ b/test/core/client_channel/load_balanced_call_destination_test.cc @@ -75,8 +75,7 @@ class LoadBalancedCallDestinationTest : public YodelTest { class TestCallDestination final : public UnstartedCallDestination { public: void StartCall(UnstartedCallHandler unstarted_call_handler) override { - handlers_.push( - unstarted_call_handler.V2HackToStartCallWithoutACallFilterStack()); + handlers_.push(unstarted_call_handler.StartWithEmptyFilterStack()); } absl::optional PopHandler() { @@ -133,7 +132,7 @@ class LoadBalancedCallDestinationTest : public YodelTest { subchannel_.reset(); } - OrphanablePtr channel_; + RefCountedPtr channel_; ClientChannel::PickerObservable picker_{nullptr}; RefCountedPtr call_destination_ = MakeRefCounted(); @@ -196,6 +195,44 @@ LOAD_BALANCED_CALL_DESTINATION_TEST(StartCall) { WaitForAllPendingWork(); } +LOAD_BALANCED_CALL_DESTINATION_TEST(StartCallOnDestroyedChannel) { + // Create a call. + auto call = MakeCall(MakeClientInitialMetadata()); + // Client side part of the call: wait for status and expect that it's + // UNAVAILABLE + SpawnTestSeq( + call.initiator, "initiator", + [this, handler = std::move(call.handler), + initiator = call.initiator]() mutable { + destination_under_test().StartCall(handler); + return initiator.PullServerTrailingMetadata(); + }, + [](ServerMetadataHandle md) { + EXPECT_EQ(md->get(GrpcStatusMetadata()).value_or(GRPC_STATUS_UNKNOWN), + GRPC_STATUS_UNAVAILABLE); + return Empty{}; + }); + // Set a picker and wait for at least one pick attempt to prove the call has + // made it to the picker. + auto mock_picker = MakeRefCounted>(); + std::atomic queued_once{false}; + EXPECT_CALL(*mock_picker, Pick) + .WillOnce([&queued_once](LoadBalancingPolicy::PickArgs) { + queued_once.store(true, std::memory_order_relaxed); + return LoadBalancingPolicy::PickResult::Queue{}; + }); + picker().Set(mock_picker); + TickUntil([&queued_once]() -> Poll { + if (queued_once.load(std::memory_order_relaxed)) return Empty{}; + return Pending(); + }); + // Now set the drop picker (as the client channel does at shutdown) which + // should trigger Unavailable to be seen by the client side part of the call. + picker().Set(MakeRefCounted( + absl::UnavailableError("Channel destroyed"))); + WaitForAllPendingWork(); +} + // TODO(roth, ctiller): more tests // - tests for the picker returning queue, fail, and drop results. diff --git a/test/core/end2end/BUILD b/test/core/end2end/BUILD index 66bbb438979..51032c0b1e2 100644 --- a/test/core/end2end/BUILD +++ b/test/core/end2end/BUILD @@ -147,6 +147,7 @@ grpc_cc_library( "//src/core:no_destruct", "//src/core:slice", "//src/core:time", + "//test/core/call:batch_builder", "//test/core/event_engine:event_engine_test_utils", "//test/core/test_util:grpc_test_util", ], diff --git a/test/core/end2end/end2end_test_suites.cc b/test/core/end2end/end2end_test_suites.cc index 35bd844a603..324931e90ce 100644 --- a/test/core/end2end/end2end_test_suites.cc +++ b/test/core/end2end/end2end_test_suites.cc @@ -986,29 +986,22 @@ std::vector DefaultConfigs() { return std::make_unique(); }}, #endif + CoreTestConfiguration { + "ChaoticGoodFullStack", + FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL | + FEATURE_MASK_DOES_NOT_SUPPORT_RETRY | + FEATURE_MASK_DOES_NOT_SUPPORT_WRITE_BUFFERING, + nullptr, + [](const ChannelArgs& /*client_args*/, + const ChannelArgs& /*server_args*/) { + return std::make_unique(); + } + } }; } -std::vector ChaoticGoodFixtures() { - return std::vector{ - CoreTestConfiguration{"ChaoticGoodFullStack", - FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL | - FEATURE_MASK_DOES_NOT_SUPPORT_RETRY | - FEATURE_MASK_DOES_NOT_SUPPORT_WRITE_BUFFERING, - nullptr, - [](const ChannelArgs& /*client_args*/, - const ChannelArgs& /*server_args*/) { - return std::make_unique(); - }}}; -} - std::vector AllConfigs() { - std::vector configs; - if (IsExperimentEnabledInConfiguration(kExperimentIdChaoticGood)) { - configs = ChaoticGoodFixtures(); - } else { - configs = DefaultConfigs(); - } + std::vector configs = DefaultConfigs(); std::sort(configs.begin(), configs.end(), [](const CoreTestConfiguration& a, const CoreTestConfiguration& b) { return strcmp(a.name, b.name) < 0; diff --git a/test/core/end2end/end2end_tests.cc b/test/core/end2end/end2end_tests.cc index 51505c91fd5..9443758ee5c 100644 --- a/test/core/end2end/end2end_tests.cc +++ b/test/core/end2end/end2end_tests.cc @@ -31,7 +31,6 @@ #include #include -#include "src/core/lib/compression/message_compress.h" #include "src/core/lib/config/core_configuration.h" #include "src/core/lib/event_engine/default_event_engine.h" #include "src/core/lib/gprpp/no_destruct.h" @@ -62,24 +61,6 @@ Slice RandomBinarySlice(size_t length) { return Slice::FromCopiedBuffer(output); } -ByteBufferUniquePtr ByteBufferFromSlice(Slice slice) { - return ByteBufferUniquePtr( - grpc_raw_byte_buffer_create(const_cast(&slice.c_slice()), 1), - grpc_byte_buffer_destroy); -} - -namespace { -absl::optional FindInMetadataArray(const grpc_metadata_array& md, - absl::string_view key) { - for (size_t i = 0; i < md.count; i++) { - if (key == StringViewFromSlice(md.metadata[i].key)) { - return std::string(StringViewFromSlice(md.metadata[i].value)); - } - } - return absl::nullopt; -} -} // namespace - void CoreEnd2endTest::SetUp() { CoreConfiguration::Reset(); initialized_ = false; @@ -126,182 +107,6 @@ void CoreEnd2endTest::TearDown() { initialized_ = false; } -absl::optional CoreEnd2endTest::IncomingMetadata::Get( - absl::string_view key) const { - return FindInMetadataArray(*metadata_, key); -} - -grpc_op CoreEnd2endTest::IncomingMetadata::MakeOp() { - grpc_op op; - memset(&op, 0, sizeof(op)); - op.op = GRPC_OP_RECV_INITIAL_METADATA; - op.data.recv_initial_metadata.recv_initial_metadata = metadata_.get(); - return op; -} - -std::string CoreEnd2endTest::IncomingMetadata::GetSuccessfulStateString() { - std::string out = "incoming_metadata: {"; - for (size_t i = 0; i < metadata_->count; i++) { - absl::StrAppend(&out, StringViewFromSlice(metadata_->metadata[i].key), ":", - StringViewFromSlice(metadata_->metadata[i].value), ","); - } - return out + "}"; -} - -std::string CoreEnd2endTest::IncomingMessage::payload() const { - Slice out; - if (payload_->data.raw.compression > GRPC_COMPRESS_NONE) { - grpc_slice_buffer decompressed_buffer; - grpc_slice_buffer_init(&decompressed_buffer); - CHECK(grpc_msg_decompress(payload_->data.raw.compression, - &payload_->data.raw.slice_buffer, - &decompressed_buffer)); - grpc_byte_buffer* rbb = grpc_raw_byte_buffer_create( - decompressed_buffer.slices, decompressed_buffer.count); - grpc_byte_buffer_reader reader; - CHECK(grpc_byte_buffer_reader_init(&reader, rbb)); - out = Slice(grpc_byte_buffer_reader_readall(&reader)); - grpc_byte_buffer_reader_destroy(&reader); - grpc_byte_buffer_destroy(rbb); - grpc_slice_buffer_destroy(&decompressed_buffer); - } else { - grpc_byte_buffer_reader reader; - CHECK(grpc_byte_buffer_reader_init(&reader, payload_)); - out = Slice(grpc_byte_buffer_reader_readall(&reader)); - grpc_byte_buffer_reader_destroy(&reader); - } - return std::string(out.begin(), out.end()); -} - -grpc_op CoreEnd2endTest::IncomingMessage::MakeOp() { - grpc_op op; - memset(&op, 0, sizeof(op)); - op.op = GRPC_OP_RECV_MESSAGE; - op.data.recv_message.recv_message = &payload_; - return op; -} - -absl::optional -CoreEnd2endTest::IncomingStatusOnClient::GetTrailingMetadata( - absl::string_view key) const { - return FindInMetadataArray(data_->trailing_metadata, key); -} - -std::string -CoreEnd2endTest::IncomingStatusOnClient::GetSuccessfulStateString() { - std::string out = absl::StrCat( - "status_on_client: status=", data_->status, - " msg=", data_->status_details.as_string_view(), " trailing_metadata={"); - for (size_t i = 0; i < data_->trailing_metadata.count; i++) { - absl::StrAppend( - &out, StringViewFromSlice(data_->trailing_metadata.metadata[i].key), - ": ", StringViewFromSlice(data_->trailing_metadata.metadata[i].value), - ","); - } - return out + "}"; -} - -std::string CoreEnd2endTest::IncomingMessage::GetSuccessfulStateString() { - if (payload_ == nullptr) return "message: empty"; - return absl::StrCat("message: ", payload().size(), "b uncompressed"); -} - -grpc_op CoreEnd2endTest::IncomingStatusOnClient::MakeOp() { - grpc_op op; - memset(&op, 0, sizeof(op)); - op.op = GRPC_OP_RECV_STATUS_ON_CLIENT; - op.data.recv_status_on_client.trailing_metadata = &data_->trailing_metadata; - op.data.recv_status_on_client.status = &data_->status; - op.data.recv_status_on_client.status_details = - const_cast(&data_->status_details.c_slice()); - op.data.recv_status_on_client.error_string = &data_->error_string; - return op; -} - -grpc_op CoreEnd2endTest::IncomingCloseOnServer::MakeOp() { - grpc_op op; - memset(&op, 0, sizeof(op)); - op.op = GRPC_OP_RECV_CLOSE_ON_SERVER; - op.data.recv_close_on_server.cancelled = &cancelled_; - return op; -} - -CoreEnd2endTest::BatchBuilder& -CoreEnd2endTest::BatchBuilder::SendInitialMetadata( - std::initializer_list> md, - uint32_t flags, absl::optional compression_level) { - auto& v = Make>(); - for (const auto& p : md) { - grpc_metadata m; - m.key = Make(Slice::FromCopiedString(p.first)).c_slice(); - m.value = Make(Slice::FromCopiedString(p.second)).c_slice(); - v.push_back(m); - } - grpc_op op; - memset(&op, 0, sizeof(op)); - op.op = GRPC_OP_SEND_INITIAL_METADATA; - op.flags = flags; - op.data.send_initial_metadata.count = v.size(); - op.data.send_initial_metadata.metadata = v.data(); - if (compression_level.has_value()) { - op.data.send_initial_metadata.maybe_compression_level.is_set = 1; - op.data.send_initial_metadata.maybe_compression_level.level = - compression_level.value(); - } - ops_.push_back(op); - return *this; -} - -CoreEnd2endTest::BatchBuilder& CoreEnd2endTest::BatchBuilder::SendMessage( - Slice payload, uint32_t flags) { - grpc_op op; - memset(&op, 0, sizeof(op)); - op.op = GRPC_OP_SEND_MESSAGE; - op.data.send_message.send_message = - Make(ByteBufferFromSlice(std::move(payload))).get(); - op.flags = flags; - ops_.push_back(op); - return *this; -} - -CoreEnd2endTest::BatchBuilder& -CoreEnd2endTest::BatchBuilder::SendCloseFromClient() { - grpc_op op; - memset(&op, 0, sizeof(op)); - op.op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; - ops_.push_back(op); - return *this; -} - -CoreEnd2endTest::BatchBuilder& -CoreEnd2endTest::BatchBuilder::SendStatusFromServer( - grpc_status_code status, absl::string_view message, - std::initializer_list> md) { - auto& v = Make>(); - for (const auto& p : md) { - grpc_metadata m; - m.key = Make(Slice::FromCopiedString(p.first)).c_slice(); - m.value = Make(Slice::FromCopiedString(p.second)).c_slice(); - v.push_back(m); - } - grpc_op op; - memset(&op, 0, sizeof(op)); - op.op = GRPC_OP_SEND_STATUS_FROM_SERVER; - op.data.send_status_from_server.trailing_metadata_count = v.size(); - op.data.send_status_from_server.trailing_metadata = v.data(); - op.data.send_status_from_server.status = status; - op.data.send_status_from_server.status_details = &Make( - Make(Slice::FromCopiedString(message)).c_slice()); - ops_.push_back(op); - return *this; -} - -CoreEnd2endTest::BatchBuilder::~BatchBuilder() { - grpc_call_error err = grpc_call_start_batch(call_, ops_.data(), ops_.size(), - CqVerifier::tag(tag_), nullptr); - EXPECT_EQ(err, GRPC_CALL_OK) << grpc_call_error_to_string(err); -} - CoreEnd2endTest::Call CoreEnd2endTest::ClientCallBuilder::Create() { if (auto* u = absl::get_if(&call_selector_)) { absl::optional host; @@ -352,8 +157,8 @@ CoreEnd2endTest::IncomingCall::IncomingCall(CoreEnd2endTest& test, void* method, EXPECT_EQ(grpc_server_request_registered_call( test.server(), method, impl_->call.call_ptr(), &impl_->call_details.deadline, &impl_->request_metadata, - message == nullptr ? nullptr : &message->payload_, test.cq(), - test.cq(), CqVerifier::tag(tag)), + message == nullptr ? nullptr : message->raw_payload_ptr(), + test.cq(), test.cq(), CqVerifier::tag(tag)), GRPC_CALL_OK); } diff --git a/test/core/end2end/end2end_tests.h b/test/core/end2end/end2end_tests.h index 4575d432594..3f35888a4f5 100644 --- a/test/core/end2end/end2end_tests.h +++ b/test/core/end2end/end2end_tests.h @@ -1,5 +1,3 @@ -// -// // Copyright 2015 gRPC authors. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,8 +11,6 @@ // 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_TEST_CORE_END2END_END2END_TESTS_H #define GRPC_TEST_CORE_END2END_END2END_TESTS_H @@ -61,6 +57,7 @@ #include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/surface/call_test_only.h" #include "src/core/lib/surface/channel.h" +#include "test/core/call/batch_builder.h" #include "test/core/end2end/cq_verifier.h" #include "test/core/event_engine/event_engine_test_utils.h" #include "test/core/test_util/test_config.h" @@ -106,9 +103,6 @@ class CoreTestFixture { Slice RandomSlice(size_t length); Slice RandomBinarySlice(size_t length); -using ByteBufferUniquePtr = - std::unique_ptr; -ByteBufferUniquePtr ByteBufferFromSlice(Slice slice); struct CoreTestConfiguration { // A descriptive name for this test fixture. @@ -252,236 +246,6 @@ class CoreEnd2endTest : public ::testing::Test { gpr_timespec deadline_ = gpr_inf_future(GPR_CLOCK_REALTIME); }; - // Receiving container for incoming metadata. - class IncomingMetadata final : public CqVerifier::SuccessfulStateString { - public: - IncomingMetadata() = default; - ~IncomingMetadata() { - if (metadata_ != nullptr) grpc_metadata_array_destroy(metadata_.get()); - } - - // Lookup a metadata value by key. - absl::optional Get(absl::string_view key) const; - - // Make a GRPC_RECV_INITIAL_METADATA op - intended for the framework, not - // for tests. - grpc_op MakeOp(); - - std::string GetSuccessfulStateString() override; - - private: - std::unique_ptr metadata_ = - std::make_unique( - grpc_metadata_array{0, 0, nullptr}); - }; - - class IncomingCall; - - // Receiving container for one incoming message. - class IncomingMessage final : public CqVerifier::SuccessfulStateString { - public: - IncomingMessage() = default; - IncomingMessage(const IncomingMessage&) = delete; - IncomingMessage& operator=(const IncomingMessage&) = delete; - ~IncomingMessage() { - if (payload_ != nullptr) grpc_byte_buffer_destroy(payload_); - } - - // Get the payload of the message - concatenated together into a string for - // easy verification. - std::string payload() const; - // Check if the message is the end of the stream. - bool is_end_of_stream() const { return payload_ == nullptr; } - // Get the type of the message. - grpc_byte_buffer_type byte_buffer_type() const { return payload_->type; } - // Get the compression algorithm used for the message. - grpc_compression_algorithm compression() const { - return payload_->data.raw.compression; - } - std::string GetSuccessfulStateString() override; - - // Make a GRPC_OP_RECV_MESSAGE op - intended for the framework, not for - // tests. - grpc_op MakeOp(); - - private: - friend class IncomingCall; - grpc_byte_buffer* payload_ = nullptr; - }; - - // Receiving container for incoming status on the client from the server. - class IncomingStatusOnClient final - : public CqVerifier::SuccessfulStateString { - public: - IncomingStatusOnClient() = default; - IncomingStatusOnClient(const IncomingStatusOnClient&) = delete; - IncomingStatusOnClient& operator=(const IncomingStatusOnClient&) = delete; - IncomingStatusOnClient(IncomingStatusOnClient&& other) noexcept = default; - IncomingStatusOnClient& operator=(IncomingStatusOnClient&& other) noexcept = - default; - ~IncomingStatusOnClient() { - if (data_ != nullptr) { - grpc_metadata_array_destroy(&data_->trailing_metadata); - gpr_free(const_cast(data_->error_string)); - } - } - - // Get the status code. - grpc_status_code status() const { return data_->status; } - // Get the status details. - std::string message() const { - return std::string(data_->status_details.as_string_view()); - } - // Get the error string. - std::string error_string() const { - return data_->error_string == nullptr ? "" : data_->error_string; - } - // Get a trailing metadata value by key. - absl::optional GetTrailingMetadata( - absl::string_view key) const; - - std::string GetSuccessfulStateString() override; - - // Make a GRPC_OP_RECV_STATUS_ON_CLIENT op - intended for the framework, not - // for tests. - grpc_op MakeOp(); - - private: - struct Data { - grpc_metadata_array trailing_metadata{0, 0, nullptr}; - grpc_status_code status; - Slice status_details; - const char* error_string = nullptr; - }; - std::unique_ptr data_ = std::make_unique(); - }; - - // Receiving container for incoming status on the server from the client. - class IncomingCloseOnServer final : public CqVerifier::SuccessfulStateString { - public: - IncomingCloseOnServer() = default; - IncomingCloseOnServer(const IncomingCloseOnServer&) = delete; - IncomingCloseOnServer& operator=(const IncomingCloseOnServer&) = delete; - - // Get the cancellation bit. - bool was_cancelled() const { return cancelled_ != 0; } - - // Make a GRPC_OP_RECV_CLOSE_ON_SERVER op - intended for the framework, not - // for tests. - grpc_op MakeOp(); - - std::string GetSuccessfulStateString() override { - return absl::StrCat("close_on_server: cancelled=", cancelled_); - } - - private: - int cancelled_; - }; - - // Build one batch. Returned from NewBatch (use that to instantiate this!) - // Upon destruction of the BatchBuilder, the batch will be executed with any - // added batches. - class BatchBuilder { - public: - BatchBuilder(grpc_call* call, CoreEnd2endTest* test, int tag) - : call_(call), tag_(tag), cq_verifier_(&test->cq_verifier()) { - cq_verifier_->ClearSuccessfulStateStrings(CqVerifier::tag(tag_)); - } - ~BatchBuilder(); - - BatchBuilder(const BatchBuilder&) = delete; - BatchBuilder& operator=(const BatchBuilder&) = delete; - BatchBuilder(BatchBuilder&&) noexcept = default; - - // Add a GRPC_OP_SEND_INITIAL_METADATA op. - // Optionally specify flags, compression level. - BatchBuilder& SendInitialMetadata( - std::initializer_list> - md, - uint32_t flags = 0, - absl::optional compression_level = - absl::nullopt); - - // Add a GRPC_OP_SEND_MESSAGE op. - BatchBuilder& SendMessage(Slice payload, uint32_t flags = 0); - BatchBuilder& SendMessage(absl::string_view payload, uint32_t flags = 0) { - return SendMessage(Slice::FromCopiedString(payload), flags); - } - - // Add a GRPC_OP_SEND_CLOSE_FROM_CLIENT op. - BatchBuilder& SendCloseFromClient(); - - // Add a GRPC_OP_SEND_STATUS_FROM_SERVER op. - BatchBuilder& SendStatusFromServer( - grpc_status_code status, absl::string_view message, - std::initializer_list> - md); - - // Add a GRPC_OP_RECV_INITIAL_METADATA op. - BatchBuilder& RecvInitialMetadata(IncomingMetadata& md) { - cq_verifier_->AddSuccessfulStateString(CqVerifier::tag(tag_), &md); - ops_.emplace_back(md.MakeOp()); - return *this; - } - - // Add a GRPC_OP_RECV_MESSAGE op. - BatchBuilder& RecvMessage(IncomingMessage& msg) { - cq_verifier_->AddSuccessfulStateString(CqVerifier::tag(tag_), &msg); - ops_.emplace_back(msg.MakeOp()); - return *this; - } - - // Add a GRPC_OP_RECV_STATUS_ON_CLIENT op. - BatchBuilder& RecvStatusOnClient(IncomingStatusOnClient& status) { - cq_verifier_->AddSuccessfulStateString(CqVerifier::tag(tag_), &status); - ops_.emplace_back(status.MakeOp()); - return *this; - } - - // Add a GRPC_OP_RECV_CLOSE_ON_SERVER op. - BatchBuilder& RecvCloseOnServer(IncomingCloseOnServer& close) { - cq_verifier_->AddSuccessfulStateString(CqVerifier::tag(tag_), &close); - ops_.emplace_back(close.MakeOp()); - return *this; - } - - private: - // We need to track little bits of memory up until the batch is executed. - // One Thing is one such block of memory. - // We specialize it with SpecificThing to track a specific type of memory. - // These get placed on things_ and deleted when the batch is executed. - class Thing { - public: - virtual ~Thing() = default; - }; - template - class SpecificThing final : public Thing { - public: - template - explicit SpecificThing(Args&&... args) - : t_(std::forward(args)...) {} - SpecificThing() = default; - - T& get() { return t_; } - - private: - T t_; - }; - - // Make a thing of type T, and return a reference to it. - template - T& Make(Args&&... args) { - things_.emplace_back(new SpecificThing(std::forward(args)...)); - return static_cast*>(things_.back().get())->get(); - } - - grpc_call* call_; - const int tag_; - std::vector ops_; - std::vector> things_; - CqVerifier* const cq_verifier_; - }; - // Wrapper around a grpc_call. // Instantiated by ClientCallBuilder via NewClientCall for client calls. // Wrapped by IncomingCall for server calls. @@ -498,7 +262,9 @@ class CoreEnd2endTest : public ::testing::Test { } // Construct a batch with a tag - upon destruction of the BatchBuilder the // operation will occur. - BatchBuilder NewBatch(int tag) { return BatchBuilder(call_, test_, tag); } + BatchBuilder NewBatch(int tag) { + return BatchBuilder(call_, &test_->cq_verifier(), tag); + } // Cancel the call void Cancel() { grpc_call_cancel(call_, nullptr); } void CancelWithStatus(grpc_status_code status, const char* message) { @@ -636,7 +402,6 @@ class CoreEnd2endTest : public ::testing::Test { } // Pull in CqVerifier types for ergonomics - // TODO(ctiller): evaluate just dropping CqVerifier and folding it in here. using ExpectedResult = CqVerifier::ExpectedResult; using Maybe = CqVerifier::Maybe; using PerformAction = CqVerifier::PerformAction; @@ -913,7 +678,7 @@ class CoreEnd2endTestRegistry { if (g_is_fuzzing_core_e2e_tests) GTEST_SKIP() << "Skipping test for fuzzing" #define SKIP_IF_CHAOTIC_GOOD() \ - if (IsChaoticGoodEnabled()) { \ + if (absl::StrContains(GetParam()->name, "ChaoticGood")) { \ GTEST_SKIP() << "Disabled for initial chaotic good testing"; \ } diff --git a/test/core/end2end/tests/bad_ping.cc b/test/core/end2end/tests/bad_ping.cc index 51a799549b2..edd8760f82b 100644 --- a/test/core/end2end/tests/bad_ping.cc +++ b/test/core/end2end/tests/bad_ping.cc @@ -43,8 +43,8 @@ CORE_END2END_TEST(RetryHttp2Test, BadPing) { .Set(GRPC_ARG_HTTP2_MAX_PING_STRIKES, MAX_PING_STRIKES) .Set(GRPC_ARG_HTTP2_BDP_PROBE, 0)); auto c = NewClientCall("/foo").Timeout(Duration::Seconds(10)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .SendInitialMetadata({}) .SendCloseFromClient() @@ -67,7 +67,7 @@ CORE_END2END_TEST(RetryHttp2Test, BadPing) { } Step(); } - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(102) .SendInitialMetadata({}) .SendStatusFromServer(GRPC_STATUS_UNIMPLEMENTED, "xyz", {}) @@ -101,8 +101,8 @@ CORE_END2END_TEST(RetryHttp2Test, PingsWithoutData) { .Set(GRPC_ARG_HTTP2_MAX_PING_STRIKES, MAX_PING_STRIKES) .Set(GRPC_ARG_HTTP2_BDP_PROBE, 0)); auto c = NewClientCall("/foo").Timeout(Duration::Seconds(10)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .SendInitialMetadata({}) .SendCloseFromClient() @@ -122,7 +122,7 @@ CORE_END2END_TEST(RetryHttp2Test, PingsWithoutData) { } Step(); } - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(102) .SendInitialMetadata({}) .SendStatusFromServer(GRPC_STATUS_UNIMPLEMENTED, "xyz", {}) diff --git a/test/core/end2end/tests/binary_metadata.cc b/test/core/end2end/tests/binary_metadata.cc index 4e4123fd369..e4032f73036 100644 --- a/test/core/end2end/tests/binary_metadata.cc +++ b/test/core/end2end/tests/binary_metadata.cc @@ -48,9 +48,9 @@ static void BinaryMetadata(CoreEnd2endTest& test, bool server_true_binary, auto status_string = RandomBinarySlice(256); auto c = test.NewClientCall("/foo").Timeout(Duration::Minutes(1)).Create(); - CoreEnd2endTest::IncomingMetadata server_initial_md; - CoreEnd2endTest::IncomingMessage server_message; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_md; + IncomingMessage server_message; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata({ {"key1-bin", key1_payload.as_string_view()}, @@ -64,7 +64,7 @@ static void BinaryMetadata(CoreEnd2endTest& test, bool server_true_binary, auto s = test.RequestCall(101); test.Expect(101, true); test.Step(); - CoreEnd2endTest::IncomingMessage client_message; + IncomingMessage client_message; s.NewBatch(102) .SendInitialMetadata({ {"key3-bin", key3_payload.as_string_view()}, @@ -73,7 +73,7 @@ static void BinaryMetadata(CoreEnd2endTest& test, bool server_true_binary, .RecvMessage(client_message); test.Expect(102, true); test.Step(); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(103) .RecvCloseOnServer(client_close) .SendMessage(response_payload.Ref()) diff --git a/test/core/end2end/tests/call_creds.cc b/test/core/end2end/tests/call_creds.cc index 2b078a1152d..fd89930a967 100644 --- a/test/core/end2end/tests/call_creds.cc +++ b/test/core/end2end/tests/call_creds.cc @@ -73,9 +73,9 @@ void TestRequestResponseWithPayloadAndCallCreds(CoreEnd2endTest& test, } EXPECT_NE(creds, nullptr); c.SetCredentials(creds); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage server_message; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingMessage server_message; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata({}) .SendMessage("hello world") @@ -90,11 +90,11 @@ void TestRequestResponseWithPayloadAndCallCreds(CoreEnd2endTest& test, PrintAuthContext(true, c.GetAuthContext().get()); // Cannot set creds on the server call object. EXPECT_NE(grpc_call_set_credentials(s.c_call(), nullptr), GRPC_CALL_OK); - CoreEnd2endTest::IncomingMessage client_message; + IncomingMessage client_message; s.NewBatch(102).SendInitialMetadata({}).RecvMessage(client_message); test.Expect(102, true); test.Step(); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(103) .RecvCloseOnServer(client_close) .SendMessage("hello you") @@ -138,9 +138,9 @@ void TestRequestResponseWithPayloadAndOverriddenCallCreds( overridden_fake_md_value); } c.SetCredentials(creds); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage server_message; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingMessage server_message; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata({}) .SendMessage("hello world") @@ -155,11 +155,11 @@ void TestRequestResponseWithPayloadAndOverriddenCallCreds( PrintAuthContext(true, c.GetAuthContext().get()); // Cannot set creds on the server call object. EXPECT_NE(grpc_call_set_credentials(s.c_call(), nullptr), GRPC_CALL_OK); - CoreEnd2endTest::IncomingMessage client_message; + IncomingMessage client_message; s.NewBatch(102).SendInitialMetadata({}).RecvMessage(client_message); test.Expect(102, true); test.Step(); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(103) .RecvCloseOnServer(client_close) .SendMessage("hello you") @@ -197,9 +197,9 @@ void TestRequestResponseWithPayloadAndDeletedCallCreds( EXPECT_NE(creds, nullptr); c.SetCredentials(creds); c.SetCredentials(nullptr); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage server_message; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingMessage server_message; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata({}) .SendMessage("hello world") @@ -214,11 +214,11 @@ void TestRequestResponseWithPayloadAndDeletedCallCreds( PrintAuthContext(true, c.GetAuthContext().get()); // Cannot set creds on the server call object. EXPECT_NE(grpc_call_set_credentials(s.c_call(), nullptr), GRPC_CALL_OK); - CoreEnd2endTest::IncomingMessage client_message; + IncomingMessage client_message; s.NewBatch(102).SendInitialMetadata({}).RecvMessage(client_message); test.Expect(102, true); test.Step(); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(103) .RecvCloseOnServer(client_close) .SendMessage("hello you") @@ -248,9 +248,9 @@ CORE_END2END_TEST(PerCallCredsOnInsecureTest, grpc_md_only_test_credentials_create(fake_md_key, fake_md_value); EXPECT_NE(creds, nullptr); c.SetCredentials(creds); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage server_message; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingMessage server_message; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata({}) .SendMessage("hello world") @@ -313,9 +313,9 @@ CORE_END2END_TEST(PerCallCredsOnInsecureTest, FailToSendCallCreds) { creds = grpc_google_iam_credentials_create(iam_token, iam_selector, nullptr); EXPECT_NE(creds, nullptr); c.SetCredentials(creds); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage server_message; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingMessage server_message; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata({}) .SendMessage("hello world") diff --git a/test/core/end2end/tests/call_host_override.cc b/test/core/end2end/tests/call_host_override.cc index e56b1deb231..66b70c042af 100644 --- a/test/core/end2end/tests/call_host_override.cc +++ b/test/core/end2end/tests/call_host_override.cc @@ -40,8 +40,8 @@ CORE_END2END_TEST(CoreClientChannelTest, CallHostOverride) { .Host("foo.test.google.fr:1234") .Create(); EXPECT_NE(c.GetPeer(), absl::nullopt); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .SendInitialMetadata({}) .SendCloseFromClient() @@ -52,7 +52,7 @@ CORE_END2END_TEST(CoreClientChannelTest, CallHostOverride) { Step(); EXPECT_NE(s.GetPeer(), absl::nullopt); EXPECT_NE(c.GetPeer(), absl::nullopt); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(102) .SendInitialMetadata({}) .SendStatusFromServer(GRPC_STATUS_UNIMPLEMENTED, "xyz", {}) diff --git a/test/core/end2end/tests/cancel_after_accept.cc b/test/core/end2end/tests/cancel_after_accept.cc index 3dcd451aaad..e79e664332a 100644 --- a/test/core/end2end/tests/cancel_after_accept.cc +++ b/test/core/end2end/tests/cancel_after_accept.cc @@ -38,9 +38,9 @@ void CancelAfterAccept(CoreEnd2endTest& test, std::unique_ptr cancellation_mode, Duration timeout) { auto c = test.NewClientCall("/service/method").Timeout(timeout).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage server_message; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingMessage server_message; c.NewBatch(1) .RecvStatusOnClient(server_status) .SendInitialMetadata({}) @@ -50,8 +50,8 @@ void CancelAfterAccept(CoreEnd2endTest& test, auto s = test.RequestCall(2); test.Expect(2, true); test.Step(); - CoreEnd2endTest::IncomingMessage client_message; - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingMessage client_message; + IncomingCloseOnServer client_close; s.NewBatch(3) .RecvMessage(client_message) .SendInitialMetadata({}) diff --git a/test/core/end2end/tests/cancel_after_client_done.cc b/test/core/end2end/tests/cancel_after_client_done.cc index 5dd19ec9e1c..4248b8b9327 100644 --- a/test/core/end2end/tests/cancel_after_client_done.cc +++ b/test/core/end2end/tests/cancel_after_client_done.cc @@ -36,9 +36,9 @@ void CancelAfterClientDone( auto c = test.NewClientCall("/service/method") .Timeout(Duration::Seconds(5)) .Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage server_message; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingMessage server_message; c.NewBatch(1) .RecvStatusOnClient(server_status) .SendInitialMetadata({}) @@ -49,8 +49,8 @@ void CancelAfterClientDone( auto s = test.RequestCall(2); test.Expect(2, true); test.Step(); - CoreEnd2endTest::IncomingMessage client_message; - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingMessage client_message; + IncomingCloseOnServer client_close; s.NewBatch(3) .RecvMessage(client_message) .SendInitialMetadata({}) diff --git a/test/core/end2end/tests/cancel_after_invoke.cc b/test/core/end2end/tests/cancel_after_invoke.cc index 64eacc7ca59..e5dec969c87 100644 --- a/test/core/end2end/tests/cancel_after_invoke.cc +++ b/test/core/end2end/tests/cancel_after_invoke.cc @@ -43,9 +43,9 @@ void CancelAfterInvoke6(CoreEnd2endTest& test, // shutdown, the test would not timeout and fail. test.InitServer(ChannelArgs().Set(GRPC_ARG_PING_TIMEOUT_MS, 5000)); auto c = test.NewClientCall("/service/method").Timeout(timeout).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage server_message; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingMessage server_message; c.NewBatch(1) .RecvStatusOnClient(server_status) .RecvInitialMetadata(server_initial_metadata) @@ -69,8 +69,8 @@ void CancelAfterInvoke5(CoreEnd2endTest& test, // shutdown, the test would not timeout and fail. test.InitServer(ChannelArgs().Set(GRPC_ARG_PING_TIMEOUT_MS, 5000)); auto c = test.NewClientCall("/service/method").Timeout(timeout).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .RecvStatusOnClient(server_status) .RecvInitialMetadata(server_initial_metadata) @@ -93,8 +93,8 @@ void CancelAfterInvoke4(CoreEnd2endTest& test, // shutdown, the test would not timeout and fail. test.InitServer(ChannelArgs().Set(GRPC_ARG_PING_TIMEOUT_MS, 5000)); auto c = test.NewClientCall("/service/method").Timeout(timeout).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .RecvStatusOnClient(server_status) .RecvInitialMetadata(server_initial_metadata) @@ -116,8 +116,8 @@ void CancelAfterInvoke3(CoreEnd2endTest& test, // shutdown, the test would not timeout and fail. test.InitServer(ChannelArgs().Set(GRPC_ARG_PING_TIMEOUT_MS, 5000)); auto c = test.NewClientCall("/service/method").Timeout(timeout).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .RecvStatusOnClient(server_status) .RecvInitialMetadata(server_initial_metadata) diff --git a/test/core/end2end/tests/cancel_after_round_trip.cc b/test/core/end2end/tests/cancel_after_round_trip.cc index afc6505f81e..fbc54a0f51e 100644 --- a/test/core/end2end/tests/cancel_after_round_trip.cc +++ b/test/core/end2end/tests/cancel_after_round_trip.cc @@ -38,8 +38,8 @@ void CancelAfterRoundTrip(CoreEnd2endTest& test, std::unique_ptr mode, Duration timeout) { auto c = test.NewClientCall("/service/method").Timeout(timeout).Create(); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage server_message; + IncomingMetadata server_initial_metadata; + IncomingMessage server_message; c.NewBatch(1) .SendInitialMetadata({}) .SendMessage(RandomSlice(100)) @@ -48,7 +48,7 @@ void CancelAfterRoundTrip(CoreEnd2endTest& test, auto s = test.RequestCall(101); test.Expect(101, true); test.Step(); - CoreEnd2endTest::IncomingMessage client_message; + IncomingMessage client_message; s.NewBatch(102) .RecvMessage(client_message) .SendInitialMetadata({}) @@ -56,11 +56,11 @@ void CancelAfterRoundTrip(CoreEnd2endTest& test, test.Expect(102, true); test.Expect(1, true); test.Step(); - CoreEnd2endTest::IncomingMessage server_message_2; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMessage server_message_2; + IncomingStatusOnClient server_status; c.NewBatch(2).RecvMessage(server_message_2).RecvStatusOnClient(server_status); mode->Apply(c); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(103).RecvCloseOnServer(client_close).SendMessage(RandomSlice(100)); test.Expect(2, true); test.Expect(103, true); diff --git a/test/core/end2end/tests/cancel_before_invoke.cc b/test/core/end2end/tests/cancel_before_invoke.cc index 38432d190f9..6c5e07d6d63 100644 --- a/test/core/end2end/tests/cancel_before_invoke.cc +++ b/test/core/end2end/tests/cancel_before_invoke.cc @@ -29,9 +29,9 @@ namespace grpc_core { CORE_END2END_TEST(CoreEnd2endTest, CancelBeforeInvoke6) { auto c = NewClientCall("/service/method").Create(); c.Cancel(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage server_message; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingMessage server_message; c.NewBatch(1) .RecvStatusOnClient(server_status) .SendInitialMetadata({}) @@ -47,8 +47,8 @@ CORE_END2END_TEST(CoreEnd2endTest, CancelBeforeInvoke6) { CORE_END2END_TEST(CoreEnd2endTest, CancelBeforeInvoke5) { auto c = NewClientCall("/service/method").Create(); c.Cancel(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .RecvStatusOnClient(server_status) .SendInitialMetadata({}) @@ -63,7 +63,7 @@ CORE_END2END_TEST(CoreEnd2endTest, CancelBeforeInvoke5) { CORE_END2END_TEST(CoreEnd2endTest, CancelBeforeInvoke4) { auto c = NewClientCall("/service/method").Create(); c.Cancel(); - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingStatusOnClient server_status; c.NewBatch(1) .RecvStatusOnClient(server_status) .SendInitialMetadata({}) @@ -77,7 +77,7 @@ CORE_END2END_TEST(CoreEnd2endTest, CancelBeforeInvoke4) { CORE_END2END_TEST(CoreEnd2endTest, CancelBeforeInvoke3) { auto c = NewClientCall("/service/method").Create(); c.Cancel(); - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingStatusOnClient server_status; c.NewBatch(1) .RecvStatusOnClient(server_status) .SendInitialMetadata({}) @@ -90,7 +90,7 @@ CORE_END2END_TEST(CoreEnd2endTest, CancelBeforeInvoke3) { CORE_END2END_TEST(CoreEnd2endTest, CancelBeforeInvoke2) { auto c = NewClientCall("/service/method").Create(); c.Cancel(); - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingStatusOnClient server_status; c.NewBatch(1).RecvStatusOnClient(server_status).SendInitialMetadata({}); Expect(1, AnyStatus()); Step(); @@ -100,7 +100,7 @@ CORE_END2END_TEST(CoreEnd2endTest, CancelBeforeInvoke2) { CORE_END2END_TEST(CoreEnd2endTest, CancelBeforeInvoke1) { auto c = NewClientCall("/service/method").Create(); c.Cancel(); - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingStatusOnClient server_status; c.NewBatch(1).RecvStatusOnClient(server_status); Expect(1, AnyStatus()); Step(); diff --git a/test/core/end2end/tests/cancel_with_status.cc b/test/core/end2end/tests/cancel_with_status.cc index 2af5d2e8498..e1dae672c16 100644 --- a/test/core/end2end/tests/cancel_with_status.cc +++ b/test/core/end2end/tests/cancel_with_status.cc @@ -33,7 +33,7 @@ namespace { CORE_END2END_TEST(CoreEnd2endTest, CancelWithStatus1) { auto c = NewClientCall("/foo").Timeout(Duration::Minutes(1)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingStatusOnClient server_status; c.NewBatch(1).RecvStatusOnClient(server_status); char* dynamic_string = gpr_strdup("xyz"); c.CancelWithStatus(GRPC_STATUS_UNIMPLEMENTED, dynamic_string); @@ -48,8 +48,8 @@ CORE_END2END_TEST(CoreEnd2endTest, CancelWithStatus1) { CORE_END2END_TEST(CoreEnd2endTest, CancelWithStatus2) { auto c = NewClientCall("/foo").Timeout(Duration::Minutes(1)).Create(); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; c.NewBatch(1) .RecvStatusOnClient(server_status) .RecvInitialMetadata(server_initial_metadata); @@ -71,8 +71,8 @@ CORE_END2END_TEST(CoreEnd2endTest, CancelWithStatus3) { // shutdown, the test would not timeout and fail. InitServer(ChannelArgs().Set(GRPC_ARG_PING_TIMEOUT_MS, 5000)); auto c = NewClientCall("/foo").Timeout(Duration::Minutes(1)).Create(); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; c.NewBatch(1) .RecvStatusOnClient(server_status) .RecvInitialMetadata(server_initial_metadata) @@ -95,8 +95,8 @@ CORE_END2END_TEST(CoreEnd2endTest, CancelWithStatus4) { // shutdown, the test would not timeout and fail. InitServer(ChannelArgs().Set(GRPC_ARG_PING_TIMEOUT_MS, 5000)); auto c = NewClientCall("/foo").Timeout(Duration::Minutes(1)).Create(); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; c.NewBatch(1) .RecvStatusOnClient(server_status) .RecvInitialMetadata(server_initial_metadata) diff --git a/test/core/end2end/tests/channelz.cc b/test/core/end2end/tests/channelz.cc index 570ba3e9670..519c544fad9 100644 --- a/test/core/end2end/tests/channelz.cc +++ b/test/core/end2end/tests/channelz.cc @@ -40,8 +40,8 @@ namespace { void RunOneRequest(CoreEnd2endTest& test, bool request_is_success) { auto c = test.NewClientCall("/foo").Timeout(Duration::Seconds(5)).Create(); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata({}) .SendCloseFromClient() @@ -50,7 +50,7 @@ void RunOneRequest(CoreEnd2endTest& test, bool request_is_success) { auto s = test.RequestCall(101); test.Expect(101, true); test.Step(); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(102) .SendInitialMetadata({}) .SendStatusFromServer( diff --git a/test/core/end2end/tests/client_streaming.cc b/test/core/end2end/tests/client_streaming.cc index c1c284bd005..e01d63d8f60 100644 --- a/test/core/end2end/tests/client_streaming.cc +++ b/test/core/end2end/tests/client_streaming.cc @@ -35,7 +35,7 @@ namespace { void ClientStreaming(CoreEnd2endTest& test, int messages) { auto c = test.NewClientCall("/foo").Timeout(Duration::Seconds(30)).Create(); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingMetadata server_initial_metadata; c.NewBatch(1).SendInitialMetadata({}).RecvInitialMetadata( server_initial_metadata); auto s = test.RequestCall(100); @@ -48,7 +48,7 @@ void ClientStreaming(CoreEnd2endTest& test, int messages) { // Client writes bunch of messages and server reads them for (int i = 0; i < messages; i++) { c.NewBatch(2).SendMessage("hello world"); - CoreEnd2endTest::IncomingMessage client_message; + IncomingMessage client_message; s.NewBatch(102).RecvMessage(client_message); test.Expect(2, true); test.Expect(102, true); @@ -69,7 +69,7 @@ void ClientStreaming(CoreEnd2endTest& test, int messages) { test.Step(); // Client sends close and requests status - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingStatusOnClient server_status; c.NewBatch(4).SendCloseFromClient().RecvStatusOnClient(server_status); test.Expect(4, true); test.Step(); diff --git a/test/core/end2end/tests/compressed_payload.cc b/test/core/end2end/tests/compressed_payload.cc index bb8cfe68148..dbe9c350696 100644 --- a/test/core/end2end/tests/compressed_payload.cc +++ b/test/core/end2end/tests/compressed_payload.cc @@ -91,8 +91,8 @@ class TestConfigurator { Init(); auto c = test_.NewClientCall("/foo").Timeout(Duration::Minutes(1)).Create(); auto s = test_.RequestCall(101); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata({}) .SendMessage(std::string(1024, 'x')) @@ -102,9 +102,9 @@ class TestConfigurator { test_.Expect(101, true); test_.Expect(1, true); test_.Step(); - CoreEnd2endTest::IncomingMessage client_message; + IncomingMessage client_message; s.NewBatch(102).SendInitialMetadata({}).RecvMessage(client_message); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; test_.Expect(102, false); s.NewBatch(103).RecvCloseOnServer(client_close); test_.Expect(103, true); @@ -126,8 +126,8 @@ class TestConfigurator { Init(); auto c = test_.NewClientCall("/foo").Timeout(Duration::Seconds(30)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .SendInitialMetadata(client_init_metadata) .RecvInitialMetadata(server_initial_metadata) @@ -136,13 +136,13 @@ class TestConfigurator { test_.Expect(100, true); test_.Step(); EXPECT_TRUE(s.GetEncodingsAcceptedByPeer().all()); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(101).SendInitialMetadata({}).RecvCloseOnServer(client_close); for (int i = 0; i < 2; i++) { c.NewBatch(2).SendMessage(std::string(1024, 'x'), client_send_flags_bitmask); test_.Expect(2, true); - CoreEnd2endTest::IncomingMessage client_message; + IncomingMessage client_message; s.NewBatch(102).RecvMessage(client_message); test_.Expect(102, true); test_.Step(); @@ -150,7 +150,7 @@ class TestConfigurator { EXPECT_EQ(client_message.payload(), std::string(1024, 'x')); EXPECT_EQ(client_message.compression(), expected_algorithm_from_client_); s.NewBatch(103).SendMessage(std::string(1024, 'y')); - CoreEnd2endTest::IncomingMessage server_message; + IncomingMessage server_message; c.NewBatch(3).RecvMessage(server_message); test_.Expect(103, true); test_.Expect(3, true); @@ -178,8 +178,8 @@ class TestConfigurator { test_.NewClientCall("/foo").Timeout(Duration::Seconds(30)).Create(); c.NewBatch(2).SendMessage(std::string(1024, 'x')); test_.Expect(2, true); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .SendInitialMetadata({}) .RecvInitialMetadata(server_initial_metadata) @@ -188,14 +188,14 @@ class TestConfigurator { test_.Expect(100, true); test_.Step(); EXPECT_TRUE(s.GetEncodingsAcceptedByPeer().all()); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(101).SendInitialMetadata({}).RecvCloseOnServer(client_close); for (int i = 0; i < 2; i++) { if (i > 0) { c.NewBatch(2).SendMessage(std::string(1024, 'x')); test_.Expect(2, true); } - CoreEnd2endTest::IncomingMessage client_message; + IncomingMessage client_message; s.NewBatch(102).RecvMessage(client_message); test_.Expect(102, true); test_.Step(); @@ -203,7 +203,7 @@ class TestConfigurator { EXPECT_EQ(client_message.payload(), std::string(1024, 'x')); EXPECT_EQ(client_message.compression(), expected_algorithm_from_client_); s.NewBatch(103).SendMessage(std::string(1024, 'y')); - CoreEnd2endTest::IncomingMessage server_message; + IncomingMessage server_message; c.NewBatch(3).RecvMessage(server_message); test_.Expect(103, true); test_.Expect(3, true); @@ -228,8 +228,8 @@ class TestConfigurator { void RequestWithServerLevel(grpc_compression_level server_compression_level) { Init(); auto c = test_.NewClientCall("/foo").Timeout(Duration::Minutes(1)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .SendInitialMetadata({}) .RecvInitialMetadata(server_initial_metadata) @@ -238,14 +238,14 @@ class TestConfigurator { test_.Expect(100, true); test_.Step(); EXPECT_TRUE(s.GetEncodingsAcceptedByPeer().all()); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(101) .SendInitialMetadata({}, 0, server_compression_level) .RecvCloseOnServer(client_close); for (int i = 0; i < 2; i++) { c.NewBatch(2).SendMessage(std::string(1024, 'x')); test_.Expect(2, true); - CoreEnd2endTest::IncomingMessage client_message; + IncomingMessage client_message; s.NewBatch(102).RecvMessage(client_message); test_.Expect(102, true); test_.Step(); @@ -253,7 +253,7 @@ class TestConfigurator { EXPECT_EQ(client_message.payload(), std::string(1024, 'x')); EXPECT_EQ(client_message.compression(), expected_algorithm_from_client_); s.NewBatch(103).SendMessage(std::string(1024, 'y')); - CoreEnd2endTest::IncomingMessage server_message; + IncomingMessage server_message; c.NewBatch(3).RecvMessage(server_message); test_.Expect(103, true); test_.Expect(3, true); diff --git a/test/core/end2end/tests/disappearing_server.cc b/test/core/end2end/tests/disappearing_server.cc index 5b65e20eb57..a4deadafede 100644 --- a/test/core/end2end/tests/disappearing_server.cc +++ b/test/core/end2end/tests/disappearing_server.cc @@ -35,8 +35,8 @@ static void OneRequestAndShutdownServer(CoreEnd2endTest& test) { auto c = test.NewClientCall("/service/method") .Timeout(Duration::Seconds(30)) .Create(); - CoreEnd2endTest::IncomingMetadata server_initial_md; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_md; + IncomingStatusOnClient server_status; LOG(ERROR) << "Start initial batch"; c.NewBatch(1) .SendInitialMetadata({}) @@ -47,7 +47,7 @@ static void OneRequestAndShutdownServer(CoreEnd2endTest& test) { test.Expect(101, true); test.Step(); test.ShutdownServerAndNotify(1000); - CoreEnd2endTest::IncomingCloseOnServer client_closed; + IncomingCloseOnServer client_closed; s.NewBatch(102) .SendInitialMetadata({}) .SendStatusFromServer(GRPC_STATUS_UNIMPLEMENTED, "xyz", {}) diff --git a/test/core/end2end/tests/filter_causes_close.cc b/test/core/end2end/tests/filter_causes_close.cc index dc7fdafc667..0e96e1213d7 100644 --- a/test/core/end2end/tests/filter_causes_close.cc +++ b/test/core/end2end/tests/filter_causes_close.cc @@ -28,6 +28,7 @@ #include "src/core/lib/channel/channel_fwd.h" #include "src/core/lib/channel/channel_stack.h" +#include "src/core/lib/channel/promise_based_filter.h" #include "src/core/lib/config/core_configuration.h" #include "src/core/lib/gprpp/debug_location.h" #include "src/core/lib/gprpp/status_helper.h" @@ -48,85 +49,48 @@ namespace { // Test filter - always closes incoming requests // -typedef struct { - grpc_closure* recv_im_ready; -} call_data; - -typedef struct { - uint8_t unused; -} channel_data; - -void recv_im_ready(void* arg, grpc_error_handle error) { - grpc_call_element* elem = static_cast(arg); - call_data* calld = static_cast(elem->call_data); - Closure::Run( - DEBUG_LOCATION, calld->recv_im_ready, - grpc_error_set_int(GRPC_ERROR_CREATE_REFERENCING( - "Failure that's not preventable.", &error, 1), - StatusIntProperty::kRpcStatus, - GRPC_STATUS_PERMISSION_DENIED)); -} - -void start_transport_stream_op_batch(grpc_call_element* elem, - grpc_transport_stream_op_batch* op) { - call_data* calld = static_cast(elem->call_data); - if (op->recv_initial_metadata) { - calld->recv_im_ready = - op->payload->recv_initial_metadata.recv_initial_metadata_ready; - op->payload->recv_initial_metadata.recv_initial_metadata_ready = - GRPC_CLOSURE_CREATE(recv_im_ready, elem, grpc_schedule_on_exec_ctx); +class TestFilter : public ImplementChannelFilter { + public: + static const grpc_channel_filter kFilter; + static absl::StatusOr> Create( + const ChannelArgs&, ChannelFilter::Args) { + return std::make_unique(); } - grpc_call_next_op(elem, op); -} - -grpc_error_handle init_call_elem(grpc_call_element* /*elem*/, - const grpc_call_element_args* /*args*/) { - return absl::OkStatus(); -} - -void destroy_call_elem(grpc_call_element* /*elem*/, - const grpc_call_final_info* /*final_info*/, - grpc_closure* /*ignored*/) {} - -grpc_error_handle init_channel_elem(grpc_channel_element* /*elem*/, - grpc_channel_element_args* /*args*/) { - return absl::OkStatus(); -} - -void destroy_channel_elem(grpc_channel_element* /*elem*/) {} -const grpc_channel_filter test_filter = { - start_transport_stream_op_batch, - [](grpc_channel_element*, CallArgs, - NextPromiseFactory) -> ArenaPromise { - return Immediate(ServerMetadataFromStatus( - absl::PermissionDeniedError("Failure that's not preventable."))); - }, - [](grpc_channel_element*, CallSpineInterface*) { - Crash("Should never be called"); - }, - grpc_channel_next_op, - sizeof(call_data), - init_call_elem, - grpc_call_stack_ignore_set_pollset_or_pollset_set, - destroy_call_elem, - sizeof(channel_data), - init_channel_elem, - grpc_channel_stack_no_post_init, - destroy_channel_elem, - grpc_channel_next_get_info, - "filter_causes_close"}; + class Call { + public: + absl::Status OnClientInitialMetadata(ClientMetadata&) { + return grpc_error_set_int( + absl::PermissionDeniedError("Failure that's not preventable."), + StatusIntProperty::kRpcStatus, GRPC_STATUS_PERMISSION_DENIED); + } + static const NoInterceptor OnServerInitialMetadata; + static const NoInterceptor OnServerTrailingMetadata; + static const NoInterceptor OnClientToServerMessage; + static const NoInterceptor OnClientToServerHalfClose; + static const NoInterceptor OnServerToClientMessage; + static const NoInterceptor OnFinalize; + }; +}; + +const NoInterceptor TestFilter::Call::OnServerInitialMetadata; +const NoInterceptor TestFilter::Call::OnServerTrailingMetadata; +const NoInterceptor TestFilter::Call::OnClientToServerMessage; +const NoInterceptor TestFilter::Call::OnClientToServerHalfClose; +const NoInterceptor TestFilter::Call::OnServerToClientMessage; +const NoInterceptor TestFilter::Call::OnFinalize; + +const grpc_channel_filter TestFilter::kFilter = + MakePromiseBasedFilter( + "filter_causes_close"); CORE_END2END_TEST(CoreEnd2endTest, FilterCausesClose) { - if (IsPromiseBasedClientCallEnabled()) { - GTEST_SKIP() << "disabled for promises until callv3 is further along"; - } CoreConfiguration::RegisterBuilder([](CoreConfiguration::Builder* builder) { - builder->channel_init()->RegisterFilter(GRPC_SERVER_CHANNEL, &test_filter); + builder->channel_init()->RegisterFilter(GRPC_SERVER_CHANNEL); }); auto c = NewClientCall("/foo").Timeout(Duration::Seconds(5)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .SendInitialMetadata({}) .SendMessage("foo") diff --git a/test/core/end2end/tests/filter_init_fails.cc b/test/core/end2end/tests/filter_init_fails.cc index 025d43fa6b6..4d1a03a5645 100644 --- a/test/core/end2end/tests/filter_init_fails.cc +++ b/test/core/end2end/tests/filter_init_fails.cc @@ -74,13 +74,7 @@ grpc_error_handle init_channel_elem(grpc_channel_element* /*elem*/, void destroy_channel_elem(grpc_channel_element* /*elem*/) {} const grpc_channel_filter test_filter = { - grpc_call_next_op, - [](grpc_channel_element*, CallArgs, - NextPromiseFactory) -> ArenaPromise { - return Immediate(ServerMetadataFromStatus( - absl::PermissionDeniedError("access denied"))); - }, - nullptr, grpc_channel_next_op, 0, init_call_elem, + grpc_call_next_op, grpc_channel_next_op, 0, init_call_elem, grpc_call_stack_ignore_set_pollset_or_pollset_set, destroy_call_elem, 0, init_channel_elem, grpc_channel_stack_no_post_init, destroy_channel_elem, grpc_channel_next_get_info, @@ -106,8 +100,8 @@ CORE_END2END_TEST(CoreEnd2endTest, DISABLED_ServerFilterChannelInitFails) { InitClient(ChannelArgs()); InitServer(ChannelArgs().Set("channel_init_fails", true)); auto c = NewClientCall("/foo").Timeout(Duration::Seconds(5)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .SendInitialMetadata({}) .SendMessage("hello") @@ -131,8 +125,8 @@ CORE_END2END_TEST(CoreEnd2endTest, ServerFilterCallInitFails) { RegisterFilter(GRPC_SERVER_CHANNEL); auto c = NewClientCall("/foo").Timeout(Duration::Seconds(5)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .SendInitialMetadata({}) .SendMessage("hello") @@ -153,8 +147,8 @@ CORE_END2END_TEST(CoreEnd2endTest, DISABLED_ClientFilterChannelInitFails) { InitServer(ChannelArgs()); InitClient(ChannelArgs().Set("channel_init_fails", true)); auto c = NewClientCall("/foo").Timeout(Duration::Seconds(5)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .SendInitialMetadata({}) .SendMessage("hello") @@ -173,9 +167,9 @@ CORE_END2END_TEST(CoreEnd2endTest, ClientFilterCallInitFails) { RegisterFilter(GRPC_CLIENT_CHANNEL); RegisterFilter(GRPC_CLIENT_DIRECT_CHANNEL); auto c = NewClientCall("/foo").Timeout(Duration::Seconds(5)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage server_message; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingMessage server_message; c.NewBatch(1) .SendInitialMetadata({}) .SendMessage("hello") @@ -195,9 +189,9 @@ CORE_END2END_TEST(CoreClientChannelTest, InitServer(ChannelArgs()); InitClient(ChannelArgs().Set("channel_init_fails", true)); auto c = NewClientCall("/foo").Timeout(Duration::Seconds(5)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage server_message; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingMessage server_message; c.NewBatch(1) .SendInitialMetadata({}) .SendMessage("hello") @@ -211,9 +205,9 @@ CORE_END2END_TEST(CoreClientChannelTest, // client_channel.c than subsequent calls on the same channel, and we need to // test both.) auto c2 = NewClientCall("/foo").Timeout(Duration::Seconds(5)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status2; - CoreEnd2endTest::IncomingMetadata server_initial_metadata2; - CoreEnd2endTest::IncomingMessage server_message2; + IncomingStatusOnClient server_status2; + IncomingMetadata server_initial_metadata2; + IncomingMessage server_message2; c2.NewBatch(2) .SendInitialMetadata({}) .SendMessage("hi again") @@ -229,9 +223,9 @@ CORE_END2END_TEST(CoreClientChannelTest, SubchannelFilterCallInitFails) { SKIP_IF_CHAOTIC_GOOD(); RegisterFilter(GRPC_CLIENT_SUBCHANNEL); auto c = NewClientCall("/foo").Timeout(Duration::Seconds(5)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage server_message; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingMessage server_message; c.NewBatch(1) .SendInitialMetadata({}) .SendMessage("hello") @@ -246,9 +240,9 @@ CORE_END2END_TEST(CoreClientChannelTest, SubchannelFilterCallInitFails) { // client_channel.c than subsequent calls on the same channel, and we need to // test both.) auto c2 = NewClientCall("/foo").Timeout(Duration::Seconds(5)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status2; - CoreEnd2endTest::IncomingMetadata server_initial_metadata2; - CoreEnd2endTest::IncomingMessage server_message2; + IncomingStatusOnClient server_status2; + IncomingMetadata server_initial_metadata2; + IncomingMessage server_message2; c2.NewBatch(2) .SendInitialMetadata({}) .SendMessage("hi again") diff --git a/test/core/end2end/tests/filtered_metadata.cc b/test/core/end2end/tests/filtered_metadata.cc index f5b94af0a5f..a16afba692a 100644 --- a/test/core/end2end/tests/filtered_metadata.cc +++ b/test/core/end2end/tests/filtered_metadata.cc @@ -36,8 +36,8 @@ void TestRequestResponseWithMetadataToBeFiltered( absl::string_view filter_md_value) { auto c = test.NewClientCall("/foo").Timeout(Duration::Seconds(30)).Create(); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata( {{"key1", "val1"}, {filtered_md_key, filter_md_value}}) @@ -55,7 +55,7 @@ void TestRequestResponseWithMetadataToBeFiltered( test.Expect(102, true); test.Step(); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(103) .RecvCloseOnServer(client_close) .SendStatusFromServer(GRPC_STATUS_OK, "xyz", {}); diff --git a/test/core/end2end/tests/graceful_server_shutdown.cc b/test/core/end2end/tests/graceful_server_shutdown.cc index 4bfc209aa74..1cd6fccb2f4 100644 --- a/test/core/end2end/tests/graceful_server_shutdown.cc +++ b/test/core/end2end/tests/graceful_server_shutdown.cc @@ -30,8 +30,8 @@ namespace { CORE_END2END_TEST(Http2Test, GracefulServerShutdown) { auto c = NewClientCall("/foo").Timeout(Duration::Seconds(10)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .SendInitialMetadata({}) .SendCloseFromClient() @@ -43,7 +43,7 @@ CORE_END2END_TEST(Http2Test, GracefulServerShutdown) { // shutdown and destroy the server ShutdownServerAndNotify(200); Step(); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(102) .SendInitialMetadata({}) .SendStatusFromServer(GRPC_STATUS_UNIMPLEMENTED, "xyz", {}) diff --git a/test/core/end2end/tests/grpc_authz.cc b/test/core/end2end/tests/grpc_authz.cc index 1c184423188..fa8c54ccec1 100644 --- a/test/core/end2end/tests/grpc_authz.cc +++ b/test/core/end2end/tests/grpc_authz.cc @@ -37,8 +37,8 @@ namespace { void TestAllowAuthorizedRequest(CoreEnd2endTest& test) { auto c = test.NewClientCall("/foo").Timeout(Duration::Seconds(5)).Create(); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata({}) .SendCloseFromClient() @@ -47,7 +47,7 @@ void TestAllowAuthorizedRequest(CoreEnd2endTest& test) { auto s = test.RequestCall(101); test.Expect(101, true); test.Step(); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(102) .SendInitialMetadata({}) .SendStatusFromServer(GRPC_STATUS_OK, "xyz", {}) @@ -60,8 +60,8 @@ void TestAllowAuthorizedRequest(CoreEnd2endTest& test) { void TestDenyUnauthorizedRequest(CoreEnd2endTest& test) { auto c = test.NewClientCall("/foo").Timeout(Duration::Seconds(5)).Create(); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata({}) .SendCloseFromClient() diff --git a/test/core/end2end/tests/high_initial_seqno.cc b/test/core/end2end/tests/high_initial_seqno.cc index ac5e0eacc3d..03228d34d37 100644 --- a/test/core/end2end/tests/high_initial_seqno.cc +++ b/test/core/end2end/tests/high_initial_seqno.cc @@ -32,8 +32,8 @@ namespace { void SimpleRequest(CoreEnd2endTest& test) { auto c = test.NewClientCall("/foo").Timeout(Duration::Minutes(1)).Create(); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata({}) .SendCloseFromClient() @@ -42,7 +42,7 @@ void SimpleRequest(CoreEnd2endTest& test) { auto s = test.RequestCall(101); test.Expect(101, true); test.Step(); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(102) .SendInitialMetadata({}) .SendStatusFromServer(GRPC_STATUS_UNIMPLEMENTED, "xyz", {}) diff --git a/test/core/end2end/tests/hpack_size.cc b/test/core/end2end/tests/hpack_size.cc index 465de045e03..bbd783aa29f 100644 --- a/test/core/end2end/tests/hpack_size.cc +++ b/test/core/end2end/tests/hpack_size.cc @@ -97,8 +97,8 @@ void SimpleRequestBody(CoreEnd2endTest& test, size_t index) { auto method = absl::StrCat("/", hobbit.first, ".", hobbit.second, "/", dragon); auto c = test.NewClientCall(method).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .SendInitialMetadata({ {"hobbit-first-name", (*hobbits)[index % hobbits->size()].first}, @@ -111,7 +111,7 @@ void SimpleRequestBody(CoreEnd2endTest& test, size_t index) { auto s = test.RequestCall(101); test.Expect(101, true); test.Step(); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(102) .SendInitialMetadata({}) .SendStatusFromServer(GRPC_STATUS_UNIMPLEMENTED, dragon, {}) diff --git a/test/core/end2end/tests/http2_stats.cc b/test/core/end2end/tests/http2_stats.cc index c146d9ec832..dfd1e029e01 100644 --- a/test/core/end2end/tests/http2_stats.cc +++ b/test/core/end2end/tests/http2_stats.cc @@ -203,11 +203,11 @@ CORE_END2END_TEST(Http2FullstackSingleHopTest, StreamStats) { std::make_shared()); auto send_from_client = RandomSlice(10); auto send_from_server = RandomSlice(20); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage server_message; - CoreEnd2endTest::IncomingMessage client_message; - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingMessage server_message; + IncomingMessage client_message; + IncomingCloseOnServer client_close; { auto c = NewClientCall("/foo").Timeout(Duration::Minutes(5)).Create(); c.NewBatch(1) diff --git a/test/core/end2end/tests/invoke_large_request.cc b/test/core/end2end/tests/invoke_large_request.cc index f7c5eb7cbe6..283ec5cb7ae 100644 --- a/test/core/end2end/tests/invoke_large_request.cc +++ b/test/core/end2end/tests/invoke_large_request.cc @@ -42,9 +42,9 @@ CORE_END2END_TEST(Http2SingleHopTest, InvokeLargeRequest) { InitClient( ChannelArgs().Set(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, kMessageSize)); auto c = NewClientCall("/foo").Timeout(Duration::Minutes(5)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage server_message; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingMessage server_message; c.NewBatch(1) .SendInitialMetadata({}) .SendMessage(send_from_client.Ref()) @@ -55,11 +55,11 @@ CORE_END2END_TEST(Http2SingleHopTest, InvokeLargeRequest) { auto s = RequestCall(101); Expect(101, true); Step(Duration::Minutes(1)); - CoreEnd2endTest::IncomingMessage client_message; + IncomingMessage client_message; s.NewBatch(102).SendInitialMetadata({}).RecvMessage(client_message); Expect(102, true); Step(Duration::Minutes(1)); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(103) .SendStatusFromServer(GRPC_STATUS_UNIMPLEMENTED, "xyz", {}) .SendMessage(send_from_server.Ref()) diff --git a/test/core/end2end/tests/large_metadata.cc b/test/core/end2end/tests/large_metadata.cc index 499e3ff6886..eb0da4d38db 100644 --- a/test/core/end2end/tests/large_metadata.cc +++ b/test/core/end2end/tests/large_metadata.cc @@ -58,11 +58,10 @@ class LargeMetadataTest { } private: - CoreEnd2endTest::IncomingStatusOnClient PerformOneRequest( - const size_t metadata_size) { + IncomingStatusOnClient PerformOneRequest(const size_t metadata_size) { auto c = test_.NewClientCall("/foo").Timeout(Duration::Seconds(5)).Create(); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata({}) .SendCloseFromClient() @@ -72,7 +71,7 @@ class LargeMetadataTest { test_.Expect(101, true); test_.Step(); // Server: send metadata of size `metadata_size`. - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(102) .SendInitialMetadata({{"key", std::string(metadata_size, 'a')}}) .RecvCloseOnServer(client_close) diff --git a/test/core/end2end/tests/max_concurrent_streams.cc b/test/core/end2end/tests/max_concurrent_streams.cc index 17c7117527c..badbec90b1c 100644 --- a/test/core/end2end/tests/max_concurrent_streams.cc +++ b/test/core/end2end/tests/max_concurrent_streams.cc @@ -33,8 +33,8 @@ namespace { void SimpleRequestBody(CoreEnd2endTest& test) { auto c = test.NewClientCall("/foo").Timeout(Duration::Seconds(5)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .SendInitialMetadata({}) .SendCloseFromClient() @@ -43,7 +43,7 @@ void SimpleRequestBody(CoreEnd2endTest& test) { auto s = test.RequestCall(101); test.Expect(101, true); test.Step(); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(102) .SendInitialMetadata({}) .SendStatusFromServer(GRPC_STATUS_UNIMPLEMENTED, "xyz", {}) diff --git a/test/core/end2end/tests/max_connection_age.cc b/test/core/end2end/tests/max_connection_age.cc index 963a4a65d49..f2d0d88a51b 100644 --- a/test/core/end2end/tests/max_connection_age.cc +++ b/test/core/end2end/tests/max_connection_age.cc @@ -66,8 +66,8 @@ CORE_END2END_TEST(Http2Test, MaxAgeForciblyClose) { static_cast(MAX_CONNECTION_AGE_MS * MAX_CONNECTION_AGE_JITTER_MULTIPLIER) + MAX_CONNECTION_AGE_GRACE_MS + IMMEDIATE_SHUTDOWN_GRACE_TIME_MS)); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata({}) .SendCloseFromClient() @@ -88,7 +88,7 @@ CORE_END2END_TEST(Http2Test, MaxAgeForciblyClose) { Expect(1, true); Step(); EXPECT_LT(Timestamp::Now(), expect_shutdown_time); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(102) .SendInitialMetadata({}) .SendStatusFromServer(GRPC_STATUS_UNIMPLEMENTED, "xyz", {}) @@ -123,8 +123,8 @@ CORE_END2END_TEST(Http2Test, MaxAgeGracefullyClose) { auto c = NewClientCall("/foo") .Timeout(Duration::Seconds(CALL_DEADLINE_S)) .Create(); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata({}) .SendCloseFromClient() @@ -143,7 +143,7 @@ CORE_END2END_TEST(Http2Test, MaxAgeGracefullyClose) { // The connection is shutting down gracefully. In-progress rpc should not be // closed, hence the completion queue should see nothing here. Step(Duration::Seconds(CQ_MAX_CONNECTION_AGE_GRACE_WAIT_TIME_S)); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(102) .SendInitialMetadata({}) .SendStatusFromServer(GRPC_STATUS_UNIMPLEMENTED, "xyz", {}) diff --git a/test/core/end2end/tests/max_connection_idle.cc b/test/core/end2end/tests/max_connection_idle.cc index 1fd5285a2be..466e72ff5b5 100644 --- a/test/core/end2end/tests/max_connection_idle.cc +++ b/test/core/end2end/tests/max_connection_idle.cc @@ -36,8 +36,8 @@ namespace { bool SimpleRequestBody(CoreEnd2endTest& test) { auto c = test.NewClientCall("/foo").Timeout(Duration::Minutes(1)).Create(); EXPECT_NE(c.GetPeer(), absl::nullopt); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata( {}, GRPC_INITIAL_METADATA_WAIT_FOR_READY | @@ -67,7 +67,7 @@ bool SimpleRequestBody(CoreEnd2endTest& test) { EXPECT_TRUE(saw_request_at_server); EXPECT_NE(s.GetPeer(), absl::nullopt); EXPECT_NE(c.GetPeer(), absl::nullopt); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(102) .SendInitialMetadata({}) .SendStatusFromServer(GRPC_STATUS_UNIMPLEMENTED, "xyz", {}) diff --git a/test/core/end2end/tests/max_message_length.cc b/test/core/end2end/tests/max_message_length.cc index f57963dc725..cedbf499377 100644 --- a/test/core/end2end/tests/max_message_length.cc +++ b/test/core/end2end/tests/max_message_length.cc @@ -34,8 +34,8 @@ namespace { void TestMaxMessageLengthOnClientOnRequest(CoreEnd2endTest& test) { auto c = test.NewClientCall("/service/method").Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .SendInitialMetadata({}) .SendMessage("hello world") @@ -51,8 +51,8 @@ void TestMaxMessageLengthOnClientOnRequest(CoreEnd2endTest& test) { void TestMaxMessageLengthOnServerOnRequest(CoreEnd2endTest& test) { auto c = test.NewClientCall("/service/method").Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .SendInitialMetadata({}) .SendMessage("hello world") @@ -62,8 +62,8 @@ void TestMaxMessageLengthOnServerOnRequest(CoreEnd2endTest& test) { auto s = test.RequestCall(101); test.Expect(101, true); test.Step(); - CoreEnd2endTest::IncomingCloseOnServer client_close; - CoreEnd2endTest::IncomingMessage client_message; + IncomingCloseOnServer client_close; + IncomingMessage client_message; s.NewBatch(102).RecvCloseOnServer(client_close).RecvMessage(client_message); test.Expect(102, true); test.Expect(1, true); @@ -77,9 +77,9 @@ void TestMaxMessageLengthOnServerOnRequest(CoreEnd2endTest& test) { void TestMaxMessageLengthOnClientOnResponse(CoreEnd2endTest& test) { auto c = test.NewClientCall("/service/method").Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage server_message; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingMessage server_message; c.NewBatch(1) .SendInitialMetadata({}) .SendCloseFromClient() @@ -89,7 +89,7 @@ void TestMaxMessageLengthOnClientOnResponse(CoreEnd2endTest& test) { auto s = test.RequestCall(101); test.Expect(101, true); test.Step(); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(102) .SendInitialMetadata({}) .RecvCloseOnServer(client_close) @@ -106,9 +106,9 @@ void TestMaxMessageLengthOnClientOnResponse(CoreEnd2endTest& test) { void TestMaxMessageLengthOnServerOnResponse(CoreEnd2endTest& test) { auto c = test.NewClientCall("/service/method").Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage server_message; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingMessage server_message; c.NewBatch(1) .SendInitialMetadata({}) .SendCloseFromClient() @@ -118,7 +118,7 @@ void TestMaxMessageLengthOnServerOnResponse(CoreEnd2endTest& test) { auto s = test.RequestCall(101); test.Expect(101, true); test.Step(); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(102) .SendInitialMetadata({}) .RecvCloseOnServer(client_close) diff --git a/test/core/end2end/tests/negative_deadline.cc b/test/core/end2end/tests/negative_deadline.cc index dc418784048..92c7aa2f120 100644 --- a/test/core/end2end/tests/negative_deadline.cc +++ b/test/core/end2end/tests/negative_deadline.cc @@ -31,8 +31,8 @@ namespace { CORE_END2END_TEST(CoreDeadlineTest, NegativeDeadline) { auto c = NewClientCall("/service/method").Timeout(Duration::Seconds(-1)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .RecvStatusOnClient(server_status) .RecvInitialMetadata(server_initial_metadata) diff --git a/test/core/end2end/tests/no_logging.cc b/test/core/end2end/tests/no_logging.cc index c9f0b99af9d..4235b02a759 100644 --- a/test/core/end2end/tests/no_logging.cc +++ b/test/core/end2end/tests/no_logging.cc @@ -113,8 +113,8 @@ std::atomic Verifier::g_log_func_(gpr_default_log); void SimpleRequest(CoreEnd2endTest& test) { auto c = test.NewClientCall("/foo").Timeout(Duration::Seconds(5)).Create(); EXPECT_NE(c.GetPeer(), absl::nullopt); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata({}) .SendCloseFromClient() @@ -125,7 +125,7 @@ void SimpleRequest(CoreEnd2endTest& test) { test.Step(); EXPECT_NE(c.GetPeer(), absl::nullopt); EXPECT_NE(s.GetPeer(), absl::nullopt); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(102) .SendInitialMetadata({}) .SendStatusFromServer(GRPC_STATUS_UNIMPLEMENTED, "xyz", {}) diff --git a/test/core/end2end/tests/payload.cc b/test/core/end2end/tests/payload.cc index 6bcb041a7aa..06cd8a7b78e 100644 --- a/test/core/end2end/tests/payload.cc +++ b/test/core/end2end/tests/payload.cc @@ -38,9 +38,9 @@ void RequestResponseWithPayload(CoreEnd2endTest& test) { auto c = test.NewClientCall("/foo").Timeout(Duration::Seconds(60)).Create(); - CoreEnd2endTest::IncomingMetadata server_initial_md; - CoreEnd2endTest::IncomingMessage server_message; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_md; + IncomingMessage server_message; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata({}) .SendMessage(request_slice.Ref()) @@ -53,12 +53,12 @@ void RequestResponseWithPayload(CoreEnd2endTest& test) { test.Expect(101, true); test.Step(); - CoreEnd2endTest::IncomingMessage client_message; + IncomingMessage client_message; s.NewBatch(102).SendInitialMetadata({}).RecvMessage(client_message); test.Expect(102, true); test.Step(); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(103) .RecvCloseOnServer(client_close) .SendMessage(response_slice.Ref()) diff --git a/test/core/end2end/tests/ping_pong_streaming.cc b/test/core/end2end/tests/ping_pong_streaming.cc index 1bec19445b3..3538e89d5fb 100644 --- a/test/core/end2end/tests/ping_pong_streaming.cc +++ b/test/core/end2end/tests/ping_pong_streaming.cc @@ -30,8 +30,8 @@ void PingPongStreaming(CoreEnd2endTest& test, int num_messages) { auto request_slice = RandomSlice(20); auto response_slice = RandomSlice(15); auto c = test.NewClientCall("/foo").Timeout(Duration::Seconds(5)).Create(); - CoreEnd2endTest::IncomingMetadata server_initial_md; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_md; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata({}) .RecvInitialMetadata(server_initial_md) @@ -39,12 +39,12 @@ void PingPongStreaming(CoreEnd2endTest& test, int num_messages) { auto s = test.RequestCall(100); test.Expect(100, true); test.Step(); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(101).SendInitialMetadata({}).RecvCloseOnServer(client_close); for (int i = 0; i < num_messages; i++) { - CoreEnd2endTest::IncomingMessage server_message; + IncomingMessage server_message; c.NewBatch(2).SendMessage(request_slice.Ref()).RecvMessage(server_message); - CoreEnd2endTest::IncomingMessage client_message; + IncomingMessage client_message; s.NewBatch(102).RecvMessage(client_message); test.Expect(102, true); test.Step(); diff --git a/test/core/end2end/tests/registered_call.cc b/test/core/end2end/tests/registered_call.cc index b0c3a9273fb..1b2db49211c 100644 --- a/test/core/end2end/tests/registered_call.cc +++ b/test/core/end2end/tests/registered_call.cc @@ -29,8 +29,8 @@ namespace { void SimpleRequestBody(CoreEnd2endTest& test, CoreEnd2endTest::RegisteredCall rc) { auto c = test.NewClientCall(rc).Timeout(Duration::Seconds(5)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .SendInitialMetadata({}) .SendCloseFromClient() @@ -39,7 +39,7 @@ void SimpleRequestBody(CoreEnd2endTest& test, auto s = test.RequestCall(101); test.Expect(101, true); test.Step(); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(102) .SendInitialMetadata({}) .SendStatusFromServer(GRPC_STATUS_UNIMPLEMENTED, "xyz", {}) diff --git a/test/core/end2end/tests/retry_cancel_during_delay.cc b/test/core/end2end/tests/retry_cancel_during_delay.cc index 5538d29f7eb..3c825dabc97 100644 --- a/test/core/end2end/tests/retry_cancel_during_delay.cc +++ b/test/core/end2end/tests/retry_cancel_during_delay.cc @@ -60,9 +60,9 @@ void TestRetryCancelDuringDelay( .Create(); EXPECT_NE(c.GetPeer(), absl::nullopt); // Client starts a batch with all 6 ops. - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage server_message; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingMessage server_message; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata({}) .SendMessage("foo") @@ -75,7 +75,7 @@ void TestRetryCancelDuringDelay( test.Step(); EXPECT_NE(s.GetPeer(), absl::nullopt); EXPECT_NE(c.GetPeer(), absl::nullopt); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(102) .SendInitialMetadata({}) .SendStatusFromServer(GRPC_STATUS_ABORTED, "xyz", {}) diff --git a/test/core/end2end/tests/retry_cancel_with_multiple_send_batches.cc b/test/core/end2end/tests/retry_cancel_with_multiple_send_batches.cc index d94cb0beb0e..1ee77a489fc 100644 --- a/test/core/end2end/tests/retry_cancel_with_multiple_send_batches.cc +++ b/test/core/end2end/tests/retry_cancel_with_multiple_send_batches.cc @@ -86,9 +86,9 @@ void TestRetryCancelWithMultipleSendBatches( // Start a batch containing send_trailing_metadata. c.NewBatch(3).SendCloseFromClient(); // Start a batch containing recv ops. - CoreEnd2endTest::IncomingMessage server_message; - CoreEnd2endTest::IncomingMetadata server_incoming_metadata; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMessage server_message; + IncomingMetadata server_incoming_metadata; + IncomingStatusOnClient server_status; c.NewBatch(4) .RecvInitialMetadata(server_incoming_metadata) .RecvMessage(server_message) @@ -162,8 +162,6 @@ class FailSendOpsFilter { grpc_channel_filter FailSendOpsFilter::kFilterVtable = { CallData::StartTransportStreamOpBatch, - nullptr, - nullptr, grpc_channel_next_op, sizeof(CallData), CallData::Init, diff --git a/test/core/end2end/tests/retry_cancellation.cc b/test/core/end2end/tests/retry_cancellation.cc index 5944f2b8b70..37000c08bf9 100644 --- a/test/core/end2end/tests/retry_cancellation.cc +++ b/test/core/end2end/tests/retry_cancellation.cc @@ -58,9 +58,9 @@ void TestRetryCancellation(CoreEnd2endTest& test, .Create(); EXPECT_NE(c.GetPeer(), absl::nullopt); // Client starts a batch with all 6 ops. - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage server_message; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingMessage server_message; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata({}) .SendMessage("foo") @@ -74,7 +74,7 @@ void TestRetryCancellation(CoreEnd2endTest& test, test.Step(); EXPECT_NE(s->GetPeer(), absl::nullopt); EXPECT_NE(c.GetPeer(), absl::nullopt); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s->NewBatch(102) .SendInitialMetadata({}) .SendStatusFromServer(GRPC_STATUS_ABORTED, "xyz", {}) diff --git a/test/core/end2end/tests/retry_recv_message_replay.cc b/test/core/end2end/tests/retry_recv_message_replay.cc index befb2391dde..902b52800dd 100644 --- a/test/core/end2end/tests/retry_recv_message_replay.cc +++ b/test/core/end2end/tests/retry_recv_message_replay.cc @@ -108,8 +108,6 @@ class FailFirstSendOpFilter { grpc_channel_filter FailFirstSendOpFilter::kFilterVtable = { CallData::StartTransportStreamOpBatch, - nullptr, - nullptr, grpc_channel_next_op, sizeof(CallData), CallData::Init, diff --git a/test/core/end2end/tests/retry_recv_trailing_metadata_error.cc b/test/core/end2end/tests/retry_recv_trailing_metadata_error.cc index 7a43114ec3a..ec3f3b8ede7 100644 --- a/test/core/end2end/tests/retry_recv_trailing_metadata_error.cc +++ b/test/core/end2end/tests/retry_recv_trailing_metadata_error.cc @@ -103,8 +103,6 @@ class InjectStatusFilter { grpc_channel_filter InjectStatusFilter::kFilterVtable = { CallData::StartTransportStreamOpBatch, - nullptr, - nullptr, grpc_channel_next_op, sizeof(CallData), CallData::Init, diff --git a/test/core/end2end/tests/retry_send_op_fails.cc b/test/core/end2end/tests/retry_send_op_fails.cc index 2fdc3818694..840525ef57f 100644 --- a/test/core/end2end/tests/retry_send_op_fails.cc +++ b/test/core/end2end/tests/retry_send_op_fails.cc @@ -109,8 +109,6 @@ class FailFirstCallFilter { grpc_channel_filter FailFirstCallFilter::kFilterVtable = { CallData::StartTransportStreamOpBatch, - nullptr, - nullptr, grpc_channel_next_op, sizeof(CallData), CallData::Init, diff --git a/test/core/end2end/tests/retry_too_many_attempts.cc b/test/core/end2end/tests/retry_too_many_attempts.cc index a51a9abb439..90cea14dd77 100644 --- a/test/core/end2end/tests/retry_too_many_attempts.cc +++ b/test/core/end2end/tests/retry_too_many_attempts.cc @@ -55,9 +55,9 @@ CORE_END2END_TEST(RetryTest, RetryTooManyAttempts) { auto c = NewClientCall("/service/method").Timeout(Duration::Seconds(5)).Create(); EXPECT_NE(c.GetPeer(), absl::nullopt); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage server_message; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingMessage server_message; c.NewBatch(1) .SendInitialMetadata({}) .SendMessage("foo") @@ -70,7 +70,7 @@ CORE_END2END_TEST(RetryTest, RetryTooManyAttempts) { Step(); EXPECT_NE(s.GetPeer(), absl::nullopt); EXPECT_NE(c.GetPeer(), absl::nullopt); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(102) .SendInitialMetadata({}) .SendStatusFromServer(GRPC_STATUS_ABORTED, "xyz", {}) @@ -83,7 +83,7 @@ CORE_END2END_TEST(RetryTest, RetryTooManyAttempts) { Step(); EXPECT_NE(s2.GetPeer(), absl::nullopt); EXPECT_NE(c.GetPeer(), absl::nullopt); - CoreEnd2endTest::IncomingCloseOnServer client_close2; + IncomingCloseOnServer client_close2; s2.NewBatch(202) .SendInitialMetadata({}) .SendStatusFromServer(GRPC_STATUS_ABORTED, "xyz", {}) diff --git a/test/core/end2end/tests/retry_transparent_goaway.cc b/test/core/end2end/tests/retry_transparent_goaway.cc index 091a800f210..ef3c9561c58 100644 --- a/test/core/end2end/tests/retry_transparent_goaway.cc +++ b/test/core/end2end/tests/retry_transparent_goaway.cc @@ -115,8 +115,6 @@ class FailFirstCallFilter { grpc_channel_filter FailFirstCallFilter::kFilterVtable = { CallData::StartTransportStreamOpBatch, - nullptr, - nullptr, grpc_channel_next_op, sizeof(CallData), CallData::Init, @@ -148,9 +146,9 @@ CORE_END2END_TEST(RetryTest, TransparentGoaway) { .SendMessage("foo") .SendCloseFromClient(); // Start a batch containing recv ops. - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage server_message; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingMessage server_message; c.NewBatch(2) .RecvInitialMetadata(server_initial_metadata) .RecvMessage(server_message) @@ -163,12 +161,12 @@ CORE_END2END_TEST(RetryTest, TransparentGoaway) { Expect(101, true); Step(); // Server receives the request. - CoreEnd2endTest::IncomingMessage client_message; + IncomingMessage client_message; s.NewBatch(102).RecvMessage(client_message); Expect(102, true); Step(); // Server sends a response with status OK. - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(103) .RecvCloseOnServer(client_close) .SendInitialMetadata({}) diff --git a/test/core/end2end/tests/retry_transparent_not_sent_on_wire.cc b/test/core/end2end/tests/retry_transparent_not_sent_on_wire.cc index 05bf6c1ac12..735be66f6e9 100644 --- a/test/core/end2end/tests/retry_transparent_not_sent_on_wire.cc +++ b/test/core/end2end/tests/retry_transparent_not_sent_on_wire.cc @@ -114,8 +114,6 @@ class FailFirstTenCallsFilter { grpc_channel_filter FailFirstTenCallsFilter::kFilterVtable = { CallData::StartTransportStreamOpBatch, - nullptr, - nullptr, grpc_channel_next_op, sizeof(CallData), CallData::Init, diff --git a/test/core/end2end/tests/server_finishes_request.cc b/test/core/end2end/tests/server_finishes_request.cc index 5d27facf228..6061207fd4c 100644 --- a/test/core/end2end/tests/server_finishes_request.cc +++ b/test/core/end2end/tests/server_finishes_request.cc @@ -31,8 +31,8 @@ namespace { CORE_END2END_TEST(CoreEnd2endTest, ServerFinishesRequest) { auto c = NewClientCall("/foo").Timeout(Duration::Seconds(5)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .SendInitialMetadata({}) .RecvInitialMetadata(server_initial_metadata) @@ -43,7 +43,7 @@ CORE_END2END_TEST(CoreEnd2endTest, ServerFinishesRequest) { Expect(101, true); Step(); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(102) .SendInitialMetadata({}) .SendStatusFromServer(GRPC_STATUS_OK, "xyz", {}) diff --git a/test/core/end2end/tests/server_streaming.cc b/test/core/end2end/tests/server_streaming.cc index b6fd6f30511..f1397b8e9d4 100644 --- a/test/core/end2end/tests/server_streaming.cc +++ b/test/core/end2end/tests/server_streaming.cc @@ -36,8 +36,8 @@ namespace { // writing, and expects to get the status after the messages. void ServerStreaming(CoreEnd2endTest& test, int num_messages) { auto c = test.NewClientCall("/foo").Timeout(Duration::Minutes(1)).Create(); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata({}) .RecvInitialMetadata(server_initial_metadata) @@ -61,7 +61,7 @@ void ServerStreaming(CoreEnd2endTest& test, int num_messages) { test.Step(); } // Server sends status - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(104) .SendStatusFromServer(GRPC_STATUS_UNIMPLEMENTED, "xyz", {}) .RecvCloseOnServer(client_close); @@ -75,7 +75,7 @@ void ServerStreaming(CoreEnd2endTest& test, int num_messages) { // Client keeps reading messages till it gets the status int num_messages_received = 0; while (true) { - CoreEnd2endTest::IncomingMessage server_message; + IncomingMessage server_message; c.NewBatch(102).RecvMessage(server_message); test.Expect(1, CqVerifier::Maybe{&seen_status}); test.Expect(102, true); diff --git a/test/core/end2end/tests/shutdown_finishes_calls.cc b/test/core/end2end/tests/shutdown_finishes_calls.cc index c59e9d24c8d..18e19ce3b49 100644 --- a/test/core/end2end/tests/shutdown_finishes_calls.cc +++ b/test/core/end2end/tests/shutdown_finishes_calls.cc @@ -35,8 +35,8 @@ CORE_END2END_TEST(CoreEnd2endTest, EarlyServerShutdownFinishesInflightCalls) { SKIP_IF_FUZZING(); auto c = NewClientCall("/foo").Timeout(Duration::Seconds(5)).Create(); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata({}) .SendCloseFromClient() @@ -45,7 +45,7 @@ CORE_END2END_TEST(CoreEnd2endTest, EarlyServerShutdownFinishesInflightCalls) { auto s = RequestCall(101); Expect(101, true); Step(); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(102).RecvCloseOnServer(client_close); // Make sure we don't shutdown the server while HTTP/2 PING frames are still diff --git a/test/core/end2end/tests/simple_metadata.cc b/test/core/end2end/tests/simple_metadata.cc index 0fbfc3c685e..93893c85118 100644 --- a/test/core/end2end/tests/simple_metadata.cc +++ b/test/core/end2end/tests/simple_metadata.cc @@ -30,9 +30,9 @@ namespace { CORE_END2END_TEST(CoreEnd2endTest, SimpleMetadata) { auto c = NewClientCall("/foo").Timeout(Duration::Minutes(1)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage server_message; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingMessage server_message; c.NewBatch(1) .SendInitialMetadata({{"key1", "val1"}, {"key2", "val2"}}) .SendMessage("hello world") @@ -43,13 +43,13 @@ CORE_END2END_TEST(CoreEnd2endTest, SimpleMetadata) { auto s = RequestCall(101); Expect(101, true); Step(); - CoreEnd2endTest::IncomingMessage client_message; + IncomingMessage client_message; s.NewBatch(102) .SendInitialMetadata({{"key3", "val3"}, {"key4", "val4"}}) .RecvMessage(client_message); Expect(102, true); Step(); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(103) .RecvCloseOnServer(client_close) .SendMessage("hello you") diff --git a/test/core/end2end/tests/simple_request.cc b/test/core/end2end/tests/simple_request.cc index cd49842b8af..a68816ec78c 100644 --- a/test/core/end2end/tests/simple_request.cc +++ b/test/core/end2end/tests/simple_request.cc @@ -51,8 +51,8 @@ void SimpleRequestBody(CoreEnd2endTest& test) { auto before = global_stats().Collect(); auto c = test.NewClientCall("/foo").Timeout(Duration::Minutes(1)).Create(); EXPECT_NE(c.GetPeer(), absl::nullopt); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .SendInitialMetadata({}) .SendCloseFromClient() @@ -65,7 +65,7 @@ void SimpleRequestBody(CoreEnd2endTest& test) { CheckPeer(*s.GetPeer()); EXPECT_NE(c.GetPeer(), absl::nullopt); CheckPeer(*c.GetPeer()); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(102) .SendInitialMetadata({}) .SendStatusFromServer(GRPC_STATUS_UNIMPLEMENTED, "xyz", {}) diff --git a/test/core/end2end/tests/streaming_error_response.cc b/test/core/end2end/tests/streaming_error_response.cc index 85fc49bb393..8f9f3b0c047 100644 --- a/test/core/end2end/tests/streaming_error_response.cc +++ b/test/core/end2end/tests/streaming_error_response.cc @@ -38,8 +38,8 @@ namespace { CORE_END2END_TEST(CoreEnd2endTest, StreamingErrorResponse) { SKIP_IF_CHAOTIC_GOOD(); auto c = NewClientCall("/foo").Timeout(Duration::Seconds(5)).Create(); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage response_payload1_recv; + IncomingMetadata server_initial_metadata; + IncomingMessage response_payload1_recv; c.NewBatch(1) .SendInitialMetadata({}) .SendCloseFromClient() @@ -59,18 +59,18 @@ CORE_END2END_TEST(CoreEnd2endTest, StreamingErrorResponse) { // Since this behavior is dependent on the transport implementation, we allow // any success status with this op. Expect(103, AnyStatus()); - CoreEnd2endTest::IncomingMessage response_payload2_recv; + IncomingMessage response_payload2_recv; c.NewBatch(2).RecvMessage(response_payload2_recv); Expect(2, true); Step(); EXPECT_FALSE(response_payload2_recv.is_end_of_stream()); // Cancel the call so that the client sets up an error status. c.Cancel(); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(104).RecvCloseOnServer(client_close); Expect(104, true); Step(); - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingStatusOnClient server_status; c.NewBatch(3).RecvStatusOnClient(server_status); Expect(3, true); Step(); @@ -83,9 +83,9 @@ CORE_END2END_TEST(CoreEnd2endTest, StreamingErrorResponse) { CORE_END2END_TEST(CoreEnd2endTest, StreamingErrorResponseRequestStatusEarly) { SKIP_IF_CHAOTIC_GOOD(); auto c = NewClientCall("/foo").Timeout(Duration::Seconds(5)).Create(); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage response_payload1_recv; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingMessage response_payload1_recv; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata({}) .SendCloseFromClient() @@ -107,7 +107,7 @@ CORE_END2END_TEST(CoreEnd2endTest, StreamingErrorResponseRequestStatusEarly) { Expect(103, AnyStatus()); // Cancel the call so that the client sets up an error status. c.Cancel(); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(104).RecvCloseOnServer(client_close); Expect(104, true); Expect(1, true); @@ -121,8 +121,8 @@ CORE_END2END_TEST( StreamingErrorResponseRequestStatusEarlyAndRecvMessageSeparately) { SKIP_IF_CHAOTIC_GOOD(); auto c = NewClientCall("/foo").Timeout(Duration::Seconds(5)).Create(); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; c.NewBatch(1) .SendInitialMetadata({}) .SendCloseFromClient() @@ -132,7 +132,7 @@ CORE_END2END_TEST( Expect(101, true); Step(); s.NewBatch(102).SendInitialMetadata({}).SendMessage("hello"); - CoreEnd2endTest::IncomingMessage response_payload1_recv; + IncomingMessage response_payload1_recv; c.NewBatch(4).RecvMessage(response_payload1_recv); Expect(102, true); Expect(4, true); @@ -146,7 +146,7 @@ CORE_END2END_TEST( Expect(103, AnyStatus()); // Cancel the call so that the client sets up an error status. c.Cancel(); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(104).RecvCloseOnServer(client_close); Expect(104, true); Expect(1, true); diff --git a/test/core/end2end/tests/timeout_before_request_call.cc b/test/core/end2end/tests/timeout_before_request_call.cc index bb61acd648e..4923a20d658 100644 --- a/test/core/end2end/tests/timeout_before_request_call.cc +++ b/test/core/end2end/tests/timeout_before_request_call.cc @@ -34,8 +34,8 @@ namespace { CORE_END2END_TEST(CoreDeadlineTest, TimeoutBeforeRequestCall) { SKIP_IF_CHAOTIC_GOOD(); auto c = NewClientCall("/foo").Timeout(Duration::Seconds(1)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .SendInitialMetadata({}) .SendCloseFromClient() @@ -79,8 +79,8 @@ CORE_END2END_TEST(CoreDeadlineTest, auto method = RegisterServerMethod("/foo", GRPC_SRM_PAYLOAD_NONE); auto c = NewClientCall("/foo").Timeout(Duration::Seconds(1)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .SendInitialMetadata({}) .SendCloseFromClient() @@ -132,8 +132,8 @@ CORE_END2END_TEST(CoreDeadlineSingleHopTest, ChannelArgs().Set(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, kMessageSize)); auto c = NewClientCall("/foo").Timeout(Duration::Seconds(1)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; c.NewBatch(1) .SendInitialMetadata({}) .SendCloseFromClient() diff --git a/test/core/end2end/tests/trailing_metadata.cc b/test/core/end2end/tests/trailing_metadata.cc index 9b8de263def..b20f996f625 100644 --- a/test/core/end2end/tests/trailing_metadata.cc +++ b/test/core/end2end/tests/trailing_metadata.cc @@ -30,9 +30,9 @@ namespace { CORE_END2END_TEST(CoreEnd2endTest, TrailingMetadata) { auto c = NewClientCall("/foo").Timeout(Duration::Minutes(1)).Create(); - CoreEnd2endTest::IncomingStatusOnClient server_status; - CoreEnd2endTest::IncomingMetadata server_initial_metadata; - CoreEnd2endTest::IncomingMessage server_message; + IncomingStatusOnClient server_status; + IncomingMetadata server_initial_metadata; + IncomingMessage server_message; c.NewBatch(1) .SendInitialMetadata({{"key1", "val1"}, {"key2", "val2"}}) .SendMessage("hello world") @@ -43,13 +43,13 @@ CORE_END2END_TEST(CoreEnd2endTest, TrailingMetadata) { auto s = RequestCall(101); Expect(101, true); Step(); - CoreEnd2endTest::IncomingMessage client_message; + IncomingMessage client_message; s.NewBatch(102) .SendInitialMetadata({{"key3", "val3"}, {"key4", "val4"}}) .RecvMessage(client_message); Expect(102, true); Step(); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(103) .RecvCloseOnServer(client_close) .SendMessage("hello you") diff --git a/test/core/end2end/tests/write_buffering.cc b/test/core/end2end/tests/write_buffering.cc index 6cddfffbec8..a551eb02c8d 100644 --- a/test/core/end2end/tests/write_buffering.cc +++ b/test/core/end2end/tests/write_buffering.cc @@ -31,7 +31,7 @@ namespace grpc_core { CORE_END2END_TEST(WriteBufferingTest, WriteBufferingWorks) { auto c = NewClientCall("/foo").Timeout(Duration::Minutes(1)).Create(); c.NewBatch(1).SendInitialMetadata({}); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingMetadata server_initial_metadata; c.NewBatch(2).RecvInitialMetadata(server_initial_metadata); auto s = RequestCall(101); Expect(1, true); // send message is buffered @@ -41,7 +41,7 @@ CORE_END2END_TEST(WriteBufferingTest, WriteBufferingWorks) { s.NewBatch(102).SendInitialMetadata({}); // recv message should not succeed yet - it's buffered at the client still - CoreEnd2endTest::IncomingMessage request_payload_recv1; + IncomingMessage request_payload_recv1; s.NewBatch(103).RecvMessage(request_payload_recv1); Expect(2, true); Expect(3, true); @@ -56,15 +56,15 @@ CORE_END2END_TEST(WriteBufferingTest, WriteBufferingWorks) { Step(); // and the next recv should be ready immediately also - CoreEnd2endTest::IncomingMessage request_payload_recv2; + IncomingMessage request_payload_recv2; s.NewBatch(104).RecvMessage(request_payload_recv2); Expect(104, true); Step(); - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingStatusOnClient server_status; c.NewBatch(5).SendCloseFromClient().RecvStatusOnClient(server_status); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(105) .RecvCloseOnServer(client_close) .SendStatusFromServer(GRPC_STATUS_OK, "xyz", {}); diff --git a/test/core/end2end/tests/write_buffering_at_end.cc b/test/core/end2end/tests/write_buffering_at_end.cc index 531e2715aa1..684318d2186 100644 --- a/test/core/end2end/tests/write_buffering_at_end.cc +++ b/test/core/end2end/tests/write_buffering_at_end.cc @@ -32,7 +32,7 @@ namespace { CORE_END2END_TEST(WriteBufferingTest, WriteBufferingAtEnd) { auto c = NewClientCall("/foo").Timeout(Duration::Minutes(1)).Create(); c.NewBatch(1).SendInitialMetadata({}); - CoreEnd2endTest::IncomingMetadata server_initial_metadata; + IncomingMetadata server_initial_metadata; c.NewBatch(2).RecvInitialMetadata(server_initial_metadata); auto s = RequestCall(101); @@ -43,7 +43,7 @@ CORE_END2END_TEST(WriteBufferingTest, WriteBufferingAtEnd) { c.NewBatch(3).SendMessage("hello world", GRPC_WRITE_BUFFER_HINT); s.NewBatch(102).SendInitialMetadata({}); // recv message should not succeed yet - it's buffered at the client still - CoreEnd2endTest::IncomingMessage request_payload_recv1; + IncomingMessage request_payload_recv1; s.NewBatch(103).RecvMessage(request_payload_recv1); Expect(2, true); Expect(3, true); @@ -58,14 +58,14 @@ CORE_END2END_TEST(WriteBufferingTest, WriteBufferingAtEnd) { Step(); // and the next recv should be ready immediately also (and empty) - CoreEnd2endTest::IncomingMessage request_payload_recv2; + IncomingMessage request_payload_recv2; s.NewBatch(104).RecvMessage(request_payload_recv2); Expect(104, true); Step(); - CoreEnd2endTest::IncomingStatusOnClient server_status; + IncomingStatusOnClient server_status; c.NewBatch(4).RecvStatusOnClient(server_status); - CoreEnd2endTest::IncomingCloseOnServer client_close; + IncomingCloseOnServer client_close; s.NewBatch(105) .RecvCloseOnServer(client_close) .SendStatusFromServer(GRPC_STATUS_OK, "xyz", {}); diff --git a/test/core/security/ssl_server_fuzzer.cc b/test/core/security/ssl_server_fuzzer.cc index bda15c101a4..d5310112c90 100644 --- a/test/core/security/ssl_server_fuzzer.cc +++ b/test/core/security/ssl_server_fuzzer.cc @@ -43,8 +43,6 @@ bool squelch = true; // Turning this on will fail the leak check. bool leak_check = false; -static void discard_write(grpc_slice /*slice*/) {} - static void dont_log(gpr_log_func_args* /*args*/) {} struct handshake_state { diff --git a/test/core/server/xds_channel_stack_modifier_test.cc b/test/core/server/xds_channel_stack_modifier_test.cc index e7cae694aec..4c1e9f0919d 100644 --- a/test/core/server/xds_channel_stack_modifier_test.cc +++ b/test/core/server/xds_channel_stack_modifier_test.cc @@ -94,11 +94,11 @@ TEST(XdsChannelStackModifierTest, XdsHttpFiltersInsertion) { grpc_init(); // Add 2 test filters to XdsChannelStackModifier const grpc_channel_filter test_filter_1 = { - nullptr, nullptr, nullptr, nullptr, 0, nullptr, nullptr, - nullptr, 0, nullptr, nullptr, nullptr, nullptr, kTestFilter1}; + nullptr, nullptr, 0, nullptr, nullptr, nullptr, + 0, nullptr, nullptr, nullptr, nullptr, kTestFilter1}; const grpc_channel_filter test_filter_2 = { - nullptr, nullptr, nullptr, nullptr, 0, nullptr, nullptr, - nullptr, 0, nullptr, nullptr, nullptr, nullptr, kTestFilter2}; + nullptr, nullptr, 0, nullptr, nullptr, nullptr, + 0, nullptr, nullptr, nullptr, nullptr, kTestFilter2}; auto channel_stack_modifier = MakeRefCounted( std::vector{&test_filter_1, &test_filter_2}); grpc_arg arg = channel_stack_modifier->MakeChannelArg(); diff --git a/test/core/surface/channel_init_test.cc b/test/core/surface/channel_init_test.cc index 07a1a4b300e..b0b84323d47 100644 --- a/test/core/surface/channel_init_test.cc +++ b/test/core/surface/channel_init_test.cc @@ -38,10 +38,9 @@ const grpc_channel_filter* FilterNamed(const char* name) { auto it = filters->find(name); if (it != filters->end()) return it->second; return filters - ->emplace(name, - new grpc_channel_filter{nullptr, nullptr, nullptr, nullptr, 0, - nullptr, nullptr, nullptr, 0, nullptr, - nullptr, nullptr, nullptr, name}) + ->emplace(name, new grpc_channel_filter{nullptr, nullptr, 0, nullptr, + nullptr, nullptr, 0, nullptr, + nullptr, nullptr, nullptr, name}) .first->second; } @@ -240,8 +239,8 @@ class TestFilter1 { }; const grpc_channel_filter TestFilter1::kFilter = { - nullptr, nullptr, nullptr, nullptr, 0, nullptr, nullptr, - nullptr, 0, nullptr, nullptr, nullptr, nullptr, "test_filter1"}; + nullptr, nullptr, 0, nullptr, nullptr, nullptr, + 0, nullptr, nullptr, nullptr, nullptr, "test_filter1"}; const NoInterceptor TestFilter1::Call::OnClientInitialMetadata; const NoInterceptor TestFilter1::Call::OnServerInitialMetadata; const NoInterceptor TestFilter1::Call::OnServerTrailingMetadata; diff --git a/test/core/surface/lame_client_test.cc b/test/core/surface/lame_client_test.cc index 44c723059bf..7d5b57af46f 100644 --- a/test/core/surface/lame_client_test.cc +++ b/test/core/surface/lame_client_test.cc @@ -123,12 +123,7 @@ TEST(LameClientTest, MainTest) { grpc_core::CqVerifier::tag(1), nullptr); ASSERT_EQ(GRPC_CALL_OK, error); - // Filter stack code considers this a failed to receive initial metadata - // result, where as promise based code interprets this as a trailers only - // failed request. Both are rational interpretations, so we accept the one - // that is implemented for each stack. - cqv.Expect(grpc_core::CqVerifier::tag(1), - grpc_core::IsPromiseBasedClientCallEnabled()); + cqv.Expect(grpc_core::CqVerifier::tag(1), false); cqv.Verify(); memset(ops, 0, sizeof(ops)); diff --git a/test/core/surface/num_external_connectivity_watchers_test.cc b/test/core/surface/num_external_connectivity_watchers_test.cc index d2ebf533b01..0194592f5e8 100644 --- a/test/core/surface/num_external_connectivity_watchers_test.cc +++ b/test/core/surface/num_external_connectivity_watchers_test.cc @@ -45,6 +45,9 @@ typedef struct test_fixture { grpc_channel* (*create_channel)(const char* addr); } test_fixture; +class NumExternalConnectivityWatchersTest + : public ::testing::TestWithParam {}; + static size_t next_tag = 1; static void channel_idle_start_watch(grpc_channel* channel, @@ -73,8 +76,6 @@ static void channel_idle_poll_for_timeout(grpc_channel* channel, // Test to make sure that "connectivity watcher" structs are free'd just // after, if their corresponding timeouts occur. static void run_timeouts_test(const test_fixture* fixture) { - LOG(INFO) << "TEST: " << fixture->name; - grpc_init(); std::string addr = grpc_core::JoinHostPort("localhost", grpc_pick_unused_port_or_die()); @@ -122,8 +123,6 @@ static void run_timeouts_test(const test_fixture* fixture) { // of a polling call. static void run_channel_shutdown_before_timeout_test( const test_fixture* fixture) { - LOG(INFO) << "TEST: " << fixture->name; - grpc_init(); std::string addr = grpc_core::JoinHostPort("localhost", grpc_pick_unused_port_or_die()); @@ -195,14 +194,18 @@ static const test_fixture secure_test = { secure_test_create_channel, }; -TEST(NumExternalConnectivityWatchersTest, MainTest) { - run_timeouts_test(&insecure_test); - run_timeouts_test(&secure_test); +TEST_P(NumExternalConnectivityWatchersTest, Timeouts) { + run_timeouts_test(&GetParam()); +} - run_channel_shutdown_before_timeout_test(&insecure_test); - run_channel_shutdown_before_timeout_test(&secure_test); +TEST_P(NumExternalConnectivityWatchersTest, ChannelShutdownBeforeTimeout) { + run_channel_shutdown_before_timeout_test(&GetParam()); } +INSTANTIATE_TEST_SUITE_P(NumExternalConnectivityWatchersTest, + NumExternalConnectivityWatchersTest, + ::testing::Values(insecure_test, secure_test)); + int main(int argc, char** argv) { grpc::testing::TestEnvironment env(&argc, argv); ::testing::InitGoogleTest(&argc, argv); diff --git a/test/core/surface/secure_channel_create_test.cc b/test/core/surface/secure_channel_create_test.cc index e22aa5cd61b..89f21615e98 100644 --- a/test/core/surface/secure_channel_create_test.cc +++ b/test/core/surface/secure_channel_create_test.cc @@ -39,7 +39,7 @@ void test_unknown_scheme_target(void) { grpc_core::Channel::FromC(chan)->channel_stack(), 0); ASSERT_STREQ(elem->filter->name, "lame-client"); grpc_core::ExecCtx exec_ctx; - grpc_core::Channel::FromC(chan)->Orphan(); + grpc_core::Channel::FromC(chan)->Unref(); creds->Unref(); } @@ -53,7 +53,7 @@ void test_security_connector_already_in_arg(void) { grpc_core::Channel::FromC(chan)->channel_stack(), 0); ASSERT_STREQ(elem->filter->name, "lame-client"); grpc_core::ExecCtx exec_ctx; - grpc_core::Channel::FromC(chan)->Orphan(); + grpc_core::Channel::FromC(chan)->Unref(); } void test_null_creds(void) { @@ -62,7 +62,7 @@ void test_null_creds(void) { grpc_core::Channel::FromC(chan)->channel_stack(), 0); ASSERT_STREQ(elem->filter->name, "lame-client"); grpc_core::ExecCtx exec_ctx; - grpc_core::Channel::FromC(chan)->Orphan(); + grpc_core::Channel::FromC(chan)->Unref(); } TEST(SecureChannelCreateTest, MainTest) { diff --git a/test/core/transport/chaotic_good/client_transport_error_test.cc b/test/core/transport/chaotic_good/client_transport_error_test.cc index 57109b8b535..fe3c1d42b33 100644 --- a/test/core/transport/chaotic_good/client_transport_error_test.cc +++ b/test/core/transport/chaotic_good/client_transport_error_test.cc @@ -188,7 +188,7 @@ TEST_F(ClientTransportTest, AddOneStreamWithWriteFailed) { std::move(data_endpoint.promise_endpoint), MakeChannelArgs(), event_engine(), HPackParser(), HPackCompressor()); auto call = MakeCall(TestInitialMetadata()); - transport->StartCall(call.handler.V2HackToStartCallWithoutACallFilterStack()); + transport->StartCall(call.handler.StartWithEmptyFilterStack()); call.initiator.SpawnGuarded("test-send", [initiator = call.initiator]() mutable { return SendClientToServerMessages(initiator, 1); @@ -232,7 +232,7 @@ TEST_F(ClientTransportTest, AddOneStreamWithReadFailed) { std::move(data_endpoint.promise_endpoint), MakeChannelArgs(), event_engine(), HPackParser(), HPackCompressor()); auto call = MakeCall(TestInitialMetadata()); - transport->StartCall(call.handler.V2HackToStartCallWithoutACallFilterStack()); + transport->StartCall(call.handler.StartWithEmptyFilterStack()); call.initiator.SpawnGuarded("test-send", [initiator = call.initiator]() mutable { return SendClientToServerMessages(initiator, 1); @@ -284,11 +284,9 @@ TEST_F(ClientTransportTest, AddMultipleStreamWithWriteFailed) { std::move(data_endpoint.promise_endpoint), MakeChannelArgs(), event_engine(), HPackParser(), HPackCompressor()); auto call1 = MakeCall(TestInitialMetadata()); - transport->StartCall( - call1.handler.V2HackToStartCallWithoutACallFilterStack()); + transport->StartCall(call1.handler.StartWithEmptyFilterStack()); auto call2 = MakeCall(TestInitialMetadata()); - transport->StartCall( - call2.handler.V2HackToStartCallWithoutACallFilterStack()); + transport->StartCall(call2.handler.StartWithEmptyFilterStack()); call1.initiator.SpawnGuarded( "test-send-1", [initiator = call1.initiator]() mutable { return SendClientToServerMessages(initiator, 1); @@ -354,11 +352,9 @@ TEST_F(ClientTransportTest, AddMultipleStreamWithReadFailed) { std::move(data_endpoint.promise_endpoint), MakeChannelArgs(), event_engine(), HPackParser(), HPackCompressor()); auto call1 = MakeCall(TestInitialMetadata()); - transport->StartCall( - call1.handler.V2HackToStartCallWithoutACallFilterStack()); + transport->StartCall(call1.handler.StartWithEmptyFilterStack()); auto call2 = MakeCall(TestInitialMetadata()); - transport->StartCall( - call2.handler.V2HackToStartCallWithoutACallFilterStack()); + transport->StartCall(call2.handler.StartWithEmptyFilterStack()); call1.initiator.SpawnGuarded( "test-send", [initiator = call1.initiator]() mutable { return SendClientToServerMessages(initiator, 1); diff --git a/test/core/transport/chaotic_good/client_transport_test.cc b/test/core/transport/chaotic_good/client_transport_test.cc index b5dc5f823f3..4aa5caa1f68 100644 --- a/test/core/transport/chaotic_good/client_transport_test.cc +++ b/test/core/transport/chaotic_good/client_transport_test.cc @@ -120,7 +120,7 @@ TEST_F(TransportTest, AddOneStream) { std::move(data_endpoint.promise_endpoint), MakeChannelArgs(), event_engine(), HPackParser(), HPackCompressor()); auto call = MakeCall(TestInitialMetadata()); - transport->StartCall(call.handler.V2HackToStartCallWithoutACallFilterStack()); + transport->StartCall(call.handler.StartWithEmptyFilterStack()); StrictMock> on_done; EXPECT_CALL(on_done, Call()); control_endpoint.ExpectWrite( @@ -206,7 +206,7 @@ TEST_F(TransportTest, AddOneStreamMultipleMessages) { std::move(data_endpoint.promise_endpoint), MakeChannelArgs(), event_engine(), HPackParser(), HPackCompressor()); auto call = MakeCall(TestInitialMetadata()); - transport->StartCall(call.handler.V2HackToStartCallWithoutACallFilterStack()); + transport->StartCall(call.handler.StartWithEmptyFilterStack()); StrictMock> on_done; EXPECT_CALL(on_done, Call()); control_endpoint.ExpectWrite( diff --git a/test/core/transport/chaotic_good/server_transport_test.cc b/test/core/transport/chaotic_good/server_transport_test.cc index da80f94781f..e23ac223624 100644 --- a/test/core/transport/chaotic_good/server_transport_test.cc +++ b/test/core/transport/chaotic_good/server_transport_test.cc @@ -125,8 +125,7 @@ TEST_F(TransportTest, ReadAndWriteOneMessage) { .get_pointer(HttpPathMetadata()) ->as_string_view(), "/demo.Service/Step"); - auto handler = - unstarted_call_handler.V2HackToStartCallWithoutACallFilterStack(); + auto handler = unstarted_call_handler.StartWithEmptyFilterStack(); handler.SpawnInfallible("test-io", [&on_done, handler]() mutable { return Seq( handler.PullClientInitialMetadata(), diff --git a/test/core/transport/chttp2/streams_not_seen_test.cc b/test/core/transport/chttp2/streams_not_seen_test.cc index be0b7ed7885..f00ca984e51 100644 --- a/test/core/transport/chttp2/streams_not_seen_test.cc +++ b/test/core/transport/chttp2/streams_not_seen_test.cc @@ -199,8 +199,6 @@ class TrailingMetadataRecordingFilter { grpc_channel_filter TrailingMetadataRecordingFilter::kFilterVtable = { CallData::StartTransportStreamOpBatch, - nullptr, - nullptr, grpc_channel_next_op, sizeof(CallData), CallData::Init, diff --git a/test/core/transport/test_suite/transport_test.cc b/test/core/transport/test_suite/transport_test.cc index 12e2932faa7..093cc6d8271 100644 --- a/test/core/transport/test_suite/transport_test.cc +++ b/test/core/transport/test_suite/transport_test.cc @@ -34,7 +34,7 @@ CallInitiator TransportTest::CreateCall( call.handler.SpawnInfallible( "start-call", [this, handler = call.handler]() mutable { transport_pair_.client->client_transport()->StartCall( - handler.V2HackToStartCallWithoutACallFilterStack()); + handler.StartWithEmptyFilterStack()); return Empty{}; }); return std::move(call.initiator); @@ -54,7 +54,7 @@ CallHandler TransportTest::TickUntilServerCall() { void TransportTest::ServerCallDestination::StartCall( UnstartedCallHandler handler) { - handlers_.push(handler.V2HackToStartCallWithoutACallFilterStack()); + handlers_.push(handler.StartWithEmptyFilterStack()); } absl::optional TransportTest::ServerCallDestination::PopHandler() { diff --git a/tools/distrib/fix_build_deps.py b/tools/distrib/fix_build_deps.py index 8e4acb81ca7..352665bf89d 100755 --- a/tools/distrib/fix_build_deps.py +++ b/tools/distrib/fix_build_deps.py @@ -399,6 +399,7 @@ for dirname in [ "src/cpp/ext/csm", "src/cpp/ext/otel", "test/core/backoff", + "test/core/call", "test/core/call/yodel", "test/core/client_channel", "test/core/experiments", diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index e5f91a13df7..d0762b62874 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -2657,6 +2657,8 @@ src/core/lib/surface/call_details.cc \ src/core/lib/surface/call_log_batch.cc \ src/core/lib/surface/call_test_only.h \ src/core/lib/surface/call_trace.h \ +src/core/lib/surface/call_utils.cc \ +src/core/lib/surface/call_utils.h \ src/core/lib/surface/channel.cc \ src/core/lib/surface/channel.h \ src/core/lib/surface/channel_create.cc \ @@ -2665,12 +2667,16 @@ src/core/lib/surface/channel_init.cc \ src/core/lib/surface/channel_init.h \ src/core/lib/surface/channel_stack_type.cc \ src/core/lib/surface/channel_stack_type.h \ +src/core/lib/surface/client_call.cc \ +src/core/lib/surface/client_call.h \ src/core/lib/surface/completion_queue.cc \ src/core/lib/surface/completion_queue.h \ src/core/lib/surface/completion_queue_factory.cc \ src/core/lib/surface/completion_queue_factory.h \ src/core/lib/surface/event_string.cc \ src/core/lib/surface/event_string.h \ +src/core/lib/surface/filter_stack_call.cc \ +src/core/lib/surface/filter_stack_call.h \ src/core/lib/surface/init.cc \ src/core/lib/surface/init.h \ src/core/lib/surface/init_internally.cc \ @@ -2680,13 +2686,11 @@ src/core/lib/surface/lame_client.h \ src/core/lib/surface/legacy_channel.cc \ src/core/lib/surface/legacy_channel.h \ src/core/lib/surface/metadata_array.cc \ +src/core/lib/surface/server_call.cc \ +src/core/lib/surface/server_call.h \ src/core/lib/surface/validate_metadata.cc \ src/core/lib/surface/validate_metadata.h \ src/core/lib/surface/version.cc \ -src/core/lib/surface/wait_for_cq_end_op.cc \ -src/core/lib/surface/wait_for_cq_end_op.h \ -src/core/lib/transport/batch_builder.cc \ -src/core/lib/transport/batch_builder.h \ src/core/lib/transport/bdp_estimator.cc \ src/core/lib/transport/bdp_estimator.h \ src/core/lib/transport/call_arena_allocator.cc \ diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 45e1972e038..e7be4ba2ddc 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -2432,6 +2432,8 @@ src/core/lib/surface/call_details.cc \ src/core/lib/surface/call_log_batch.cc \ src/core/lib/surface/call_test_only.h \ src/core/lib/surface/call_trace.h \ +src/core/lib/surface/call_utils.cc \ +src/core/lib/surface/call_utils.h \ src/core/lib/surface/channel.cc \ src/core/lib/surface/channel.h \ src/core/lib/surface/channel_create.cc \ @@ -2440,12 +2442,16 @@ src/core/lib/surface/channel_init.cc \ src/core/lib/surface/channel_init.h \ src/core/lib/surface/channel_stack_type.cc \ src/core/lib/surface/channel_stack_type.h \ +src/core/lib/surface/client_call.cc \ +src/core/lib/surface/client_call.h \ src/core/lib/surface/completion_queue.cc \ src/core/lib/surface/completion_queue.h \ src/core/lib/surface/completion_queue_factory.cc \ src/core/lib/surface/completion_queue_factory.h \ src/core/lib/surface/event_string.cc \ src/core/lib/surface/event_string.h \ +src/core/lib/surface/filter_stack_call.cc \ +src/core/lib/surface/filter_stack_call.h \ src/core/lib/surface/init.cc \ src/core/lib/surface/init.h \ src/core/lib/surface/init_internally.cc \ @@ -2455,14 +2461,12 @@ src/core/lib/surface/lame_client.h \ src/core/lib/surface/legacy_channel.cc \ src/core/lib/surface/legacy_channel.h \ src/core/lib/surface/metadata_array.cc \ +src/core/lib/surface/server_call.cc \ +src/core/lib/surface/server_call.h \ src/core/lib/surface/validate_metadata.cc \ src/core/lib/surface/validate_metadata.h \ src/core/lib/surface/version.cc \ -src/core/lib/surface/wait_for_cq_end_op.cc \ -src/core/lib/surface/wait_for_cq_end_op.h \ src/core/lib/transport/README.md \ -src/core/lib/transport/batch_builder.cc \ -src/core/lib/transport/batch_builder.h \ src/core/lib/transport/bdp_estimator.cc \ src/core/lib/transport/bdp_estimator.h \ src/core/lib/transport/call_arena_allocator.cc \ diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index b45248aa268..1be46fa624c 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -1373,6 +1373,30 @@ ], "uses_polling": false }, + { + "args": [], + "benchmark": false, + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": true, + "language": "c++", + "name": "call_utils_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "uses_polling": true + }, { "args": [], "benchmark": false, @@ -2065,6 +2089,26 @@ ], "uses_polling": false }, + { + "args": [], + "benchmark": false, + "ci_platforms": [ + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": true, + "language": "c++", + "name": "client_call_test", + "platforms": [ + "linux", + "posix" + ], + "uses_polling": false + }, { "args": [], "benchmark": false, @@ -8963,6 +9007,26 @@ ], "uses_polling": true }, + { + "args": [], + "benchmark": false, + "ci_platforms": [ + "linux", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": true, + "language": "c++", + "name": "server_call_test", + "platforms": [ + "linux", + "posix" + ], + "uses_polling": false + }, { "args": [], "benchmark": false,