Compare commits

...

12 Commits

Author SHA1 Message Date
Hannah Shi 52d0c6c326
Merge release 1.73.x to main (#336)
* remove cronet files

* remove cronet files

* Sync c-core 1.72.0-pre1

* use c++17 for swift package

* update ios deployment target to 15.0

* Sync c-core 1.72.0

* Sync c-core 1.73.0-pre1

* include additional files

* Re-sync c-core 1.73.0-pre1

* exclude inc files from swift package

* upgrade abseil swift to 0.20250127.1 (#330)

* Sync c-core 1.73.0-pre2

* Sync c-core 1.73.0

* Sync c-core 1.73.1
2025-07-12 16:19:13 -07:00
Hannah Shi d88573fd5f
Merge from 1.73.x (#329)
* remove cronet files

* remove cronet files

* Sync c-core 1.72.0-pre1

* use c++17 for swift package

* update ios deployment target to 15.0

* Sync c-core 1.72.0

* Sync c-core 1.73.0-pre1

* include additional files

* Re-sync c-core 1.73.0-pre1

* exclude inc files from swift package
2025-05-24 11:39:33 -07:00
Hannah Shi e584a88115 Re-sync c-core 1.73.0-pre1 2025-05-24 09:40:48 -07:00
Hannah Shi 96ddc18603 include additional files 2025-05-24 09:40:48 -07:00
Hannah Shi fcb8b99697 Sync c-core 1.73.0-pre1 2025-05-24 09:40:48 -07:00
Hannah Shi 9849f527f0 Sync c-core 1.72.0 2025-05-24 09:40:48 -07:00
Hannah Shi 30bd3c9d49 Sync c-core 1.72.0-pre1 2025-05-24 09:40:48 -07:00
Hannah Shi 78593d170e update ios deployment target to 15.0 2025-04-24 18:00:28 -07:00
Hannah Shi c92e41c10b use c++17 for swift package 2025-04-23 13:32:00 -07:00
Hannah Shi b641ac3789 remove cronet files 2025-04-09 15:51:16 -07:00
Hannah Shi 5c9cda2cf6 remove cronet files 2025-04-09 15:51:16 -07:00
Hannah Shi 6797fe4c02 update github workflow to use macos-14 2025-04-09 14:34:57 -07:00
1009 changed files with 50945 additions and 34216 deletions

View File

@ -23,7 +23,7 @@ env:
jobs:
release-cocoapod:
runs-on: macos-12
runs-on: macos-14
steps:
- name: Repo checkout
uses: actions/checkout@v3

View File

@ -24,7 +24,7 @@ let package = Package(
],
dependencies: [
.package(url: "https://github.com/firebase/abseil-cpp-SwiftPM.git", "0.20240722.0"..<"0.20240723.0"),
.package(url: "https://github.com/firebase/abseil-cpp-SwiftPM.git", "0.20250127.0"..<"0.20250128.0"),
.package(url: "https://github.com/firebase/boringssl-SwiftPM.git", "0.32.0"..<"0.33.0"),
],
@ -41,14 +41,13 @@ let package = Package(
"src/cpp/",
"third_party/upb/upb/port/def.inc",
"third_party/upb/upb/port/undef.inc",
"third_party/utf8_range/utf8_range_sse.inc",
"third_party/utf8_range/utf8_range_neon.inc",
"third_party/re2/LICENSE",
"third_party/utf8_range/LICENSE",
"third_party/xxhash/LICENSE",
"third_party/zlib/LICENSE",
"tests",
"include/grpc/grpc_cronet.h",
"src/core/ext/transport/cronet/",
"third_party/objective_c/Cronet/bidirectional_stream_c.h",
],
sources: [
@ -85,8 +84,8 @@ let package = Package(
path: basePath,
exclude: [
"tests",
"include/grpcpp/security/cronet_credentials.h",
"src/cpp/client/cronet_credentials.cc",
"include/grpcpp/ports_undef.inc",
"include/grpcpp/ports_def.inc",
],
sources: [
"src/cpp/",
@ -111,5 +110,5 @@ let package = Package(
),
],
cLanguageStandard: .gnu11,
cxxLanguageStandard: .cxx14
cxxLanguageStandard: .cxx17
)

View File

@ -22,7 +22,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC-C++'
# TODO (mxyan): use version that match gRPC version when pod is stabilized
version = '1.72.0-dev'
version = '1.73.1'
s.version = version
s.summary = 'gRPC C++ library'
s.homepage = 'https://grpc.io'
@ -34,8 +34,8 @@ Pod::Spec.new do |s|
:tag => "v#{version}",
}
s.ios.deployment_target = '11.0'
s.osx.deployment_target = '10.14'
s.ios.deployment_target = '15.0'
s.osx.deployment_target = '11.0'
s.tvos.deployment_target = '13.0'
s.watchos.deployment_target = '6.0'
s.visionos.deployment_target = '1.0'
@ -232,7 +232,7 @@ Pod::Spec.new do |s|
ss.dependency "#{s.name}/Privacy", version
ss.dependency "#{s.name}/Interface", version
ss.dependency 'gRPC-Core', version
abseil_version = '~> 1.20240722.0'
abseil_version = '~> 1.20250127.1'
ss.dependency 'abseil/algorithm/container', abseil_version
ss.dependency 'abseil/base/base', abseil_version
ss.dependency 'abseil/base/config', abseil_version
@ -240,6 +240,7 @@ Pod::Spec.new do |s|
ss.dependency 'abseil/base/log_severity', abseil_version
ss.dependency 'abseil/base/no_destructor', abseil_version
ss.dependency 'abseil/cleanup/cleanup', abseil_version
ss.dependency 'abseil/container/btree', abseil_version
ss.dependency 'abseil/container/flat_hash_map', abseil_version
ss.dependency 'abseil/container/flat_hash_set', abseil_version
ss.dependency 'abseil/container/inlined_vector', abseil_version
@ -271,11 +272,30 @@ Pod::Spec.new do |s|
ss.dependency 'abseil/types/span', abseil_version
ss.dependency 'abseil/utility/utility', abseil_version
ss.source_files = 'src/core/call/request_buffer.h',
ss.source_files = 'src/core/call/call_arena_allocator.h',
'src/core/call/call_destination.h',
'src/core/call/call_filters.h',
'src/core/call/call_finalization.h',
'src/core/call/call_spine.h',
'src/core/call/call_state.h',
'src/core/call/client_call.h',
'src/core/call/custom_metadata.h',
'src/core/call/interception_chain.h',
'src/core/call/message.h',
'src/core/call/metadata.h',
'src/core/call/metadata_batch.h',
'src/core/call/metadata_compression_traits.h',
'src/core/call/metadata_info.h',
'src/core/call/parsed_metadata.h',
'src/core/call/request_buffer.h',
'src/core/call/security_context.h',
'src/core/call/server_call.h',
'src/core/call/simple_slice_based_metadata.h',
'src/core/call/status_util.h',
'src/core/channelz/channel_trace.h',
'src/core/channelz/channelz.h',
'src/core/channelz/channelz_registry.h',
'src/core/channelz/ztrace_collector.h',
'src/core/client_channel/backup_poller.h',
'src/core/client_channel/client_channel.h',
'src/core/client_channel/client_channel_args.h',
@ -375,7 +395,6 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/bin_encoder.h',
'src/core/ext/transport/chttp2/transport/call_tracer_wrapper.h',
'src/core/ext/transport/chttp2/transport/chttp2_transport.h',
'src/core/ext/transport/chttp2/transport/context_list_entry.h',
'src/core/ext/transport/chttp2/transport/decode_huff.h',
'src/core/ext/transport/chttp2/transport/flow_control.h',
'src/core/ext/transport/chttp2/transport/frame.h',
@ -393,8 +412,11 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/hpack_parser.h',
'src/core/ext/transport/chttp2/transport/hpack_parser_table.h',
'src/core/ext/transport/chttp2/transport/http2_settings.h',
'src/core/ext/transport/chttp2/transport/http2_status.h',
'src/core/ext/transport/chttp2/transport/http2_ztrace_collector.h',
'src/core/ext/transport/chttp2/transport/huffsyms.h',
'src/core/ext/transport/chttp2/transport/internal.h',
'src/core/ext/transport/chttp2/transport/internal_channel_arg_names.h',
'src/core/ext/transport/chttp2/transport/legacy_frame.h',
'src/core/ext/transport/chttp2/transport/ping_abuse_policy.h',
'src/core/ext/transport/chttp2/transport/ping_callbacks.h',
@ -909,7 +931,6 @@ Pod::Spec.new do |s|
'src/core/handshaker/tcp_connect/tcp_connect_handshaker.h',
'src/core/lib/address_utils/parse_address.h',
'src/core/lib/address_utils/sockaddr_utils.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',
@ -918,7 +939,6 @@ Pod::Spec.new do |s|
'src/core/lib/channel/channel_stack_builder_impl.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/debug/trace.h',
@ -934,9 +954,13 @@ Pod::Spec.new do |s|
'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/blocking_dns.h',
'src/core/lib/event_engine/extensions/can_track_errors.h',
'src/core/lib/event_engine/extensions/channelz.h',
'src/core/lib/event_engine/extensions/chaotic_good_extension.h',
'src/core/lib/event_engine/extensions/iomgr_compatible.h',
'src/core/lib/event_engine/extensions/supports_fd.h',
'src/core/lib/event_engine/extensions/supports_win_sockets.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',
@ -1010,7 +1034,6 @@ Pod::Spec.new do |s|
'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/internal_errqueue.h',
'src/core/lib/iomgr/iocp_windows.h',
'src/core/lib/iomgr/iomgr.h',
@ -1112,7 +1135,6 @@ Pod::Spec.new do |s|
'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/connection_context.h',
@ -1122,27 +1144,11 @@ Pod::Spec.new do |s|
'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/transport/bdp_estimator.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/call_state.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/metadata_info.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',
@ -1203,12 +1209,16 @@ Pod::Spec.new do |s|
'src/core/service_config/service_config_impl.h',
'src/core/service_config/service_config_parser.h',
'src/core/telemetry/call_tracer.h',
'src/core/telemetry/context_list_entry.h',
'src/core/telemetry/default_tcp_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/transport/auth_context.h',
'src/core/transport/endpoint_transport.h',
'src/core/transport/endpoint_transport_client_channel_factory.h',
'src/core/tsi/alts/crypt/gsec.h',
'src/core/tsi/alts/frame_protector/alts_counter.h',
'src/core/tsi/alts/frame_protector/alts_crypter.h',
@ -1243,6 +1253,7 @@ Pod::Spec.new do |s|
'src/core/util/avl.h',
'src/core/util/backoff.h',
'src/core/util/bitset.h',
'src/core/util/check_class_size.h',
'src/core/util/chunked_vector.h',
'src/core/util/construct_destruct.h',
'src/core/util/cpp_impl_of.h',
@ -1256,6 +1267,7 @@ Pod::Spec.new do |s|
'src/core/util/event_log.h',
'src/core/util/examine_stack.h',
'src/core/util/fork.h',
'src/core/util/function_signature.h',
'src/core/util/gcp_metadata_query.h',
'src/core/util/gethostname.h',
'src/core/util/glob.h',
@ -1292,6 +1304,7 @@ Pod::Spec.new do |s|
'src/core/util/ref_counted_ptr.h',
'src/core/util/ref_counted_string.h',
'src/core/util/ring_buffer.h',
'src/core/util/shared_bit_gen.h',
'src/core/util/single_set_ptr.h',
'src/core/util/sorted_pack.h',
'src/core/util/spinlock.h',
@ -1473,8 +1486,8 @@ Pod::Spec.new do |s|
'third_party/upb/upb/message/copy.h',
'third_party/upb/upb/message/internal/accessors.h',
'third_party/upb/upb/message/internal/array.h',
'third_party/upb/upb/message/internal/compare_unknown.h',
'third_party/upb/upb/message/internal/extension.h',
'third_party/upb/upb/message/internal/iterator.h',
'third_party/upb/upb/message/internal/map.h',
'third_party/upb/upb/message/internal/map_entry.h',
'third_party/upb/upb/message/internal/map_sorter.h',
@ -1562,6 +1575,8 @@ Pod::Spec.new do |s|
'third_party/upb/upb/wire/reader.h',
'third_party/upb/upb/wire/types.h',
'third_party/utf8_range/utf8_range.h',
'third_party/utf8_range/utf8_range_neon.inc',
'third_party/utf8_range/utf8_range_sse.inc',
'third_party/xxhash/xxhash.h',
'third_party/zlib/crc32.h',
'third_party/zlib/deflate.h',
@ -1575,11 +1590,30 @@ Pod::Spec.new do |s|
'third_party/zlib/zlib.h',
'third_party/zlib/zutil.h'
ss.private_header_files = 'src/core/call/request_buffer.h',
ss.private_header_files = 'src/core/call/call_arena_allocator.h',
'src/core/call/call_destination.h',
'src/core/call/call_filters.h',
'src/core/call/call_finalization.h',
'src/core/call/call_spine.h',
'src/core/call/call_state.h',
'src/core/call/client_call.h',
'src/core/call/custom_metadata.h',
'src/core/call/interception_chain.h',
'src/core/call/message.h',
'src/core/call/metadata.h',
'src/core/call/metadata_batch.h',
'src/core/call/metadata_compression_traits.h',
'src/core/call/metadata_info.h',
'src/core/call/parsed_metadata.h',
'src/core/call/request_buffer.h',
'src/core/call/security_context.h',
'src/core/call/server_call.h',
'src/core/call/simple_slice_based_metadata.h',
'src/core/call/status_util.h',
'src/core/channelz/channel_trace.h',
'src/core/channelz/channelz.h',
'src/core/channelz/channelz_registry.h',
'src/core/channelz/ztrace_collector.h',
'src/core/client_channel/backup_poller.h',
'src/core/client_channel/client_channel.h',
'src/core/client_channel/client_channel_args.h',
@ -1679,7 +1713,6 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/bin_encoder.h',
'src/core/ext/transport/chttp2/transport/call_tracer_wrapper.h',
'src/core/ext/transport/chttp2/transport/chttp2_transport.h',
'src/core/ext/transport/chttp2/transport/context_list_entry.h',
'src/core/ext/transport/chttp2/transport/decode_huff.h',
'src/core/ext/transport/chttp2/transport/flow_control.h',
'src/core/ext/transport/chttp2/transport/frame.h',
@ -1697,8 +1730,11 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/hpack_parser.h',
'src/core/ext/transport/chttp2/transport/hpack_parser_table.h',
'src/core/ext/transport/chttp2/transport/http2_settings.h',
'src/core/ext/transport/chttp2/transport/http2_status.h',
'src/core/ext/transport/chttp2/transport/http2_ztrace_collector.h',
'src/core/ext/transport/chttp2/transport/huffsyms.h',
'src/core/ext/transport/chttp2/transport/internal.h',
'src/core/ext/transport/chttp2/transport/internal_channel_arg_names.h',
'src/core/ext/transport/chttp2/transport/legacy_frame.h',
'src/core/ext/transport/chttp2/transport/ping_abuse_policy.h',
'src/core/ext/transport/chttp2/transport/ping_callbacks.h',
@ -2213,7 +2249,6 @@ Pod::Spec.new do |s|
'src/core/handshaker/tcp_connect/tcp_connect_handshaker.h',
'src/core/lib/address_utils/parse_address.h',
'src/core/lib/address_utils/sockaddr_utils.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',
@ -2222,7 +2257,6 @@ Pod::Spec.new do |s|
'src/core/lib/channel/channel_stack_builder_impl.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/debug/trace.h',
@ -2238,9 +2272,13 @@ Pod::Spec.new do |s|
'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/blocking_dns.h',
'src/core/lib/event_engine/extensions/can_track_errors.h',
'src/core/lib/event_engine/extensions/channelz.h',
'src/core/lib/event_engine/extensions/chaotic_good_extension.h',
'src/core/lib/event_engine/extensions/iomgr_compatible.h',
'src/core/lib/event_engine/extensions/supports_fd.h',
'src/core/lib/event_engine/extensions/supports_win_sockets.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',
@ -2314,7 +2352,6 @@ Pod::Spec.new do |s|
'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/internal_errqueue.h',
'src/core/lib/iomgr/iocp_windows.h',
'src/core/lib/iomgr/iomgr.h',
@ -2416,7 +2453,6 @@ Pod::Spec.new do |s|
'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/connection_context.h',
@ -2426,27 +2462,11 @@ Pod::Spec.new do |s|
'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/transport/bdp_estimator.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/call_state.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/metadata_info.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',
@ -2507,12 +2527,16 @@ Pod::Spec.new do |s|
'src/core/service_config/service_config_impl.h',
'src/core/service_config/service_config_parser.h',
'src/core/telemetry/call_tracer.h',
'src/core/telemetry/context_list_entry.h',
'src/core/telemetry/default_tcp_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/transport/auth_context.h',
'src/core/transport/endpoint_transport.h',
'src/core/transport/endpoint_transport_client_channel_factory.h',
'src/core/tsi/alts/crypt/gsec.h',
'src/core/tsi/alts/frame_protector/alts_counter.h',
'src/core/tsi/alts/frame_protector/alts_crypter.h',
@ -2547,6 +2571,7 @@ Pod::Spec.new do |s|
'src/core/util/avl.h',
'src/core/util/backoff.h',
'src/core/util/bitset.h',
'src/core/util/check_class_size.h',
'src/core/util/chunked_vector.h',
'src/core/util/construct_destruct.h',
'src/core/util/cpp_impl_of.h',
@ -2560,6 +2585,7 @@ Pod::Spec.new do |s|
'src/core/util/event_log.h',
'src/core/util/examine_stack.h',
'src/core/util/fork.h',
'src/core/util/function_signature.h',
'src/core/util/gcp_metadata_query.h',
'src/core/util/gethostname.h',
'src/core/util/glob.h',
@ -2596,6 +2622,7 @@ Pod::Spec.new do |s|
'src/core/util/ref_counted_ptr.h',
'src/core/util/ref_counted_string.h',
'src/core/util/ring_buffer.h',
'src/core/util/shared_bit_gen.h',
'src/core/util/single_set_ptr.h',
'src/core/util/sorted_pack.h',
'src/core/util/spinlock.h',
@ -2727,8 +2754,8 @@ Pod::Spec.new do |s|
'third_party/upb/upb/message/copy.h',
'third_party/upb/upb/message/internal/accessors.h',
'third_party/upb/upb/message/internal/array.h',
'third_party/upb/upb/message/internal/compare_unknown.h',
'third_party/upb/upb/message/internal/extension.h',
'third_party/upb/upb/message/internal/iterator.h',
'third_party/upb/upb/message/internal/map.h',
'third_party/upb/upb/message/internal/map_entry.h',
'third_party/upb/upb/message/internal/map_sorter.h',
@ -2816,6 +2843,8 @@ Pod::Spec.new do |s|
'third_party/upb/upb/wire/reader.h',
'third_party/upb/upb/wire/types.h',
'third_party/utf8_range/utf8_range.h',
'third_party/utf8_range/utf8_range_neon.inc',
'third_party/utf8_range/utf8_range_sse.inc',
'third_party/xxhash/xxhash.h',
'third_party/zlib/crc32.h',
'third_party/zlib/deflate.h',
@ -2840,25 +2869,6 @@ Pod::Spec.new do |s|
'include/grpcpp/impl/codegen/proto_utils.h'
end
s.subspec 'Cronet-Interface' do |ss|
ss.header_mappings_dir = 'include/grpcpp'
ss.public_header_files = "include/grpcpp/security/cronet_credentials.h",
"include/grpcpp/security/cronet_credentials_impl.h"
ss.source_files = "include/grpcpp/security/cronet_credentials.h",
"include/grpcpp/security/cronet_credentials_impl.h"
end
s.subspec 'Cronet-Implementation' do |ss|
ss.header_mappings_dir = '.'
ss.dependency "#{s.name}/Cronet-Interface", version
ss.dependency "#{s.name}/Implementation", version
ss.dependency "#{s.name}/Privacy", version
ss.dependency 'gRPC-Core/Cronet-Implementation', version
ss.source_files = "src/cpp/client/cronet_credentials.cc"
end
# patch include of openssl to openssl_grpc
s.prepare_command = <<-END_OF_COMMAND
set -e

View File

@ -21,7 +21,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC-Core'
version = '1.72.0-dev'
version = '1.73.1'
s.version = version
s.summary = 'Core cross-platform gRPC library, written in C'
s.homepage = 'https://grpc.io'
@ -38,8 +38,8 @@ Pod::Spec.new do |s|
# which was released in Cocoapods v1.2.0.
s.cocoapods_version = '>= 1.2.0'
s.ios.deployment_target = '11.0'
s.osx.deployment_target = '10.14'
s.ios.deployment_target = '15.0'
s.osx.deployment_target = '11.0'
s.tvos.deployment_target = '13.0'
s.watchos.deployment_target = '6.0'
s.visionos.deployment_target = '1.0'
@ -47,7 +47,7 @@ Pod::Spec.new do |s|
s.requires_arc = false
name = 'grpc'
abseil_version = '~> 1.20240722.0'
abseil_version = '~> 1.20250127.1'
# When creating a dynamic framework, name it grpc.framework instead of gRPC-Core.framework.
# This lets users write their includes like `#include <grpc/grpc.h>` as opposed to `#include
@ -127,6 +127,7 @@ Pod::Spec.new do |s|
'include/grpc/event_engine/extensible.h',
'include/grpc/event_engine/internal/memory_allocator_impl.h',
'include/grpc/event_engine/internal/slice_cast.h',
'include/grpc/event_engine/internal/write_event.h',
'include/grpc/event_engine/memory_allocator.h',
'include/grpc/event_engine/memory_request.h',
'include/grpc/event_engine/port.h',
@ -200,7 +201,7 @@ Pod::Spec.new do |s|
ss.libraries = 'z'
ss.dependency "#{s.name}/Interface", version
ss.dependency "#{s.name}/Privacy", version
ss.dependency 'BoringSSL-GRPC', '0.0.39'
ss.dependency 'BoringSSL-GRPC', '0.0.41'
ss.dependency 'abseil/algorithm/container', abseil_version
ss.dependency 'abseil/base/base', abseil_version
ss.dependency 'abseil/base/config', abseil_version
@ -208,6 +209,7 @@ Pod::Spec.new do |s|
ss.dependency 'abseil/base/log_severity', abseil_version
ss.dependency 'abseil/base/no_destructor', abseil_version
ss.dependency 'abseil/cleanup/cleanup', abseil_version
ss.dependency 'abseil/container/btree', abseil_version
ss.dependency 'abseil/container/flat_hash_map', abseil_version
ss.dependency 'abseil/container/flat_hash_set', abseil_version
ss.dependency 'abseil/container/inlined_vector', abseil_version
@ -238,16 +240,48 @@ Pod::Spec.new do |s|
ss.dependency 'abseil/utility/utility', abseil_version
ss.compiler_flags = '-DBORINGSSL_PREFIX=GRPC -Wno-unreachable-code -Wno-shorten-64-to-32'
ss.source_files = 'src/core/call/request_buffer.cc',
ss.source_files = 'src/core/call/call_arena_allocator.cc',
'src/core/call/call_arena_allocator.h',
'src/core/call/call_destination.h',
'src/core/call/call_filters.cc',
'src/core/call/call_filters.h',
'src/core/call/call_finalization.h',
'src/core/call/call_spine.cc',
'src/core/call/call_spine.h',
'src/core/call/call_state.cc',
'src/core/call/call_state.h',
'src/core/call/client_call.cc',
'src/core/call/client_call.h',
'src/core/call/custom_metadata.h',
'src/core/call/interception_chain.cc',
'src/core/call/interception_chain.h',
'src/core/call/message.cc',
'src/core/call/message.h',
'src/core/call/metadata.cc',
'src/core/call/metadata.h',
'src/core/call/metadata_batch.cc',
'src/core/call/metadata_batch.h',
'src/core/call/metadata_compression_traits.h',
'src/core/call/metadata_info.cc',
'src/core/call/metadata_info.h',
'src/core/call/parsed_metadata.cc',
'src/core/call/parsed_metadata.h',
'src/core/call/request_buffer.cc',
'src/core/call/request_buffer.h',
'src/core/call/security_context.cc',
'src/core/call/security_context.h',
'src/core/call/server_call.cc',
'src/core/call/server_call.h',
'src/core/call/simple_slice_based_metadata.h',
'src/core/call/status_util.cc',
'src/core/call/status_util.h',
'src/core/channelz/channel_trace.cc',
'src/core/channelz/channel_trace.h',
'src/core/channelz/channelz.cc',
'src/core/channelz/channelz.h',
'src/core/channelz/channelz_registry.cc',
'src/core/channelz/channelz_registry.h',
'src/core/channelz/ztrace_collector.h',
'src/core/client_channel/backup_poller.cc',
'src/core/client_channel/backup_poller.h',
'src/core/client_channel/client_channel.cc',
@ -438,6 +472,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/stateful_session/stateful_session_service_config_parser.h',
'src/core/ext/transport/chttp2/alpn/alpn.cc',
'src/core/ext/transport/chttp2/alpn/alpn.h',
'src/core/ext/transport/chttp2/chttp2_plugin.cc',
'src/core/ext/transport/chttp2/client/chttp2_connector.cc',
'src/core/ext/transport/chttp2/client/chttp2_connector.h',
'src/core/ext/transport/chttp2/server/chttp2_server.cc',
@ -450,7 +485,6 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/call_tracer_wrapper.h',
'src/core/ext/transport/chttp2/transport/chttp2_transport.cc',
'src/core/ext/transport/chttp2/transport/chttp2_transport.h',
'src/core/ext/transport/chttp2/transport/context_list_entry.h',
'src/core/ext/transport/chttp2/transport/decode_huff.cc',
'src/core/ext/transport/chttp2/transport/decode_huff.h',
'src/core/ext/transport/chttp2/transport/flow_control.cc',
@ -484,9 +518,12 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/hpack_parser_table.h',
'src/core/ext/transport/chttp2/transport/http2_settings.cc',
'src/core/ext/transport/chttp2/transport/http2_settings.h',
'src/core/ext/transport/chttp2/transport/http2_status.h',
'src/core/ext/transport/chttp2/transport/http2_ztrace_collector.h',
'src/core/ext/transport/chttp2/transport/huffsyms.cc',
'src/core/ext/transport/chttp2/transport/huffsyms.h',
'src/core/ext/transport/chttp2/transport/internal.h',
'src/core/ext/transport/chttp2/transport/internal_channel_arg_names.h',
'src/core/ext/transport/chttp2/transport/legacy_frame.h',
'src/core/ext/transport/chttp2/transport/parsing.cc',
'src/core/ext/transport/chttp2/transport/ping_abuse_policy.cc',
@ -1337,6 +1374,7 @@ Pod::Spec.new do |s|
'src/core/handshaker/proxy_mapper.h',
'src/core/handshaker/proxy_mapper_registry.cc',
'src/core/handshaker/proxy_mapper_registry.h',
'src/core/handshaker/security/legacy_secure_endpoint.cc',
'src/core/handshaker/security/secure_endpoint.cc',
'src/core/handshaker/security/secure_endpoint.h',
'src/core/handshaker/security/security_handshaker.cc',
@ -1347,7 +1385,6 @@ Pod::Spec.new do |s|
'src/core/lib/address_utils/parse_address.h',
'src/core/lib/address_utils/sockaddr_utils.cc',
'src/core/lib/address_utils/sockaddr_utils.h',
'src/core/lib/channel/call_finalization.h',
'src/core/lib/channel/channel_args.cc',
'src/core/lib/channel/channel_args.h',
'src/core/lib/channel/channel_args_preconditioning.cc',
@ -1363,8 +1400,6 @@ Pod::Spec.new do |s|
'src/core/lib/channel/connected_channel.h',
'src/core/lib/channel/promise_based_filter.cc',
'src/core/lib/channel/promise_based_filter.h',
'src/core/lib/channel/status_util.cc',
'src/core/lib/channel/status_util.h',
'src/core/lib/compression/compression.cc',
'src/core/lib/compression/compression_internal.cc',
'src/core/lib/compression/compression_internal.h',
@ -1393,9 +1428,13 @@ Pod::Spec.new do |s|
'src/core/lib/event_engine/default_event_engine_factory.h',
'src/core/lib/event_engine/event_engine.cc',
'src/core/lib/event_engine/event_engine_context.h',
'src/core/lib/event_engine/extensions/blocking_dns.h',
'src/core/lib/event_engine/extensions/can_track_errors.h',
'src/core/lib/event_engine/extensions/channelz.h',
'src/core/lib/event_engine/extensions/chaotic_good_extension.h',
'src/core/lib/event_engine/extensions/iomgr_compatible.h',
'src/core/lib/event_engine/extensions/supports_fd.h',
'src/core/lib/event_engine/extensions/supports_win_sockets.h',
'src/core/lib/event_engine/extensions/tcp_trace.h',
'src/core/lib/event_engine/forkable.cc',
'src/core/lib/event_engine/forkable.h',
@ -1428,6 +1467,7 @@ Pod::Spec.new do |s|
'src/core/lib/event_engine/posix_engine/posix_engine_listener.h',
'src/core/lib/event_engine/posix_engine/posix_engine_listener_utils.cc',
'src/core/lib/event_engine/posix_engine/posix_engine_listener_utils.h',
'src/core/lib/event_engine/posix_engine/set_socket_dualstack.cc',
'src/core/lib/event_engine/posix_engine/tcp_socket_utils.cc',
'src/core/lib/event_engine/posix_engine/tcp_socket_utils.h',
'src/core/lib/event_engine/posix_engine/timer.cc',
@ -1530,8 +1570,6 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/event_engine_shims/tcp_client.h',
'src/core/lib/iomgr/exec_ctx.cc',
'src/core/lib/iomgr/exec_ctx.h',
'src/core/lib/iomgr/executor.cc',
'src/core/lib/iomgr/executor.h',
'src/core/lib/iomgr/fork_posix.cc',
'src/core/lib/iomgr/fork_windows.cc',
'src/core/lib/iomgr/internal_errqueue.cc',
@ -1715,8 +1753,6 @@ 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',
@ -1736,44 +1772,17 @@ 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/transport/bdp_estimator.cc',
'src/core/lib/transport/bdp_estimator.h',
'src/core/lib/transport/call_arena_allocator.cc',
'src/core/lib/transport/call_arena_allocator.h',
'src/core/lib/transport/call_destination.h',
'src/core/lib/transport/call_filters.cc',
'src/core/lib/transport/call_filters.h',
'src/core/lib/transport/call_final_info.cc',
'src/core/lib/transport/call_final_info.h',
'src/core/lib/transport/call_spine.cc',
'src/core/lib/transport/call_spine.h',
'src/core/lib/transport/call_state.cc',
'src/core/lib/transport/call_state.h',
'src/core/lib/transport/connectivity_state.cc',
'src/core/lib/transport/connectivity_state.h',
'src/core/lib/transport/custom_metadata.h',
'src/core/lib/transport/error_utils.cc',
'src/core/lib/transport/error_utils.h',
'src/core/lib/transport/http2_errors.h',
'src/core/lib/transport/interception_chain.cc',
'src/core/lib/transport/interception_chain.h',
'src/core/lib/transport/message.cc',
'src/core/lib/transport/message.h',
'src/core/lib/transport/metadata.cc',
'src/core/lib/transport/metadata.h',
'src/core/lib/transport/metadata_batch.cc',
'src/core/lib/transport/metadata_batch.h',
'src/core/lib/transport/metadata_compression_traits.h',
'src/core/lib/transport/metadata_info.cc',
'src/core/lib/transport/metadata_info.h',
'src/core/lib/transport/parsed_metadata.cc',
'src/core/lib/transport/parsed_metadata.h',
'src/core/lib/transport/simple_slice_based_metadata.h',
'src/core/lib/transport/status_conversion.cc',
'src/core/lib/transport/status_conversion.h',
'src/core/lib/transport/timeout_encoding.cc',
@ -1876,6 +1885,7 @@ Pod::Spec.new do |s|
'src/core/resolver/xds/xds_dependency_manager.h',
'src/core/resolver/xds/xds_resolver.cc',
'src/core/resolver/xds/xds_resolver_attributes.h',
'src/core/server/add_port.cc',
'src/core/server/server.cc',
'src/core/server/server.h',
'src/core/server/server_call_tracer_filter.cc',
@ -1896,6 +1906,9 @@ Pod::Spec.new do |s|
'src/core/service_config/service_config_parser.h',
'src/core/telemetry/call_tracer.cc',
'src/core/telemetry/call_tracer.h',
'src/core/telemetry/context_list_entry.h',
'src/core/telemetry/default_tcp_tracer.cc',
'src/core/telemetry/default_tcp_tracer.h',
'src/core/telemetry/histogram_view.cc',
'src/core/telemetry/histogram_view.h',
'src/core/telemetry/metrics.cc',
@ -1904,9 +1917,13 @@ Pod::Spec.new do |s|
'src/core/telemetry/stats.h',
'src/core/telemetry/stats_data.cc',
'src/core/telemetry/stats_data.h',
'src/core/telemetry/tcp_tracer.cc',
'src/core/telemetry/tcp_tracer.h',
'src/core/transport/auth_context.cc',
'src/core/transport/auth_context.h',
'src/core/transport/endpoint_transport.h',
'src/core/transport/endpoint_transport_client_channel_factory.cc',
'src/core/transport/endpoint_transport_client_channel_factory.h',
'src/core/tsi/alts/crypt/aes_gcm.cc',
'src/core/tsi/alts/crypt/gsec.cc',
'src/core/tsi/alts/crypt/gsec.h',
@ -1972,6 +1989,7 @@ Pod::Spec.new do |s|
'src/core/util/backoff.cc',
'src/core/util/backoff.h',
'src/core/util/bitset.h',
'src/core/util/check_class_size.h',
'src/core/util/chunked_vector.h',
'src/core/util/construct_destruct.h',
'src/core/util/cpp_impl_of.h',
@ -1990,6 +2008,7 @@ Pod::Spec.new do |s|
'src/core/util/examine_stack.h',
'src/core/util/fork.cc',
'src/core/util/fork.h',
'src/core/util/function_signature.h',
'src/core/util/gcp_metadata_query.cc',
'src/core/util/gcp_metadata_query.h',
'src/core/util/gethostname.h',
@ -2064,6 +2083,8 @@ Pod::Spec.new do |s|
'src/core/util/ref_counted_string.cc',
'src/core/util/ref_counted_string.h',
'src/core/util/ring_buffer.h',
'src/core/util/shared_bit_gen.cc',
'src/core/util/shared_bit_gen.h',
'src/core/util/single_set_ptr.h',
'src/core/util/sorted_pack.h',
'src/core/util/spinlock.h',
@ -2280,10 +2301,10 @@ Pod::Spec.new do |s|
'third_party/upb/upb/message/copy.h',
'third_party/upb/upb/message/internal/accessors.h',
'third_party/upb/upb/message/internal/array.h',
'third_party/upb/upb/message/internal/compare_unknown.c',
'third_party/upb/upb/message/internal/compare_unknown.h',
'third_party/upb/upb/message/internal/extension.c',
'third_party/upb/upb/message/internal/extension.h',
'third_party/upb/upb/message/internal/iterator.c',
'third_party/upb/upb/message/internal/iterator.h',
'third_party/upb/upb/message/internal/map.h',
'third_party/upb/upb/message/internal/map_entry.h',
'third_party/upb/upb/message/internal/map_sorter.h',
@ -2409,6 +2430,8 @@ Pod::Spec.new do |s|
'third_party/upb/upb/wire/types.h',
'third_party/utf8_range/utf8_range.c',
'third_party/utf8_range/utf8_range.h',
'third_party/utf8_range/utf8_range_neon.inc',
'third_party/utf8_range/utf8_range_sse.inc',
'third_party/xxhash/xxhash.h',
'third_party/zlib/adler32.c',
'third_party/zlib/compress.c',
@ -2432,11 +2455,30 @@ Pod::Spec.new do |s|
'third_party/zlib/zlib.h',
'third_party/zlib/zutil.c',
'third_party/zlib/zutil.h'
ss.private_header_files = 'src/core/call/request_buffer.h',
ss.private_header_files = 'src/core/call/call_arena_allocator.h',
'src/core/call/call_destination.h',
'src/core/call/call_filters.h',
'src/core/call/call_finalization.h',
'src/core/call/call_spine.h',
'src/core/call/call_state.h',
'src/core/call/client_call.h',
'src/core/call/custom_metadata.h',
'src/core/call/interception_chain.h',
'src/core/call/message.h',
'src/core/call/metadata.h',
'src/core/call/metadata_batch.h',
'src/core/call/metadata_compression_traits.h',
'src/core/call/metadata_info.h',
'src/core/call/parsed_metadata.h',
'src/core/call/request_buffer.h',
'src/core/call/security_context.h',
'src/core/call/server_call.h',
'src/core/call/simple_slice_based_metadata.h',
'src/core/call/status_util.h',
'src/core/channelz/channel_trace.h',
'src/core/channelz/channelz.h',
'src/core/channelz/channelz_registry.h',
'src/core/channelz/ztrace_collector.h',
'src/core/client_channel/backup_poller.h',
'src/core/client_channel/client_channel.h',
'src/core/client_channel/client_channel_args.h',
@ -2536,7 +2578,6 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/bin_encoder.h',
'src/core/ext/transport/chttp2/transport/call_tracer_wrapper.h',
'src/core/ext/transport/chttp2/transport/chttp2_transport.h',
'src/core/ext/transport/chttp2/transport/context_list_entry.h',
'src/core/ext/transport/chttp2/transport/decode_huff.h',
'src/core/ext/transport/chttp2/transport/flow_control.h',
'src/core/ext/transport/chttp2/transport/frame.h',
@ -2554,8 +2595,11 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/hpack_parser.h',
'src/core/ext/transport/chttp2/transport/hpack_parser_table.h',
'src/core/ext/transport/chttp2/transport/http2_settings.h',
'src/core/ext/transport/chttp2/transport/http2_status.h',
'src/core/ext/transport/chttp2/transport/http2_ztrace_collector.h',
'src/core/ext/transport/chttp2/transport/huffsyms.h',
'src/core/ext/transport/chttp2/transport/internal.h',
'src/core/ext/transport/chttp2/transport/internal_channel_arg_names.h',
'src/core/ext/transport/chttp2/transport/legacy_frame.h',
'src/core/ext/transport/chttp2/transport/ping_abuse_policy.h',
'src/core/ext/transport/chttp2/transport/ping_callbacks.h',
@ -3070,7 +3114,6 @@ Pod::Spec.new do |s|
'src/core/handshaker/tcp_connect/tcp_connect_handshaker.h',
'src/core/lib/address_utils/parse_address.h',
'src/core/lib/address_utils/sockaddr_utils.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',
@ -3079,7 +3122,6 @@ Pod::Spec.new do |s|
'src/core/lib/channel/channel_stack_builder_impl.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/debug/trace.h',
@ -3095,9 +3137,13 @@ Pod::Spec.new do |s|
'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/blocking_dns.h',
'src/core/lib/event_engine/extensions/can_track_errors.h',
'src/core/lib/event_engine/extensions/channelz.h',
'src/core/lib/event_engine/extensions/chaotic_good_extension.h',
'src/core/lib/event_engine/extensions/iomgr_compatible.h',
'src/core/lib/event_engine/extensions/supports_fd.h',
'src/core/lib/event_engine/extensions/supports_win_sockets.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',
@ -3171,7 +3217,6 @@ Pod::Spec.new do |s|
'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/internal_errqueue.h',
'src/core/lib/iomgr/iocp_windows.h',
'src/core/lib/iomgr/iomgr.h',
@ -3273,7 +3318,6 @@ Pod::Spec.new do |s|
'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/connection_context.h',
@ -3283,27 +3327,11 @@ Pod::Spec.new do |s|
'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/transport/bdp_estimator.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/call_state.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/metadata_info.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',
@ -3364,12 +3392,16 @@ Pod::Spec.new do |s|
'src/core/service_config/service_config_impl.h',
'src/core/service_config/service_config_parser.h',
'src/core/telemetry/call_tracer.h',
'src/core/telemetry/context_list_entry.h',
'src/core/telemetry/default_tcp_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/transport/auth_context.h',
'src/core/transport/endpoint_transport.h',
'src/core/transport/endpoint_transport_client_channel_factory.h',
'src/core/tsi/alts/crypt/gsec.h',
'src/core/tsi/alts/frame_protector/alts_counter.h',
'src/core/tsi/alts/frame_protector/alts_crypter.h',
@ -3404,6 +3436,7 @@ Pod::Spec.new do |s|
'src/core/util/avl.h',
'src/core/util/backoff.h',
'src/core/util/bitset.h',
'src/core/util/check_class_size.h',
'src/core/util/chunked_vector.h',
'src/core/util/construct_destruct.h',
'src/core/util/cpp_impl_of.h',
@ -3417,6 +3450,7 @@ Pod::Spec.new do |s|
'src/core/util/event_log.h',
'src/core/util/examine_stack.h',
'src/core/util/fork.h',
'src/core/util/function_signature.h',
'src/core/util/gcp_metadata_query.h',
'src/core/util/gethostname.h',
'src/core/util/glob.h',
@ -3453,6 +3487,7 @@ Pod::Spec.new do |s|
'src/core/util/ref_counted_ptr.h',
'src/core/util/ref_counted_string.h',
'src/core/util/ring_buffer.h',
'src/core/util/shared_bit_gen.h',
'src/core/util/single_set_ptr.h',
'src/core/util/sorted_pack.h',
'src/core/util/spinlock.h',
@ -3572,8 +3607,8 @@ Pod::Spec.new do |s|
'third_party/upb/upb/message/copy.h',
'third_party/upb/upb/message/internal/accessors.h',
'third_party/upb/upb/message/internal/array.h',
'third_party/upb/upb/message/internal/compare_unknown.h',
'third_party/upb/upb/message/internal/extension.h',
'third_party/upb/upb/message/internal/iterator.h',
'third_party/upb/upb/message/internal/map.h',
'third_party/upb/upb/message/internal/map_entry.h',
'third_party/upb/upb/message/internal/map_sorter.h',
@ -3661,6 +3696,8 @@ Pod::Spec.new do |s|
'third_party/upb/upb/wire/reader.h',
'third_party/upb/upb/wire/types.h',
'third_party/utf8_range/utf8_range.h',
'third_party/utf8_range/utf8_range_neon.inc',
'third_party/utf8_range/utf8_range_sse.inc',
'third_party/xxhash/xxhash.h',
'third_party/zlib/crc32.h',
'third_party/zlib/deflate.h',
@ -3680,28 +3717,6 @@ Pod::Spec.new do |s|
ss.dependency "#{s.name}/Implementation", version
end
s.subspec 'Cronet-Interface' do |ss|
ss.header_mappings_dir = 'include/grpc'
ss.source_files = 'include/grpc/grpc_cronet.h'
end
s.subspec 'Cronet-Implementation' do |ss|
ss.header_mappings_dir = '.'
ss.dependency "#{s.name}/Interface", version
ss.dependency "#{s.name}/Implementation", version
ss.dependency "#{s.name}/Privacy", version
ss.dependency "#{s.name}/Cronet-Interface", version
ss.source_files = 'src/core/ext/transport/cronet/client/secure/cronet_channel_create.cc',
'src/core/ext/transport/cronet/client/secure/cronet_channel_create.h',
'src/core/ext/transport/cronet/transport/cronet_status.cc',
'src/core/ext/transport/cronet/transport/cronet_status.h',
'src/core/ext/transport/cronet/transport/cronet_transport.cc',
'src/core/ext/transport/cronet/transport/cronet_transport.h',
'third_party/objective_c/Cronet/bidirectional_stream_c.h'
end
# patch include of openssl to openssl_grpc
s.prepare_command = <<-END_OF_COMMAND
set -e

View File

@ -21,7 +21,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC-ProtoRPC'
version = '1.72.0-dev'
version = '1.73.1'
s.version = version
s.summary = 'RPC library for Protocol Buffers, based on gRPC'
s.homepage = 'https://grpc.io'
@ -33,8 +33,8 @@ Pod::Spec.new do |s|
:tag => "v#{version}",
}
s.ios.deployment_target = '11.0'
s.osx.deployment_target = '10.14'
s.ios.deployment_target = '15.0'
s.osx.deployment_target = '11.0'
s.tvos.deployment_target = '13.0'
s.watchos.deployment_target = '6.0'
s.visionos.deployment_target = '1.0'
@ -55,7 +55,7 @@ Pod::Spec.new do |s|
ss.header_mappings_dir = "src/objective-c/ProtoRPC"
ss.dependency "#{s.name}/Legacy-Header", version
ss.dependency 'gRPC/Interface', version
ss.dependency 'Protobuf', '~> 3.0'
ss.dependency 'Protobuf', '~> 4.0'
ss.source_files = "src/objective-c/ProtoRPC/ProtoMethod.{h,m}",
"src/objective-c/ProtoRPC/ProtoRPC.{h,m}",
@ -68,7 +68,7 @@ Pod::Spec.new do |s|
ss.dependency "#{s.name}/Legacy-Header", version
ss.dependency 'gRPC/GRPCCore', version
ss.dependency 'gRPC-RxLibrary', version
ss.dependency 'Protobuf', '~> 3.0'
ss.dependency 'Protobuf', '~> 4.0'
ss.source_files = "src/objective-c/ProtoRPC/ProtoRPCLegacy.m",
"src/objective-c/ProtoRPC/ProtoServiceLegacy.m"

View File

@ -21,7 +21,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC-RxLibrary'
version = '1.72.0-dev'
version = '1.73.1'
s.version = version
s.summary = 'Reactive Extensions library for iOS/OSX.'
s.homepage = 'https://grpc.io'
@ -33,8 +33,8 @@ Pod::Spec.new do |s|
:tag => "v#{version}",
}
s.ios.deployment_target = '11.0'
s.osx.deployment_target = '10.14'
s.ios.deployment_target = '15.0'
s.osx.deployment_target = '11.0'
s.tvos.deployment_target = '13.0'
s.watchos.deployment_target = '6.0'
s.visionos.deployment_target = '1.0'

View File

@ -20,7 +20,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC'
version = '1.72.0-dev'
version = '1.73.1'
s.version = version
s.summary = 'gRPC client library for iOS/OSX'
s.homepage = 'https://grpc.io'
@ -45,8 +45,8 @@ Pod::Spec.new do |s|
'CLANG_CXX_LANGUAGE_STANDARD' => 'c++17',
}
s.ios.deployment_target = '11.0'
s.osx.deployment_target = '10.14'
s.ios.deployment_target = '15.0'
s.osx.deployment_target = '11.0'
s.tvos.deployment_target = '13.0'
s.watchos.deployment_target = '6.0'
s.visionos.deployment_target = '1.0'
@ -64,7 +64,6 @@ Pod::Spec.new do |s|
ss.public_header_files = "src/objective-c/GRPCClient/GRPCCall+ChannelArg.h",
"src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h",
"src/objective-c/GRPCClient/GRPCCall+Cronet.h",
"src/objective-c/GRPCClient/GRPCCall+OAuth2.h",
"src/objective-c/GRPCClient/GRPCCall+Tests.h",
"src/objective-c/GRPCClient/GRPCCallLegacy.h",
@ -72,7 +71,6 @@ Pod::Spec.new do |s|
ss.source_files = "src/objective-c/GRPCClient/GRPCCall+ChannelArg.h",
"src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h",
"src/objective-c/GRPCClient/GRPCCall+Cronet.h",
"src/objective-c/GRPCClient/GRPCCall+OAuth2.h",
"src/objective-c/GRPCClient/GRPCCall+Tests.h",
"src/objective-c/GRPCClient/GRPCCallLegacy.h",
@ -80,8 +78,8 @@ Pod::Spec.new do |s|
"src/objective-c/GRPCClient/GRPCTypes.mm"
ss.dependency "gRPC-RxLibrary/Interface", version
ss.dependency "#{s.name}/Privacy", version
s.ios.deployment_target = '11.0'
s.osx.deployment_target = '10.14'
s.ios.deployment_target = '15.0'
s.osx.deployment_target = '11.0'
s.tvos.deployment_target = '13.0'
s.watchos.deployment_target = '6.0'
s.visionos.deployment_target = '1.0'
@ -116,8 +114,8 @@ Pod::Spec.new do |s|
ss.dependency "#{s.name}/Interface-Legacy", version
ss.dependency "#{s.name}/Privacy", version
s.ios.deployment_target = '11.0'
s.osx.deployment_target = '10.14'
s.ios.deployment_target = '15.0'
s.osx.deployment_target = '11.0'
s.tvos.deployment_target = '13.0'
s.watchos.deployment_target = '6.0'
s.visionos.deployment_target = '1.0'
@ -127,7 +125,6 @@ Pod::Spec.new do |s|
ss.header_mappings_dir = 'src/objective-c/GRPCClient'
ss.public_header_files = 'src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h',
'src/objective-c/GRPCClient/GRPCCall+Cronet.h',
'src/objective-c/GRPCClient/GRPCCall+OAuth2.h',
'src/objective-c/GRPCClient/GRPCCall+Tests.h',
'src/objective-c/GRPCClient/GRPCCall+ChannelArg.h'
@ -137,8 +134,6 @@ Pod::Spec.new do |s|
'src/objective-c/GRPCClient/GRPCCall+ChannelArg.mm',
'src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h',
'src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.mm',
'src/objective-c/GRPCClient/GRPCCall+Cronet.h',
'src/objective-c/GRPCClient/GRPCCall+Cronet.mm',
'src/objective-c/GRPCClient/GRPCCall+OAuth2.h',
'src/objective-c/GRPCClient/GRPCCall+OAuth2.mm',
'src/objective-c/GRPCClient/GRPCCall+Tests.h',
@ -154,33 +149,19 @@ Pod::Spec.new do |s|
ss.dependency 'gRPC-Core', version
ss.dependency 'gRPC-RxLibrary', version
s.ios.deployment_target = '11.0'
s.osx.deployment_target = '10.14'
s.ios.deployment_target = '15.0'
s.osx.deployment_target = '11.0'
s.tvos.deployment_target = '13.0'
s.watchos.deployment_target = '6.0'
s.visionos.deployment_target = '1.0'
end
s.subspec 'GRPCCoreCronet' do |ss|
ss.header_mappings_dir = 'src/objective-c/GRPCClient'
ss.source_files = 'src/objective-c/GRPCClient/GRPCCall+Cronet.h',
'src/objective-c/GRPCClient/GRPCCall+Cronet.mm',
'src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/*.{h,mm}'
ss.dependency "#{s.name}/GRPCCore", version
ss.dependency "#{s.name}/Privacy", version
ss.dependency 'gRPC-Core/Cronet-Implementation', version
ss.dependency 'CronetFramework'
ss.ios.deployment_target = '11.0'
end
# CFStream is now default. Leaving this subspec only for compatibility purpose.
s.subspec 'CFStream' do |ss|
ss.dependency "#{s.name}/GRPCCore", version
s.ios.deployment_target = '11.0'
s.osx.deployment_target = '10.14'
s.ios.deployment_target = '15.0'
s.osx.deployment_target = '11.0'
s.tvos.deployment_target = '13.0'
s.watchos.deployment_target = '6.0'
s.visionos.deployment_target = '1.0'
@ -192,8 +173,8 @@ Pod::Spec.new do |s|
ss.source_files = 'src/objective-c/GRPCClient/internal_testing/*.{h,mm}'
ss.header_mappings_dir = 'src/objective-c/GRPCClient'
s.ios.deployment_target = '11.0'
s.osx.deployment_target = '10.14'
s.ios.deployment_target = '15.0'
s.osx.deployment_target = '11.0'
s.tvos.deployment_target = '13.0'
s.watchos.deployment_target = '6.0'
s.visionos.deployment_target = '1.0'

View File

@ -16,11 +16,14 @@
#include <grpc/event_engine/endpoint_config.h>
#include <grpc/event_engine/extensible.h>
#include <grpc/event_engine/internal/write_event.h>
#include <grpc/event_engine/memory_allocator.h>
#include <grpc/event_engine/port.h>
#include <grpc/event_engine/slice_buffer.h>
#include <grpc/support/port_platform.h>
#include <bitset>
#include <initializer_list>
#include <vector>
#include "absl/functional/any_invocable.h"
@ -180,13 +183,26 @@ class EventEngine : public std::enable_shared_from_this<EventEngine>,
/// EventEngine Endpoint Read API call.
///
/// Passed as argument to an Endpoint \a Read
struct ReadArgs {
class ReadArgs final {
public:
ReadArgs() = default;
ReadArgs(const ReadArgs&) = delete;
ReadArgs& operator=(const ReadArgs&) = delete;
ReadArgs(ReadArgs&&) = default;
ReadArgs& operator=(ReadArgs&&) = default;
// A suggestion to the endpoint implementation to read at-least the
// specified number of bytes over the network connection before marking
// the endpoint read operation as complete. gRPC may use this argument
// to minimize the number of endpoint read API calls over the lifetime
// of a connection.
int64_t read_hint_bytes;
void set_read_hint_bytes(int64_t read_hint_bytes) {
read_hint_bytes_ = read_hint_bytes;
}
int64_t read_hint_bytes() const { return read_hint_bytes_; }
private:
int64_t read_hint_bytes_ = 1;
};
/// Reads data from the Endpoint.
///
@ -212,20 +228,110 @@ class EventEngine : public std::enable_shared_from_this<EventEngine>,
/// statuses to \a on_read. For example, callbacks might expect to receive
/// CANCELLED on endpoint shutdown.
virtual bool Read(absl::AnyInvocable<void(absl::Status)> on_read,
SliceBuffer* buffer, const ReadArgs* args) = 0;
SliceBuffer* buffer, ReadArgs args) = 0;
//// The set of write events that can be reported by an Endpoint.
using WriteEvent = ::grpc_event_engine::experimental::internal::WriteEvent;
/// An output WriteMetric consists of a key and a value.
/// The space of keys can be queried from the endpoint via the
/// \a AllWriteMetrics, \a GetMetricName and \a GetMetricKey APIs.
/// The value is an int64_t that is implementation-defined. Check with the
/// endpoint implementation documentation for the semantics of each metric.
struct WriteMetric {
size_t key;
int64_t value;
};
using WriteEventCallback = absl::AnyInvocable<void(
WriteEvent, absl::Time, std::vector<WriteMetric>) const>;
// A bitmask of the events that the caller is interested in.
// Each bit corresponds to an entry in WriteEvent.
using WriteEventSet = std::bitset<static_cast<int>(WriteEvent::kCount)>;
// A sink to receive write events.
// The requested metrics are the keys of the metrics that the caller is
// interested in. The on_event callback will be called on each event
// requested.
class WriteEventSink final {
public:
WriteEventSink(absl::Span<const size_t> requested_metrics,
std::initializer_list<WriteEvent> requested_events,
WriteEventCallback on_event)
: requested_metrics_(requested_metrics),
on_event_(std::move(on_event)) {
for (auto event : requested_events) {
requested_events_mask_.set(static_cast<int>(event));
}
}
absl::Span<const size_t> requested_metrics() const {
return requested_metrics_;
}
bool requested_event(WriteEvent event) const {
return requested_events_mask_.test(static_cast<int>(event));
}
WriteEventSet requested_events_mask() const {
return requested_events_mask_;
}
WriteEventCallback TakeEventCallback() { return std::move(on_event_); }
private:
absl::Span<const size_t> requested_metrics_;
WriteEventSet requested_events_mask_;
// The callback to be called on each event.
WriteEventCallback on_event_;
};
/// A struct representing optional arguments that may be provided to an
/// EventEngine Endpoint Write API call.
///
/// Passed as argument to an Endpoint \a Write
struct WriteArgs {
class WriteArgs final {
public:
WriteArgs() = default;
WriteArgs(const WriteArgs&) = delete;
WriteArgs& operator=(const WriteArgs&) = delete;
WriteArgs(WriteArgs&&) = default;
WriteArgs& operator=(WriteArgs&&) = default;
// A sink to receive write events.
std::optional<WriteEventSink> TakeMetricsSink() {
auto sink = std::move(metrics_sink_);
metrics_sink_.reset();
return sink;
}
bool has_metrics_sink() const { return metrics_sink_.has_value(); }
void set_metrics_sink(WriteEventSink sink) {
metrics_sink_ = std::move(sink);
}
// Represents private information that may be passed by gRPC for
// select endpoints expected to be used only within google.
void* google_specific = nullptr;
// TODO(ctiller): Remove this method once all callers are migrated to
// metrics sink.
void* GetDeprecatedAndDiscouragedGoogleSpecificPointer() {
return google_specific_;
}
void SetDeprecatedAndDiscouragedGoogleSpecificPointer(void* pointer) {
google_specific_ = pointer;
}
// A suggestion to the endpoint implementation to group data to be written
// into frames of the specified max_frame_size. gRPC may use this
// argument to dynamically control the max sizes of frames sent to a
// receiver in response to high receiver memory pressure.
int64_t max_frame_size;
int64_t max_frame_size() const { return max_frame_size_; }
void set_max_frame_size(int64_t max_frame_size) {
max_frame_size_ = max_frame_size;
}
private:
std::optional<WriteEventSink> metrics_sink_;
void* google_specific_ = nullptr;
int64_t max_frame_size_ = 1024 * 1024;
};
/// Writes data out on the connection.
///
@ -248,11 +354,22 @@ class EventEngine : public std::enable_shared_from_this<EventEngine>,
/// statuses to \a on_writable. For example, callbacks might expect to
/// receive CANCELLED on endpoint shutdown.
virtual bool Write(absl::AnyInvocable<void(absl::Status)> on_writable,
SliceBuffer* data, const WriteArgs* args) = 0;
SliceBuffer* data, WriteArgs args) = 0;
/// Returns an address in the format described in DNSResolver. The returned
/// values are expected to remain valid for the life of the Endpoint.
virtual const ResolvedAddress& GetPeerAddress() const = 0;
virtual const ResolvedAddress& GetLocalAddress() const = 0;
/// Returns the list of write metrics that the endpoint supports.
/// The keys are used to identify the metrics in the GetMetricName and
/// GetMetricKey APIs. The current value of the metric can be queried by
/// adding a WriteEventSink to the WriteArgs of a Write call.
virtual std::vector<size_t> AllWriteMetrics() = 0;
/// Returns the name of the write metric with the given key.
/// If the key is not found, returns std::nullopt.
virtual std::optional<absl::string_view> GetMetricName(size_t key) = 0;
/// Returns the key of the write metric with the given name.
/// If the name is not found, returns std::nullopt.
virtual std::optional<size_t> GetMetricKey(absl::string_view name) = 0;
};
/// Called when a new connection is established.
@ -334,7 +451,7 @@ class EventEngine : public std::enable_shared_from_this<EventEngine>,
/// when the object is destroyed and all pending callbacks will be called
/// shortly. If cancellation races with request completion, implementations
/// may choose to either cancel or satisfy the request.
class DNSResolver {
class DNSResolver : public Extensible {
public:
/// Optional configuration for DNSResolvers.
struct ResolverOptions {

View File

@ -0,0 +1,34 @@
// Copyright 2022 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GRPC_EVENT_ENGINE_INTERNAL_WRITE_EVENT_H
#define GRPC_EVENT_ENGINE_INTERNAL_WRITE_EVENT_H
namespace grpc_event_engine::experimental::internal {
// Use of this enum via this name is internal to gRPC.
// API users should get this enumeration via the
// EventEngine::Endpoint::WriteEvent.
enum class WriteEvent {
kSendMsg,
kScheduled,
kSent,
kAcked,
kClosed,
kCount // Must be last.
};
} // namespace grpc_event_engine::experimental::internal
#endif // GRPC_EVENT_ENGINE_INTERNAL_WRITE_EVENT_H

View File

@ -1,37 +0,0 @@
/*
*
* Copyright 2016 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_GRPC_CRONET_H
#define GRPC_GRPC_CRONET_H
#include <grpc/grpc.h>
#include <grpc/support/port_platform.h>
#ifdef __cplusplus
extern "C" {
#endif
GRPCAPI grpc_channel* grpc_cronet_secure_channel_create(
void* engine, const char* target, const grpc_channel_args* args,
void* reserved);
#ifdef __cplusplus
}
#endif
#endif /* GRPC_GRPC_CRONET_H */

View File

@ -31,13 +31,15 @@
#define GRPC_ARG_SERVER_CALL_METRIC_RECORDING \
"grpc.server_call_metric_recording"
/** Request that optional features default to off (regardless of what they
usually default to) - to enable tight control over what gets enabled */
usually default to) - to enable tight control over what gets enabled
Boolean valued. Defaults to false. */
#define GRPC_ARG_MINIMAL_STACK "grpc.minimal_stack"
/** Maximum number of concurrent incoming streams to allow on a http2
connection. Int valued. */
connection. Int valued. Deafult to -1(indicating no explicit limit).*/
#define GRPC_ARG_MAX_CONCURRENT_STREAMS "grpc.max_concurrent_streams"
/** Maximum message length that the channel can receive. Int valued, bytes.
-1 means unlimited. */
-1 means unlimited. Defaults to 4MB(4*1024*1024 bytes). -1 means unlimited.
*/
#define GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH "grpc.max_receive_message_length"
/** \deprecated For backward compatibility.
* Use GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH instead. */
@ -47,27 +49,31 @@
#define GRPC_ARG_MAX_SEND_MESSAGE_LENGTH "grpc.max_send_message_length"
/** Maximum time that a channel may have no outstanding rpcs, after which the
* server will close the connection. Int valued, milliseconds. INT_MAX means
* unlimited. */
* unlimited. Defaults to INT_MAX. */
#define GRPC_ARG_MAX_CONNECTION_IDLE_MS "grpc.max_connection_idle_ms"
/** Maximum time that a channel may exist. Int valued, milliseconds.
* INT_MAX means unlimited. */
/** Maximum amount of time in milliseconds that a connection may exist before it
* will be gracefully shut down. Refer
* https://github.com/grpc/proposal/blob/master/A9-server-side-conn-mgt.md for
* more details. Int valued, defaults to INT_MAX (disabled). */
#define GRPC_ARG_MAX_CONNECTION_AGE_MS "grpc.max_connection_age_ms"
/** Grace period after the channel reaches its max age. Int valued,
milliseconds. INT_MAX means unlimited. */
/** Grace period in milliseconds after connection reaches its max age for
* outstanding RPCs to complete. Int valued, defaults to INT_MAX (disabled). */
#define GRPC_ARG_MAX_CONNECTION_AGE_GRACE_MS "grpc.max_connection_age_grace_ms"
/** Timeout after the last RPC finishes on the client channel at which the
* channel goes back into IDLE state. Int valued, milliseconds. INT_MAX means
* unlimited. The default value is 30 minutes and the min value is 1 second. */
#define GRPC_ARG_CLIENT_IDLE_TIMEOUT_MS "grpc.client_idle_timeout_ms"
/** Enable/disable support for per-message compression. Defaults to 1, unless
GRPC_ARG_MINIMAL_STACK is enabled, in which case it defaults to 0. */
/** Enable/disable support for per-message compression. Boolean valued. Defaults
to true, unless GRPC_ARG_MINIMAL_STACK is enabled, in which case it defaults
to false. */
#define GRPC_ARG_ENABLE_PER_MESSAGE_COMPRESSION "grpc.per_message_compression"
/** Experimental Arg. Enable/disable support for per-message decompression.
Defaults to 1. If disabled, decompression will not be performed and the
application will see the compressed message in the byte buffer. */
#define GRPC_ARG_ENABLE_PER_MESSAGE_DECOMPRESSION \
"grpc.per_message_decompression"
/** Initial stream ID for http2 transports. Int valued. */
/** Initial stream ID for http2 transports. Int valued. Defaults to -1
indicating use of default http2 setting initial stream ID (1). */
#define GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER \
"grpc.http2.initial_sequence_number"
/** Amount to read ahead on individual streams. Defaults to 64kb, larger
@ -75,17 +81,22 @@
NOTE: at some point we'd like to auto-tune this, and this parameter
will become a no-op. Int valued, bytes. */
#define GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES "grpc.http2.lookahead_bytes"
/** How much memory to use for hpack decoding. Int valued, bytes. */
/** How much memory to use for hpack decoding. Int valued, bytes. Defaults to -1
indicating use of default http2 setting(4096 bytes). */
#define GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER \
"grpc.http2.hpack_table_size.decoder"
/** How much memory to use for hpack encoding. Int valued, bytes. */
/** How much memory to use for hpack encoding. Int valued, bytes. Defaults to -1
indicating use of default http2 setting(4096 bytes). */
#define GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER \
"grpc.http2.hpack_table_size.encoder"
/** How big a frame are we willing to receive via HTTP2.
Min 16384, max 16777215. Larger values give lower CPU usage for large
messages, but more head of line blocking for small messages. */
messages, but more head of line blocking for small messages. Defaults to
-1(indicating no explicit max frame size), so it will take standard http/2
specified max frame size to 16 KB. */
#define GRPC_ARG_HTTP2_MAX_FRAME_SIZE "grpc.http2.max_frame_size"
/** Should BDP probing be performed? */
/** Should BDP probing be performed?
Boolean valued. Defaults to true(enabled). */
#define GRPC_ARG_HTTP2_BDP_PROBE "grpc.http2.bdp_probe"
/** (DEPRECATED) Does not have any effect.
Earlier, this arg configured the minimum time between successive ping frames
@ -109,21 +120,24 @@
before the request is cancelled */
#define GRPC_ARG_SERVER_MAX_UNREQUESTED_TIME_IN_SERVER_SECONDS \
"grpc.server_max_unrequested_time_in_server"
/** Channel arg to override the http2 :scheme header */
/** Channel arg to override the http2 :scheme header. String valued. */
#define GRPC_ARG_HTTP2_SCHEME "grpc.http2_scheme"
/** How many pings can the client send before needing to send a data/header
frame? (0 indicates that an infinite number of pings can be sent without
sending a data frame or header frame).
If experiment "max_pings_wo_data_throttle" is enabled, instead of pings being
completely blocked, they are throttled. */
completely blocked, they are throttled.
* Integer valued. Defaults to 2. */
#define GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA \
"grpc.http2.max_pings_without_data"
/** How many misbehaving pings the server can bear before sending goaway and
closing the transport? (0 indicates that the server can bear an infinite
number of misbehaving pings) */
number of misbehaving pings)
* Integer valued. Defaults to 2. */
#define GRPC_ARG_HTTP2_MAX_PING_STRIKES "grpc.http2.max_ping_strikes"
/** How much data are we willing to queue up per stream if
GRPC_WRITE_BUFFER_HINT is set? This is an upper bound */
GRPC_WRITE_BUFFER_HINT is set? This is an upper bound
* Integer valued, bytes. Defaults to 65535 bytes. */
#define GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE "grpc.http2.write_buffer_size"
/** Should we allow receipt of true-binary data on http2 connections?
Defaults to on (1) */
@ -136,33 +150,44 @@
#define GRPC_ARG_EXPERIMENTAL_HTTP2_PREFERRED_CRYPTO_FRAME_SIZE \
"grpc.experimental.http2.enable_preferred_frame_size"
/** After a duration of this time the client/server pings its peer to see if the
transport is still alive. Int valued, milliseconds. */
transport is still alive. Int valued, milliseconds. Defaults to 7200000 (2
hours). */
#define GRPC_ARG_KEEPALIVE_TIME_MS "grpc.keepalive_time_ms"
/** After waiting for a duration of this time, if the keepalive ping sender does
not receive the ping ack, it will close the transport. Int valued,
milliseconds. */
milliseconds. Defaults to 20000 (20 seonds). */
#define GRPC_ARG_KEEPALIVE_TIMEOUT_MS "grpc.keepalive_timeout_ms"
/** Is it permissible to send keepalive pings from the client without any
outstanding streams. Int valued, 0(false)/1(true). */
outstanding streams. Int valued, 0(false)/1(true). Defaults to 0. */
#define GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS \
"grpc.keepalive_permit_without_calls"
/** Default authority to pass if none specified on call construction. A string.
* */
#define GRPC_ARG_DEFAULT_AUTHORITY "grpc.default_authority"
/** Primary user agent: goes at the start of the user-agent metadata
sent on each request. A string. */
sent on each request. A string. Defaults to empty string(""). */
#define GRPC_ARG_PRIMARY_USER_AGENT_STRING "grpc.primary_user_agent"
/** Secondary user agent: goes at the end of the user-agent metadata
sent on each request. A string. */
#define GRPC_ARG_SECONDARY_USER_AGENT_STRING "grpc.secondary_user_agent"
/** The minimum time between subsequent connection attempts, in ms */
/** The minimum time between subsequent connection attempts, in ms. Refer to
* MIN_CONNECT_TIMEOUT from
* https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md. Defaults
* to 20 seconds. */
#define GRPC_ARG_MIN_RECONNECT_BACKOFF_MS "grpc.min_reconnect_backoff_ms"
/** The maximum time between subsequent connection attempts, in ms */
/** The maximum time between subsequent connection attempts, in ms. Refer to
* MAX_BACKOFF from
* https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md. Defaults
* to 120 seconds. */
#define GRPC_ARG_MAX_RECONNECT_BACKOFF_MS "grpc.max_reconnect_backoff_ms"
/** The time between the first and second connection attempts, in ms */
/** The time between the first and second connection attempts, in ms. Refer to
* INITIAL_BACKOFF from
* https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md. Defaults
* to 1 second. */
#define GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS \
"grpc.initial_reconnect_backoff_ms"
/** Minimum amount of time between DNS resolutions, in ms */
/** Minimum amount of time between DNS resolutions, in ms. Defaults to 30
* seconds. */
#define GRPC_ARG_DNS_MIN_TIME_BETWEEN_RESOLUTIONS_MS \
"grpc.dns_min_time_between_resolutions_ms"
/** The timeout used on servers for finishing handshaking on an incoming
@ -178,10 +203,10 @@
#define GRPC_SSL_TARGET_NAME_OVERRIDE_ARG "grpc.ssl_target_name_override"
/** If non-zero, a pointer to a session cache (a pointer of type
grpc_ssl_session_cache*). (use grpc_ssl_session_cache_arg_vtable() to fetch
an appropriate pointer arg vtable) */
an appropriate pointer arg vtable). */
#define GRPC_SSL_SESSION_CACHE_ARG "grpc.ssl_session_cache"
/** If non-zero, it will determine the maximum frame size used by TSI's frame
* protector.
* protector. Defaults to zero.
*/
#define GRPC_ARG_TSI_MAX_FRAME_SIZE "grpc.tsi.max_frame_size"
/** Maximum metadata size (soft limit), in bytes. Note this limit applies to the
@ -200,17 +225,20 @@
#define GRPC_ARG_ALLOW_REUSEPORT "grpc.so_reuseport"
/** If non-zero, a pointer to a buffer pool (a pointer of type
* grpc_resource_quota*). (use grpc_resource_quota_arg_vtable() to fetch an
* appropriate pointer arg vtable) */
* appropriate pointer arg vtable). */
#define GRPC_ARG_RESOURCE_QUOTA "grpc.resource_quota"
/** If non-zero, expand wildcard addresses to a list of local addresses. */
/** If non-zero, expand wildcard addresses to a list of local addresses. Boolean
* valued. */
#define GRPC_ARG_EXPAND_WILDCARD_ADDRS "grpc.expand_wildcard_addrs"
/** Service config data in JSON form.
This value will be ignored if the name resolver returns a service config. */
This value will be ignored if the name resolver returns a service config. A
string value. */
#define GRPC_ARG_SERVICE_CONFIG "grpc.service_config"
/** Disable looking up the service config via the name resolver. */
/** Disable looking up the service config via the name resolver. Boolean valued.
* Defaults to true. */
#define GRPC_ARG_SERVICE_CONFIG_DISABLE_RESOLUTION \
"grpc.service_config_disable_resolution"
/** LB policy name. */
/** LB policy name. A string value.*/
#define GRPC_ARG_LB_POLICY_NAME "grpc.lb_policy_name"
/** Cap for ring size in the ring_hash LB policy. The min and max ring size
values set in the LB policy config will be capped to this value.
@ -223,24 +251,23 @@
/** The maximum amount of memory used by trace events per channel trace node.
* Once the maximum is reached, subsequent events will evict the oldest events
* from the buffer. The unit for this knob is bytes. Setting it to zero causes
* channel tracing to be disabled. */
* channel tracing to be disabled. Defaults to (1024 * 4) bytes. */
#define GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE \
"grpc.max_channel_trace_event_memory_per_node"
/** If non-zero, gRPC library will track stats and information at at per channel
* level. Disabling channelz naturally disables channel tracing. The default
* is for channelz to be enabled. */
#define GRPC_ARG_ENABLE_CHANNELZ "grpc.enable_channelz"
/** If non-zero, Cronet transport will coalesce packets to fewer frames
* when possible. */
#define GRPC_ARG_USE_CRONET_PACKET_COALESCING \
"grpc.use_cronet_packet_coalescing"
/** Channel arg (integer) setting how large a slice to try and read from the
wire each time recvmsg (or equivalent) is called **/
wire each time recvmsg (or equivalent). Range varied from 1
to (32 * 1024 * 1024) bytes. Defaults to 8192 bytes. **/
#define GRPC_ARG_TCP_READ_CHUNK_SIZE "grpc.experimental.tcp_read_chunk_size"
/** Note this is not a "channel arg" key. This is the default slice size to use
* when trying to read from the wire if the GRPC_ARG_TCP_READ_CHUNK_SIZE
* channel arg is unspecified. */
#define GRPC_TCP_DEFAULT_READ_SLICE_SIZE 8192
/** Minimum read chunk size defaults to 256 bytes. Range varies from 1 to (32 *
* 1024 * 1024) bytes. */
#define GRPC_ARG_TCP_MIN_READ_CHUNK_SIZE \
"grpc.experimental.tcp_min_read_chunk_size"
#define GRPC_ARG_TCP_MAX_READ_CHUNK_SIZE \
@ -259,10 +286,12 @@
issued by the tcp_write(). By default, this is set to 4. */
#define GRPC_ARG_TCP_TX_ZEROCOPY_MAX_SIMULT_SENDS \
"grpc.experimental.tcp_tx_zerocopy_max_simultaneous_sends"
/* Overrides the TCP socket receive buffer size, SO_RCVBUF. */
/* Overrides the TCP socket receive buffer size, SO_RCVBUF.
Default value is -1(kReadBufferSizeUnset) indicating that the system will
decide the buffer size. Range varies from 0 to INT_MAX. */
#define GRPC_ARG_TCP_RECEIVE_BUFFER_SIZE "grpc.tcp_receive_buffer_size"
/* Timeout in milliseconds to use for calls to the grpclb load balancer.
If 0 or unset, the balancer calls will have no deadline. */
If 0 or unset, the balancer calls will have no deadline. Defaults to 0 ms. */
#define GRPC_ARG_GRPCLB_CALL_TIMEOUT_MS "grpc.grpclb_call_timeout_ms"
/* Specifies the xDS bootstrap config as a JSON string.
FOR TESTING PURPOSES ONLY -- DO NOT USE IN PRODUCTION.
@ -277,7 +306,7 @@
"grpc.TEST_ONLY_DO_NOT_USE_IN_PROD.xds_bootstrap_config"
/* Timeout in milliseconds to wait for the serverlist from the grpclb load
balancer before using fallback backend addresses from the resolver.
If 0, enter fallback mode immediately. Default value is 10000. */
If 0, enter fallback mode immediately. Default value is 10000ms. */
#define GRPC_ARG_GRPCLB_FALLBACK_TIMEOUT_MS "grpc.grpclb_fallback_timeout_ms"
/* Experimental Arg. Channel args to be used for the control-plane channel
* created to the grpclb load balancers. This is a pointer arg whose value is a
@ -290,9 +319,6 @@
over to the next priority. Default value is 10 seconds. */
#define GRPC_ARG_PRIORITY_FAILOVER_TIMEOUT_MS \
"grpc.priority_failover_timeout_ms"
/** If non-zero, grpc server's cronet compression workaround will be enabled */
#define GRPC_ARG_WORKAROUND_CRONET_COMPRESSION \
"grpc.workaround.cronet_compression"
/** String defining the optimization target for a channel.
Can be: "latency" - attempt to minimize latency at the cost of throughput
"blend" - try to balance latency and throughput
@ -325,13 +351,15 @@
/** Channel arg that carries the bridged objective c object for custom metrics
* logging filter. */
#define GRPC_ARG_MOBILE_LOG_CONTEXT "grpc.mobile_log_context"
/** If non-zero, client authority filter is disabled for the channel */
/** If non-zero, client authority filter is disabled for the channel.
* Boolean valued. Defaults to false. */
#define GRPC_ARG_DISABLE_CLIENT_AUTHORITY_FILTER \
"grpc.disable_client_authority_filter"
/** If set to zero, disables use of http proxies. Enabled by default. */
#define GRPC_ARG_ENABLE_HTTP_PROXY "grpc.enable_http_proxy"
/** Channel arg to set http proxy per channel. If set, the channel arg
* value will be preferred over the environment variable settings. */
* value will be preferred over the environment variable settings. String
* value. */
#define GRPC_ARG_HTTP_PROXY "grpc.http_proxy"
/** Specifies an HTTP proxy to use for individual addresses.
* The proxy must be specified as an IP address, not a DNS name.
@ -347,7 +375,7 @@
agent is surfaced by default. */
#define GRPC_ARG_SURFACE_USER_AGENT "grpc.surface_user_agent"
/** If set, inhibits health checking (which may be enabled via the
* service config.) */
* service config.). Boolean valued. Defaults to false. */
#define GRPC_ARG_INHIBIT_HEALTH_CHECKING "grpc.inhibit_health_checking"
/** If enabled, the channel's DNS resolver queries for SRV records.
* This is useful only when using the "grpclb" load balancing policy,
@ -356,17 +384,17 @@
* https://github.com/grpc/proposal/blob/master/A24-lb-policy-config.md
* https://github.com/grpc/proposal/blob/master/A26-grpclb-selection.md
* Note that this works only with the "ares" DNS resolver; it isn't supported
* by the "native" DNS resolver. */
* by the "native" DNS resolver. Boolean valued. Defaults to false. */
#define GRPC_ARG_DNS_ENABLE_SRV_QUERIES "grpc.dns_enable_srv_queries"
/** If set, determines an upper bound on the number of milliseconds that the
* c-ares based DNS resolver will wait on queries before cancelling them.
* The default value is 120,000. Setting this to "0" will disable the
* The default value is 120,000ms. Setting this to "0" will disable the
* overall timeout entirely. Note that this doesn't include internal c-ares
* timeouts/backoff/retry logic, and so the actual DNS resolution may time out
* sooner than the value specified here. */
#define GRPC_ARG_DNS_ARES_QUERY_TIMEOUT_MS "grpc.dns_ares_query_timeout"
/** If set, uses a local subchannel pool within the channel. Otherwise, uses the
* global subchannel pool. */
* global subchannel pool. Boolean valued. Defaults to false. */
#define GRPC_ARG_USE_LOCAL_SUBCHANNEL_POOL "grpc.use_local_subchannel_pool"
/** gRPC Objective-C channel pooling domain string. */
#define GRPC_ARG_CHANNEL_POOL_DOMAIN "grpc.channel_pooling_domain"

View File

@ -41,8 +41,9 @@ extern "C" {
* Its value is an int from the \a grpc_compression_algorithm enum. */
#define GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM \
"grpc.default_compression_algorithm"
/** Default compression level for the channel.
* Its value is an int from the \a grpc_compression_level enum. */
/** Set the default compression level for the channel.
* Valid values are defined by the enum type grpc_compression_level, defaults to
* GRPC_COMPRESS_LEVEL_NONE. */
#define GRPC_COMPRESSION_CHANNEL_DEFAULT_LEVEL "grpc.default_compression_level"
/** Compression algorithms supported by the channel.
* Its value is a bitset (an int). Bits correspond to algorithms in \a

View File

@ -73,7 +73,7 @@ struct grpc_slice {
} data;
};
#define GRPC_SLICE_BUFFER_INLINE_ELEMENTS 6
#define GRPC_SLICE_BUFFER_INLINE_ELEMENTS 3
/** Represents an expandable array of slices, to be interpreted as a
single item. */

View File

@ -22,6 +22,7 @@
#include <map>
#include <string>
#include <type_traits>
#include <utility>
#include <variant>
#include <vector>
@ -72,27 +73,8 @@ class Json {
json.value_ = NumberValue{std::move(str)};
return json;
}
static Json FromNumber(int32_t value) {
Json json;
json.value_ = NumberValue{absl::StrCat(value)};
return json;
}
static Json FromNumber(uint32_t value) {
Json json;
json.value_ = NumberValue{absl::StrCat(value)};
return json;
}
static Json FromNumber(int64_t value) {
Json json;
json.value_ = NumberValue{absl::StrCat(value)};
return json;
}
static Json FromNumber(uint64_t value) {
Json json;
json.value_ = NumberValue{absl::StrCat(value)};
return json;
}
static Json FromNumber(double value) {
template <typename T>
static std::enable_if_t<std::is_arithmetic_v<T>, Json> FromNumber(T value) {
Json json;
json.value_ = NumberValue{absl::StrCat(value)};
return json;

View File

@ -26,17 +26,20 @@
#define GRPC_DEPRECATED(reason)
#endif // __cplusplus >= 201402L
#ifndef GPR_DISABLE_ABSEIL_SYNC
/*
* Defines GPR_ABSEIL_SYNC to use synchronization features from Abseil
*
* You can opt for gRPC's native synchronization by enabling
* GPR_DISABLE_ABSEIL_SYNC. However, this flag is temporary and will be
* removed once the Abseil synchronization is stabilized.
* If you encounter any issues with this feature, please report them
* by filing a bug at https://github.com/grpc/grpc.
*/
#ifndef GPR_ABSEIL_SYNC
#if defined(__APPLE__)
// This is disabled on Apple platforms because macos/grpc_basictests_c_cpp
// fails with this. https://github.com/grpc/grpc/issues/23661
#else
#define GPR_ABSEIL_SYNC 1
#endif
#endif // GPR_ABSEIL_SYNC
#endif // GPR_DISABLE_ABSEIL_SYNC
/* Get windows.h included everywhere (we need it) */
#if defined(_WIN64) || defined(WIN64) || defined(_WIN32) || defined(WIN32)

View File

@ -23,9 +23,6 @@
* explanation and detailed descriptions of workarounds, see
* /doc/workarounds.md
*/
typedef enum {
GRPC_WORKAROUND_ID_CRONET_COMPRESSION = 0,
GRPC_MAX_WORKAROUND_ID
} grpc_workaround_list;
typedef enum { GRPC_MAX_WORKAROUND_ID } grpc_workaround_list;
#endif /* GRPC_SUPPORT_WORKAROUND_LIST_H */

View File

@ -36,12 +36,12 @@
#include <grpc/support/atm.h>
#include <grpc/support/time.h>
#include <grpcpp/impl/codegen/rpc_service_method.h>
#include <grpcpp/impl/codegen/status.h>
#include <grpcpp/impl/codegen/sync.h>
#include <grpcpp/impl/codegen/time.h>
#include <grpcpp/impl/completion_queue_tag.h>
#include <grpcpp/impl/grpc_library.h>
#include <grpcpp/impl/sync.h>
#include <grpcpp/support/status.h>
#include <list>

View File

@ -116,8 +116,8 @@ class CallbackUnaryHandler : public grpc::internal::MethodHandler {
// A callback that only contains a call to MaybeDone can be run as an
// inline callback regardless of whether or not OnDone is inlineable
// because if the actual OnDone callback needs to be scheduled, MaybeDone
// is responsible for dispatching to an executor thread if needed. Thus,
// when setting up the finish_tag_, we can set its own callback to
// is responsible for dispatching to an EventEngine thread if needed.
// Thus, when setting up the finish_tag_, we can set its own callback to
// inlineable.
finish_tag_.Set(
call_.call(),
@ -152,9 +152,9 @@ class CallbackUnaryHandler : public grpc::internal::MethodHandler {
this->Ref();
// The callback for this function should not be marked inline because it
// is directly invoking a user-controlled reaction
// (OnSendInitialMetadataDone). Thus it must be dispatched to an executor
// thread. However, any OnDone needed after that can be inlined because it
// is already running on an executor thread.
// (OnSendInitialMetadataDone). Thus it must be dispatched to an
// EventEngine thread. However, any OnDone needed after that can be
// inlined because it is already running on an EventEngine thread.
meta_tag_.Set(
call_.call(),
[this](bool ok) {
@ -340,7 +340,7 @@ class CallbackClientStreamingHandler : public grpc::internal::MethodHandler {
this->Ref();
// The callback for this function should not be inlined because it invokes
// a user-controlled reaction, but any resulting OnDone can be inlined in
// the executor to which this callback is dispatched.
// the EventEngine thread to which this callback is dispatched.
meta_tag_.Set(
call_.call(),
[this](bool ok) {
@ -380,7 +380,7 @@ class CallbackClientStreamingHandler : public grpc::internal::MethodHandler {
reactor_.store(reactor, std::memory_order_relaxed);
// The callback for this function should not be inlined because it invokes
// a user-controlled reaction, but any resulting OnDone can be inlined in
// the executor to which this callback is dispatched.
// the EventEngine thread to which this callback is dispatched.
read_tag_.Set(
call_.call(),
[this, reactor](bool ok) {
@ -544,7 +544,7 @@ class CallbackServerStreamingHandler : public grpc::internal::MethodHandler {
this->Ref();
// The callback for this function should not be inlined because it invokes
// a user-controlled reaction, but any resulting OnDone can be inlined in
// the executor to which this callback is dispatched.
// the EventEngine thread to which this callback is dispatched.
meta_tag_.Set(
call_.call(),
[this](bool ok) {
@ -607,7 +607,7 @@ class CallbackServerStreamingHandler : public grpc::internal::MethodHandler {
reactor_.store(reactor, std::memory_order_relaxed);
// The callback for this function should not be inlined because it invokes
// a user-controlled reaction, but any resulting OnDone can be inlined in
// the executor to which this callback is dispatched.
// the EventEngine thread to which this callback is dispatched.
write_tag_.Set(
call_.call(),
[this, reactor](bool ok) {
@ -756,7 +756,7 @@ class CallbackBidiHandler : public grpc::internal::MethodHandler {
this->Ref();
// The callback for this function should not be inlined because it invokes
// a user-controlled reaction, but any resulting OnDone can be inlined in
// the executor to which this callback is dispatched.
// the EventEngine thread to which this callback is dispatched.
meta_tag_.Set(
call_.call(),
[this](bool ok) {
@ -821,7 +821,7 @@ class CallbackBidiHandler : public grpc::internal::MethodHandler {
reactor_.store(reactor, std::memory_order_relaxed);
// The callbacks for these functions should not be inlined because they
// invoke user-controlled reactions, but any resulting OnDones can be
// inlined in the executor to which a callback is dispatched.
// inlined in the EventEngine thread to which a callback is dispatched.
write_tag_.Set(
call_.call(),
[this, reactor](bool ok) {

View File

@ -17,7 +17,7 @@
#include <grpc/grpc_security.h>
#include <grpc/status.h>
#include <grpcpp/impl/codegen/status.h>
#include <grpcpp/support/status.h>
#include <memory>

View File

@ -501,9 +501,9 @@ class ServerContextBase {
void OnCancel() override {}
void OnDone() override {}
// Override InternalInlineable for this class since its reactions are
// trivial and thus do not need to be run from the executor (triggering a
// thread hop). This should only be used by internal reactors (thus the
// name) and not by user application code.
// trivial and thus do not need to be run from the EventEngine (potentially
// triggering a thread hop). This should only be used by internal reactors
// (thus the name) and not by user application code.
bool InternalInlineable() override { return true; }
};

View File

@ -84,8 +84,10 @@ class ChannelArguments {
void SetMaxSendMessageSize(int size);
/// Set LB policy name.
/// Note that if the name resolver returns only balancer addresses, the
/// grpclb LB policy will be used, regardless of what is specified here.
/// Note that this API implicitly provides an empty config for the
/// specified LB policy, so it cannot be used for any policy with
/// required configuration parameters. For those cases, set the LB
/// policy via the service config instead.
void SetLoadBalancingPolicyName(const std::string& lb_policy_name);
/// Set service config in JSON form.

View File

@ -636,8 +636,8 @@ class ClientCallbackReaderWriterImpl
// like StartCall or RemoveHold. If this is the last operation or hold on this
// object, it will invoke the OnDone reaction. If MaybeFinish was called from
// a reaction, it can call OnDone directly. If not, it would need to schedule
// OnDone onto an executor thread to avoid the possibility of deadlocking with
// any locks in the user code that invoked it.
// OnDone onto an EventEngine thread to avoid the possibility of deadlocking
// with any locks in the user code that invoked it.
void MaybeFinish(bool from_reaction) {
if (GPR_UNLIKELY(callbacks_outstanding_.fetch_sub(
1, std::memory_order_acq_rel) == 1)) {

View File

@ -56,7 +56,7 @@ class ServerReactor {
virtual void OnCancel() = 0;
// The following is not API. It is for internal use only and specifies whether
// all reactions of this Reactor can be run without an extra executor
// all reactions of this Reactor can be run without extra EventEngine
// scheduling. This should only be used for internally-defined reactors with
// trivial reactions.
virtual bool InternalInlineable() { return false; }
@ -90,7 +90,7 @@ class ServerCallbackCall {
// advance (used for the ServerContext CompletionOp), and one for where we
// know the inlineability of the OnDone reaction. You should set the inline
// flag to true if either the Reactor is InternalInlineable() or if this
// callback is already being forced to run dispatched to an executor
// callback is already being forced to run dispatched to an EventEngine thread
// (typically because it contains additional work than just the MaybeDone).
void MaybeDone() {
@ -141,12 +141,12 @@ class ServerCallbackCall {
// ever invoked on a fully-Unref'fed ServerCallbackCall.
virtual void CallOnDone() = 0;
// If the OnDone reaction is inlineable, execute it inline. Otherwise send it
// to an executor.
// If the OnDone reaction is inlineable, execute it inline. Otherwise run it
// async on EventEngine.
void ScheduleOnDone(bool inline_ondone);
// If the OnCancel reaction is inlineable, execute it inline. Otherwise send
// it to an executor.
// If the OnCancel reaction is inlineable, execute it inline. Otherwise run it
// async on EventEngine.
void CallOnCancel(ServerReactor* reactor);
// Implement the cancellation constraint counter. Return true if OnCancel

View File

@ -19,9 +19,9 @@
#define GRPCPP_VERSION_INFO_H
#define GRPC_CPP_VERSION_MAJOR 1
#define GRPC_CPP_VERSION_MINOR 72
#define GRPC_CPP_VERSION_PATCH 0
#define GRPC_CPP_VERSION_TAG "dev"
#define GRPC_CPP_VERSION_STRING "1.72.0-dev"
#define GRPC_CPP_VERSION_MINOR 73
#define GRPC_CPP_VERSION_PATCH 1
#define GRPC_CPP_VERSION_TAG ""
#define GRPC_CPP_VERSION_STRING "1.73.1"
#endif // GRPCPP_VERSION_INFO_H
#endif // GRPCPP_VERSION_INFO_H

View File

@ -9,7 +9,7 @@ GRPC_IOS_BUILD_FLAGS="
CODE_SIGNING_ALLOWED=NO
ONLY_ACTIVE_ARCH=NO
ARCHS=arm64
IPHONEOS_DEPLOYMENT_TARGET=12.0
IPHONEOS_DEPLOYMENT_TARGET=15.0
"
# Xcodebuild destination for iOS

View File

@ -28,10 +28,14 @@ targets = (
'grpc_authorization_provider',
'gpr',
'upb_base_lib',
'upb_hash_lib',
'upb_lex_lib',
'upb_mem_lib',
'upb_message_lib',
'upb_mini_descriptor_lib',
'upb_mini_table_lib',
'upb_json_lib',
'upb_reflection_lib',
'upb_textformat_lib',
'upb_wire_lib',
'utf8_range_lib',
@ -53,17 +57,6 @@ extra_files = (
'src/objective-c/!ProtoCompiler-gRPCPlugin.podspec',
'src/objective-c/!ProtoCompiler.podspec',
'src/objective-c/BoringSSL-GRPC.podspec',
# cronet files
'include/grpc/grpc_cronet.h',
'src/core/ext/transport/cronet/client/secure/cronet_channel_create.cc',
'src/core/ext/transport/cronet/client/secure/cronet_channel_create.h',
'src/core/ext/transport/cronet/transport/cronet_status.cc',
'src/core/ext/transport/cronet/transport/cronet_status.h',
'src/core/ext/transport/cronet/transport/cronet_transport.cc',
'src/core/ext/transport/cronet/transport/cronet_transport.h',
'third_party/objective_c/Cronet/bidirectional_stream_c.h',
'include/grpcpp/security/cronet_credentials.h',
'src/cpp/client/cronet_credentials.cc',
# podspec files
'gRPC-C++.podspec',
'gRPC-Core.podspec',

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/core/lib/transport/call_arena_allocator.h"
#include "src/core/call/call_arena_allocator.h"
#include <grpc/support/port_platform.h>

View File

@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GRPC_SRC_CORE_LIB_TRANSPORT_CALL_ARENA_ALLOCATOR_H
#define GRPC_SRC_CORE_LIB_TRANSPORT_CALL_ARENA_ALLOCATOR_H
#ifndef GRPC_SRC_CORE_CALL_CALL_ARENA_ALLOCATOR_H
#define GRPC_SRC_CORE_CALL_CALL_ARENA_ALLOCATOR_H
#include <grpc/support/port_platform.h>
#include <stddef.h>
@ -88,4 +88,4 @@ class CallArenaAllocator final : public ArenaFactory {
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_TRANSPORT_CALL_ARENA_ALLOCATOR_H
#endif // GRPC_SRC_CORE_CALL_CALL_ARENA_ALLOCATOR_H

View File

@ -12,12 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GRPC_SRC_CORE_LIB_TRANSPORT_CALL_DESTINATION_H
#define GRPC_SRC_CORE_LIB_TRANSPORT_CALL_DESTINATION_H
#ifndef GRPC_SRC_CORE_CALL_CALL_DESTINATION_H
#define GRPC_SRC_CORE_CALL_CALL_DESTINATION_H
#include <grpc/support/port_platform.h>
#include "src/core/lib/transport/call_spine.h"
#include "src/core/call/call_spine.h"
#include "src/core/util/orphanable.h"
namespace grpc_core {
@ -73,4 +73,4 @@ auto MakeCallDestinationFromHandlerFunction(HC handle_call) {
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_TRANSPORT_CALL_DESTINATION_H
#endif // GRPC_SRC_CORE_CALL_CALL_DESTINATION_H

View File

@ -12,13 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/core/lib/transport/call_filters.h"
#include "src/core/call/call_filters.h"
#include <grpc/support/port_platform.h>
#include "absl/log/check.h"
#include "absl/log/log.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/call/metadata.h"
#include "src/core/util/crash.h"
namespace grpc_core {

View File

@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GRPC_SRC_CORE_LIB_TRANSPORT_CALL_FILTERS_H
#define GRPC_SRC_CORE_LIB_TRANSPORT_CALL_FILTERS_H
#ifndef GRPC_SRC_CORE_CALL_CALL_FILTERS_H
#define GRPC_SRC_CORE_CALL_CALL_FILTERS_H
#include <grpc/support/port_platform.h>
@ -24,6 +24,9 @@
#include <type_traits>
#include "absl/log/check.h"
#include "src/core/call/call_state.h"
#include "src/core/call/message.h"
#include "src/core/call/metadata.h"
#include "src/core/lib/promise/for_each.h"
#include "src/core/lib/promise/if.h"
#include "src/core/lib/promise/latch.h"
@ -33,9 +36,6 @@
#include "src/core/lib/promise/status_flag.h"
#include "src/core/lib/promise/try_seq.h"
#include "src/core/lib/transport/call_final_info.h"
#include "src/core/lib/transport/call_state.h"
#include "src/core/lib/transport/message.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/util/dump_args.h"
#include "src/core/util/ref_counted.h"
#include "src/core/util/ref_counted_ptr.h"
@ -186,6 +186,12 @@ class NextMessage {
DCHECK(has_value());
return *message_;
}
const Message& value() const {
DCHECK_NE(message_, taken());
DCHECK(ok());
DCHECK(has_value());
return *message_;
}
MessageHandle TakeValue() {
DCHECK_NE(message_, taken());
DCHECK(ok());
@ -200,6 +206,19 @@ class NextMessage {
call_state_ = nullptr;
}
template <typename Sink>
friend void AbslStringify(Sink& sink, const NextMessage& msg) {
if (!msg.ok()) {
sink.Append("<failure>");
return;
}
if (!msg.has_value()) {
sink.Append("<end-of-stream>");
return;
}
AbslStringify(sink, msg.value());
}
private:
static Message* end_of_stream() { return nullptr; }
static Message* error() { return reinterpret_cast<Message*>(1); }
@ -952,6 +971,30 @@ struct AddOpImpl<FilterType, T, R (FilterType::Call::*)(T, FilterType*), impl,
absl::enable_if_t<std::is_same<absl::StatusOr<T>,
PromiseResult<R>>::value>> {
static void Add(FilterType* channel_data, size_t call_offset, Layout<T>& to) {
#if defined(__GNUC__) && __GNUC__ == 9
// Workaround for a bug in GNU C++ 9 compilers that fail to compile this
// class.
class Promise {
public:
Promise(T value, typename FilterType::Call* call_data,
FilterType* channel_data)
: impl_(std::make_unique<R>(
(call_data->*impl)(std::move(value), channel_data))) {}
Poll<ResultOr<T>> PollOnce() {
auto p = (*impl_)();
auto* r = p.value_if_ready();
if (r == nullptr) return Pending{};
this->~Promise();
if (r->ok()) return ResultOr<T>{std::move(**r), nullptr};
return ResultOr<T>{nullptr,
CancelledServerMetadataFromStatus(r->status())};
}
private:
std::unique_ptr<R> impl_;
};
#else
class Promise {
public:
Promise(T value, typename FilterType::Call* call_data,
@ -971,6 +1014,7 @@ struct AddOpImpl<FilterType, T, R (FilterType::Call::*)(T, FilterType*), impl,
private:
GPR_NO_UNIQUE_ADDRESS R impl_;
};
#endif
to.Add(sizeof(Promise), alignof(Promise),
Operator<T>{
channel_data,
@ -1272,7 +1316,7 @@ template <typename T>
GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline OperationExecutor<
T>::~OperationExecutor() {
if (promise_data_ != nullptr) {
ops_->early_destroy(promise_data_);
if (ops_ != end_ops_) ops_->early_destroy(promise_data_);
gpr_free_aligned(promise_data_);
}
}
@ -1305,7 +1349,10 @@ OperationExecutor<T>::InitStep(T input, void* call_data) {
ops_->promise_init(promise_data_, Offset(call_data, ops_->call_offset),
ops_->channel_data, std::move(input));
if (auto* r = p.value_if_ready()) {
if (r->ok == nullptr) return std::move(*r);
if (r->ok == nullptr) {
ops_ = end_ops_;
return std::move(*r);
}
input = std::move(r->ok);
++ops_;
continue;
@ -1399,20 +1446,20 @@ constexpr bool MethodHasChannelAccess<R (T::*)()> = false;
template <typename T, typename R, typename A, typename C>
constexpr bool MethodHasChannelAccess<R (T::*)(A, C)> = true;
template <auto... Ts>
constexpr bool AnyMethodHasChannelAccess =
(MethodHasChannelAccess<decltype(Ts)> || ...);
template <typename... Ts>
constexpr bool AnyMethodHasChannelAccess = (MethodHasChannelAccess<Ts> || ...);
// Composite for a given channel type to determine if any of its interceptors
// fall into this category: later code should use this.
template <typename Derived>
inline constexpr bool CallHasChannelAccess() {
return AnyMethodHasChannelAccess<&Derived::Call::OnClientInitialMetadata,
&Derived::Call::OnClientToServerMessage,
&Derived::Call::OnServerInitialMetadata,
&Derived::Call::OnServerToClientMessage,
&Derived::Call::OnServerTrailingMetadata,
&Derived::Call::OnFinalize>;
return AnyMethodHasChannelAccess<
decltype(&Derived::Call::OnClientInitialMetadata),
decltype(&Derived::Call::OnClientToServerMessage),
decltype(&Derived::Call::OnServerInitialMetadata),
decltype(&Derived::Call::OnServerToClientMessage),
decltype(&Derived::Call::OnServerTrailingMetadata),
decltype(&Derived::Call::OnFinalize)>;
}
} // namespace filters_detail
@ -1623,7 +1670,9 @@ class CallFilters {
}
return FinishStep(executor_.Start(
&(stack_current_->stack->data_.*layout),
std::move(filters_->*input_location), filters_->call_data_));
std::move(filters_->*input_location),
filters_detail::Offset(filters_->call_data_,
stack_current_->call_data_offset)));
} else {
return FinishStep(executor_.Step(filters_->call_data_));
}
@ -1640,9 +1689,10 @@ class CallFilters {
(filters_->call_state_.*on_done)();
return ValueOrFailure<Output>{std::move(r->ok)};
}
return FinishStep(
executor_.Start(&(stack_current_->stack->data_.*layout),
std::move(r->ok), filters_->call_data_));
return FinishStep(executor_.Start(
&(stack_current_->stack->data_.*layout), std::move(r->ok),
filters_detail::Offset(filters_->call_data_,
stack_current_->call_data_offset)));
}
(filters_->call_state_.*on_done)();
filters_->PushServerTrailingMetadata(std::move(r->error));
@ -1680,7 +1730,9 @@ class CallFilters {
}
return FinishStep(executor_.Start(
&(stack_current_->stack->data_.*layout),
std::move(filters_->*input_location), filters_->call_data_));
std::move(filters_->*input_location),
filters_detail::Offset(filters_->call_data_,
stack_current_->call_data_offset)));
} else {
return FinishStep(executor_.Step(filters_->call_data_));
}
@ -1695,9 +1747,10 @@ class CallFilters {
if (stack_current_ == stack_end_) {
return NextMsg{std::move(r->ok), &filters_->call_state_};
}
return FinishStep(
executor_.Start(&(stack_current_->stack->data_.*layout),
std::move(r->ok), filters_->call_data_));
return FinishStep(executor_.Start(
&(stack_current_->stack->data_.*layout), std::move(r->ok),
filters_detail::Offset(filters_->call_data_,
stack_current_->call_data_offset)));
}
(filters_->call_state_.*on_done)();
filters_->PushServerTrailingMetadata(std::move(r->error));
@ -1920,4 +1973,4 @@ static_assert(
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_TRANSPORT_CALL_FILTERS_H
#endif // GRPC_SRC_CORE_CALL_CALL_FILTERS_H

View File

@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GRPC_SRC_CORE_LIB_CHANNEL_CALL_FINALIZATION_H
#define GRPC_SRC_CORE_LIB_CHANNEL_CALL_FINALIZATION_H
#ifndef GRPC_SRC_CORE_CALL_CALL_FINALIZATION_H
#define GRPC_SRC_CORE_CALL_CALL_FINALIZATION_H
#include <grpc/support/port_platform.h>
@ -85,4 +85,4 @@ struct ContextType<CallFinalization> {};
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_CHANNEL_CALL_FINALIZATION_H
#endif // GRPC_SRC_CORE_CALL_CALL_FINALIZATION_H

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/core/lib/transport/call_spine.h"
#include "src/core/call/call_spine.h"
#include <grpc/support/port_platform.h>

View File

@ -12,12 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GRPC_SRC_CORE_LIB_TRANSPORT_CALL_SPINE_H
#define GRPC_SRC_CORE_LIB_TRANSPORT_CALL_SPINE_H
#ifndef GRPC_SRC_CORE_CALL_CALL_SPINE_H
#define GRPC_SRC_CORE_CALL_CALL_SPINE_H
#include <grpc/support/port_platform.h>
#include "absl/log/check.h"
#include "src/core/call/call_arena_allocator.h"
#include "src/core/call/call_filters.h"
#include "src/core/call/message.h"
#include "src/core/call/metadata.h"
#include "src/core/lib/promise/detail/status.h"
#include "src/core/lib/promise/if.h"
#include "src/core/lib/promise/latch.h"
@ -27,10 +31,6 @@
#include "src/core/lib/promise/promise.h"
#include "src/core/lib/promise/status_flag.h"
#include "src/core/lib/promise/try_seq.h"
#include "src/core/lib/transport/call_arena_allocator.h"
#include "src/core/lib/transport/call_filters.h"
#include "src/core/lib/transport/message.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/util/dual_ref_counted.h"
namespace grpc_core {
@ -106,7 +106,8 @@ class CallSpine final : public Party {
void PushServerTrailingMetadata(ServerMetadataHandle md) {
GRPC_TRACE_LOG(call_state, INFO)
<< "[call_state] PushServerTrailingMetadata: " << md->DebugString();
<< "[call_state] PushServerTrailingMetadata: " << this << " "
<< md->DebugString();
call_filters().PushServerTrailingMetadata(std::move(md));
}
@ -134,15 +135,17 @@ class CallSpine final : public Party {
DCHECK(GetContext<Activity>() == this);
using P = promise_detail::PromiseLike<Promise>;
using ResultType = typename P::Result;
return Map(std::move(promise), [this](ResultType r) {
CancelIfFailed(r);
return r;
});
return Map(std::move(promise),
[self = RefAsSubclass<CallSpine>()](ResultType r) {
self->CancelIfFailed(r);
});
}
template <typename StatusType>
void CancelIfFailed(const StatusType& r) {
if (!IsStatusOk(r)) {
GRPC_TRACE_LOG(call_state, INFO)
<< "[call_state] spine " << this << " fails: " << r;
Cancel();
}
}
@ -220,18 +223,16 @@ class CallSpine final : public Party {
void SpawnPushServerToClientMessage(MessageHandle msg) {
server_to_client_serializer()->Spawn(
[msg = std::move(msg), self = RefAsSubclass<CallSpine>()]() mutable {
return Map(self->CancelIfFails(
self->PushServerToClientMessage(std::move(msg))),
[](auto) { return Empty{}; });
return self->CancelIfFails(
self->PushServerToClientMessage(std::move(msg)));
});
}
void SpawnPushClientToServerMessage(MessageHandle msg) {
client_to_server_serializer()->Spawn(
[msg = std::move(msg), self = RefAsSubclass<CallSpine>()]() mutable {
return Map(self->CancelIfFails(
self->PushClientToServerMessage(std::move(msg))),
[](auto) { return Empty{}; });
return self->CancelIfFails(
self->PushClientToServerMessage(std::move(msg)));
});
}
@ -322,36 +323,56 @@ class CallInitiator {
CallInitiator() = default;
explicit CallInitiator(RefCountedPtr<CallSpine> spine)
: spine_(std::move(spine)) {}
: spine_(std::move(spine)) {
DCHECK_NE(spine_.get(), nullptr);
}
// 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 <typename Promise>
auto CancelIfFails(Promise promise) {
DCHECK_NE(spine_.get(), nullptr);
return spine_->CancelIfFails(std::move(promise));
}
auto PullServerInitialMetadata() {
DCHECK_NE(spine_.get(), nullptr);
return spine_->PullServerInitialMetadata();
}
auto PushMessage(MessageHandle message) {
DCHECK_NE(spine_.get(), nullptr);
return spine_->PushClientToServerMessage(std::move(message));
}
void SpawnPushMessage(MessageHandle message) {
DCHECK_NE(spine_.get(), nullptr);
spine_->SpawnPushClientToServerMessage(std::move(message));
}
void FinishSends() { spine_->FinishSends(); }
void FinishSends() {
DCHECK_NE(spine_.get(), nullptr);
spine_->FinishSends();
}
void SpawnFinishSends() { spine_->SpawnFinishSends(); }
void SpawnFinishSends() {
DCHECK_NE(spine_.get(), nullptr);
spine_->SpawnFinishSends();
}
auto PullMessage() { return spine_->PullServerToClientMessage(); }
auto PullMessage() {
DCHECK_NE(spine_.get(), nullptr);
return spine_->PullServerToClientMessage();
}
auto PullServerTrailingMetadata() {
DCHECK_NE(spine_.get(), nullptr);
return spine_->PullServerTrailingMetadata();
}
void Cancel(absl::Status error) {
DCHECK_NE(spine_.get(), nullptr);
CHECK(!error.ok());
auto status = ServerMetadataFromStatus(error);
status->Set(GrpcCallWasCancelled(), true);
@ -359,52 +380,72 @@ class CallInitiator {
}
void SpawnCancel(absl::Status error) {
DCHECK_NE(spine_.get(), nullptr);
CHECK(!error.ok());
auto status = ServerMetadataFromStatus(error);
status->Set(GrpcCallWasCancelled(), true);
spine_->SpawnPushServerTrailingMetadata(std::move(status));
}
void Cancel() { spine_->Cancel(); }
void Cancel() {
DCHECK_NE(spine_.get(), nullptr);
spine_->Cancel();
}
void SpawnCancel() { spine_->SpawnCancel(); }
void SpawnCancel() {
DCHECK_NE(spine_.get(), nullptr);
spine_->SpawnCancel();
}
GRPC_MUST_USE_RESULT bool OnDone(absl::AnyInvocable<void(bool)> fn) {
DCHECK_NE(spine_.get(), nullptr);
return spine_->OnDone(std::move(fn));
}
template <typename Promise>
auto UntilCallCompletes(Promise promise) {
DCHECK_NE(spine_.get(), nullptr);
return spine_->UntilCallCompletes(std::move(promise));
}
template <typename PromiseFactory>
void SpawnGuarded(absl::string_view name, PromiseFactory promise_factory) {
DCHECK_NE(spine_.get(), nullptr);
spine_->SpawnGuarded(name, std::move(promise_factory));
}
template <typename PromiseFactory>
void SpawnGuardedUntilCallCompletes(absl::string_view name,
PromiseFactory promise_factory) {
DCHECK_NE(spine_.get(), nullptr);
spine_->SpawnGuardedUntilCallCompletes(name, std::move(promise_factory));
}
template <typename PromiseFactory>
void SpawnInfallible(absl::string_view name, PromiseFactory promise_factory) {
DCHECK_NE(spine_.get(), nullptr);
spine_->SpawnInfallible(name, std::move(promise_factory));
}
template <typename PromiseFactory>
auto SpawnWaitable(absl::string_view name, PromiseFactory promise_factory) {
DCHECK_NE(spine_.get(), nullptr);
return spine_->SpawnWaitable(name, std::move(promise_factory));
}
bool WasCancelledPushed() const {
DCHECK_NE(spine_.get(), nullptr);
return spine_->call_filters().WasCancelledPushed();
}
Arena* arena() { return spine_->arena(); }
Party* party() { return spine_.get(); }
Arena* arena() {
DCHECK_NE(spine_.get(), nullptr);
return spine_->arena();
}
Party* party() {
DCHECK_NE(spine_.get(), nullptr);
return spine_.get();
}
private:
friend class CallHandler;
@ -442,6 +483,9 @@ class CallHandler {
return spine_->OnDone(std::move(fn));
}
// 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 <typename Promise>
auto CancelIfFails(Promise promise) {
return spine_->CancelIfFails(std::move(promise));
@ -599,4 +643,4 @@ void ForwardCall(
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_TRANSPORT_CALL_SPINE_H
#endif // GRPC_SRC_CORE_CALL_CALL_SPINE_H

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/core/lib/transport/call_state.h"
#include "src/core/call/call_state.h"
namespace grpc_core {

View File

@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GRPC_SRC_CORE_LIB_TRANSPORT_CALL_STATE_H
#define GRPC_SRC_CORE_LIB_TRANSPORT_CALL_STATE_H
#ifndef GRPC_SRC_CORE_CALL_CALL_STATE_H
#define GRPC_SRC_CORE_CALL_CALL_STATE_H
#include <grpc/support/port_platform.h>
@ -1151,4 +1151,4 @@ CallState::PollServerTrailingMetadataWasPushed() {
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_TRANSPORT_CALL_STATE_H
#endif // GRPC_SRC_CORE_CALL_CALL_STATE_H

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/core/lib/surface/client_call.h"
#include "src/core/call/client_call.h"
#include <grpc/byte_buffer.h>
#include <grpc/compression.h>
@ -42,6 +42,7 @@
#include "absl/log/check.h"
#include "absl/status/status.h"
#include "absl/strings/string_view.h"
#include "src/core/call/metadata.h"
#include "src/core/lib/event_engine/event_engine_context.h"
#include "src/core/lib/promise/all_ok.h"
#include "src/core/lib/promise/status_flag.h"
@ -49,7 +50,6 @@
#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/telemetry/stats.h"
#include "src/core/telemetry/stats_data.h"
#include "src/core/util/bitset.h"
@ -404,12 +404,14 @@ void ClientCall::OnReceivedStatus(ServerMetadataHandle server_trailing_metadata,
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();
if (!IsErrorFlattenEnabled() || status != GRPC_STATUS_OK) {
Slice message_slice;
if (Slice* message =
server_trailing_metadata->get_pointer(GrpcMessageMetadata())) {
message_slice = message->Ref();
}
*out_status_details = message_slice.TakeCSlice();
}
*out_status_details = message_slice.TakeCSlice();
if (out_error_string != nullptr) {
if (status != GRPC_STATUS_OK) {
*out_error_string =

View File

@ -12,8 +12,8 @@
// 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
#ifndef GRPC_SRC_CORE_CALL_CLIENT_CALL_H
#define GRPC_SRC_CORE_CALL_CLIENT_CALL_H
#include <grpc/byte_buffer.h>
#include <grpc/compression.h>
@ -40,11 +40,11 @@
#include "absl/status/status.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "src/core/call/metadata.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"
#include "src/core/util/crash.h"
#include "src/core/util/ref_counted.h"
#include "src/core/util/ref_counted_ptr.h"
@ -189,4 +189,4 @@ grpc_call* MakeClientCall(grpc_call* parent_call, uint32_t propagation_mask,
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_SURFACE_CLIENT_CALL_H
#endif // GRPC_SRC_CORE_CALL_CLIENT_CALL_H

View File

@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GRPC_SRC_CORE_LIB_TRANSPORT_CUSTOM_METADATA_H
#define GRPC_SRC_CORE_LIB_TRANSPORT_CUSTOM_METADATA_H
#ifndef GRPC_SRC_CORE_CALL_CUSTOM_METADATA_H
#define GRPC_SRC_CORE_CALL_CUSTOM_METADATA_H
// This file defines two macros: GRPC_CUSTOM_CLIENT_METADATA and
// GRPC_CUSTOM_SERVER_METADATA.
@ -27,4 +27,4 @@
#define GRPC_CUSTOM_CLIENT_METADATA
#define GRPC_CUSTOM_SERVER_METADATA
#endif // GRPC_SRC_CORE_LIB_TRANSPORT_CUSTOM_METADATA_H
#endif // GRPC_SRC_CORE_CALL_CUSTOM_METADATA_H

View File

@ -12,17 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/core/lib/transport/interception_chain.h"
#include "src/core/call/interception_chain.h"
#include <grpc/support/port_platform.h>
#include <cstddef>
#include "src/core/call/call_destination.h"
#include "src/core/call/call_filters.h"
#include "src/core/call/call_spine.h"
#include "src/core/call/metadata.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/transport/call_destination.h"
#include "src/core/lib/transport/call_filters.h"
#include "src/core/lib/transport/call_spine.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/util/match.h"
namespace grpc_core {

View File

@ -12,18 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GRPC_SRC_CORE_LIB_TRANSPORT_INTERCEPTION_CHAIN_H
#define GRPC_SRC_CORE_LIB_TRANSPORT_INTERCEPTION_CHAIN_H
#ifndef GRPC_SRC_CORE_CALL_INTERCEPTION_CHAIN_H
#define GRPC_SRC_CORE_CALL_INTERCEPTION_CHAIN_H
#include <grpc/support/port_platform.h>
#include <memory>
#include <vector>
#include "src/core/lib/transport/call_destination.h"
#include "src/core/lib/transport/call_filters.h"
#include "src/core/lib/transport/call_spine.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/call/call_destination.h"
#include "src/core/call/call_filters.h"
#include "src/core/call/call_spine.h"
#include "src/core/call/metadata.h"
#include "src/core/util/ref_counted.h"
namespace grpc_core {
@ -279,4 +279,4 @@ class InterceptionChainBuilder final {
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_TRANSPORT_INTERCEPTION_CHAIN_H
#endif // GRPC_SRC_CORE_CALL_INTERCEPTION_CHAIN_H

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/core/lib/transport/message.h"
#include "src/core/call/message.h"
#include <grpc/impl/grpc_types.h>
#include <grpc/support/port_platform.h>

View File

@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GRPC_SRC_CORE_LIB_TRANSPORT_MESSAGE_H
#define GRPC_SRC_CORE_LIB_TRANSPORT_MESSAGE_H
#ifndef GRPC_SRC_CORE_CALL_MESSAGE_H
#define GRPC_SRC_CORE_CALL_MESSAGE_H
#include <grpc/support/port_platform.h>
@ -47,6 +47,10 @@ class Message {
SliceBuffer* payload() { return &payload_; }
const SliceBuffer* payload() const { return &payload_; }
Arena::PoolPtr<Message> Clone() const {
return Arena::MakePooled<Message>(payload_.Copy(), flags_);
}
std::string DebugString() const;
template <typename Sink>
@ -63,4 +67,4 @@ using MessageHandle = Arena::PoolPtr<Message>;
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_TRANSPORT_MESSAGE_H
#endif // GRPC_SRC_CORE_CALL_MESSAGE_H

View File

@ -12,12 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/core/lib/transport/metadata.h"
#include "src/core/call/metadata.h"
#include <grpc/support/port_platform.h>
#include "src/core/call/metadata_batch.h"
#include "src/core/lib/transport/error_utils.h"
#include "src/core/lib/transport/metadata_batch.h"
namespace grpc_core {

View File

@ -12,13 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GRPC_SRC_CORE_LIB_TRANSPORT_METADATA_H
#define GRPC_SRC_CORE_LIB_TRANSPORT_METADATA_H
#ifndef GRPC_SRC_CORE_CALL_METADATA_H
#define GRPC_SRC_CORE_CALL_METADATA_H
#include <grpc/support/port_platform.h>
#include "src/core/call/metadata_batch.h"
#include "src/core/lib/promise/try_seq.h"
#include "src/core/lib/transport/metadata_batch.h"
namespace grpc_core {
@ -62,6 +62,16 @@ class ServerMetadataOrHandle {
return value_;
}
ServerMetadataHandle TakeMetadata() && {
CHECK(!ok());
return std::move(server_metadata_);
}
ValueType TakeValue() && {
CHECK(ok());
return std::move(value_);
}
private:
ServerMetadataOrHandle(ServerMetadataHandle server_metadata, ValueType value)
: server_metadata_(std::move(server_metadata)),
@ -85,6 +95,13 @@ struct FailureStatusCastImpl<ServerMetadataOrHandle<T>, ServerMetadataHandle&> {
}
};
template <>
struct FailureStatusCastImpl<ServerMetadataHandle, ServerMetadataHandle&> {
static ServerMetadataHandle Cast(ServerMetadataHandle& t) {
return std::move(t);
}
};
template <typename T>
inline bool IsStatusOk(const ServerMetadataOrHandle<T>& x) {
return x.ok();
@ -198,4 +215,4 @@ struct StatusCastImpl<
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_TRANSPORT_METADATA_H
#endif // GRPC_SRC_CORE_CALL_METADATA_H

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/call/metadata_batch.h"
#include <grpc/support/port_platform.h>
#include <string.h>

View File

@ -16,8 +16,8 @@
//
//
#ifndef GRPC_SRC_CORE_LIB_TRANSPORT_METADATA_BATCH_H
#define GRPC_SRC_CORE_LIB_TRANSPORT_METADATA_BATCH_H
#ifndef GRPC_SRC_CORE_CALL_METADATA_BATCH_H
#define GRPC_SRC_CORE_CALL_METADATA_BATCH_H
#include <grpc/impl/compression_types.h>
#include <grpc/status.h>
@ -36,14 +36,14 @@
#include "absl/meta/type_traits.h"
#include "absl/strings/numbers.h"
#include "absl/strings/string_view.h"
#include "src/core/call/custom_metadata.h"
#include "src/core/call/metadata_compression_traits.h"
#include "src/core/call/parsed_metadata.h"
#include "src/core/call/simple_slice_based_metadata.h"
#include "src/core/lib/compression/compression_internal.h"
#include "src/core/lib/experiments/experiments.h"
#include "src/core/lib/promise/poll.h"
#include "src/core/lib/slice/slice.h"
#include "src/core/lib/transport/custom_metadata.h"
#include "src/core/lib/transport/metadata_compression_traits.h"
#include "src/core/lib/transport/parsed_metadata.h"
#include "src/core/lib/transport/simple_slice_based_metadata.h"
#include "src/core/util/chunked_vector.h"
#include "src/core/util/if_list.h"
#include "src/core/util/packed_table.h"
@ -1665,4 +1665,4 @@ struct grpc_metadata_batch : public grpc_metadata_batch_base {
using grpc_metadata_batch_base::grpc_metadata_batch_base;
};
#endif // GRPC_SRC_CORE_LIB_TRANSPORT_METADATA_BATCH_H
#endif // GRPC_SRC_CORE_CALL_METADATA_BATCH_H

View File

@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GRPC_SRC_CORE_LIB_TRANSPORT_METADATA_COMPRESSION_TRAITS_H
#define GRPC_SRC_CORE_LIB_TRANSPORT_METADATA_COMPRESSION_TRAITS_H
#ifndef GRPC_SRC_CORE_CALL_METADATA_COMPRESSION_TRAITS_H
#define GRPC_SRC_CORE_CALL_METADATA_COMPRESSION_TRAITS_H
#include <grpc/support/port_platform.h>
#include <stddef.h>
@ -63,4 +63,4 @@ struct HttpStatusCompressor {};
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_TRANSPORT_METADATA_COMPRESSION_TRAITS_H
#endif // GRPC_SRC_CORE_CALL_METADATA_COMPRESSION_TRAITS_H

View File

@ -12,17 +12,28 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/core/lib/transport/metadata_info.h"
#include "src/core/call/metadata_info.h"
#include <grpc/support/port_platform.h>
#include <cstddef>
#include <string>
#include "absl/strings/str_cat.h"
#include "src/core/lib/slice/slice.h"
namespace grpc_core {
class MetadataSizesAnnotation::MetadataSizeEncoder {
public:
explicit MetadataSizeEncoder(std::string& summary) : summary_(summary) {}
explicit MetadataSizeEncoder(std::string& summary, uint64_t soft_limit,
uint64_t hard_limit)
: summary_(summary) {
header_ = absl::StrCat("gRPC metadata soft_limit:", soft_limit,
",hard_limit:", hard_limit, ",");
absl::StrAppend(&summary_, header_);
entry_length_ = header_.length();
}
void Encode(const Slice& key, const Slice& value) {
AddToSummary(key.as_string_view(), value.size());
@ -36,18 +47,25 @@ class MetadataSizesAnnotation::MetadataSizeEncoder {
private:
void AddToSummary(absl::string_view key,
size_t value_length) GPR_ATTRIBUTE_NOINLINE {
absl::StrAppend(&summary_, key, ":",
hpack_constants::SizeForEntry(key.size(), value_length),
",");
std::string metadata_str = absl::StrCat(
key, ":", hpack_constants::SizeForEntry(key.size(), value_length), ",");
if ((entry_length_ + metadata_str.length()) < 200) {
// Limit each annotation to 200 bytes.
entry_length_ += metadata_str.length();
absl::StrAppend(&summary_, metadata_str);
} else {
absl::StrAppend(&summary_, ";", header_, metadata_str);
entry_length_ = header_.length() + metadata_str.length();
}
}
std::string& summary_;
std::string header_;
size_t entry_length_ = 0;
};
std::string MetadataSizesAnnotation::ToString() const {
std::string metadata_annotation =
absl::StrCat("gRPC metadata soft_limit:", soft_limit_,
",hard_limit:", hard_limit_, ",");
MetadataSizeEncoder encoder(metadata_annotation);
std::string metadata_annotation;
MetadataSizeEncoder encoder(metadata_annotation, soft_limit_, hard_limit_);
metadata_buffer_->Encode(&encoder);
return metadata_annotation;
}

View File

@ -12,14 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GRPC_SRC_CORE_LIB_TRANSPORT_METADATA_INFO_H
#define GRPC_SRC_CORE_LIB_TRANSPORT_METADATA_INFO_H
#ifndef GRPC_SRC_CORE_CALL_METADATA_INFO_H
#define GRPC_SRC_CORE_CALL_METADATA_INFO_H
#include <grpc/support/port_platform.h>
#include "src/core/call/metadata_batch.h"
#include "src/core/ext/transport/chttp2/transport/hpack_constants.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/telemetry/call_tracer.h"
namespace grpc_core {
@ -82,4 +82,4 @@ class MetadataSizesAnnotation
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_TRANSPORT_METADATA_INFO_H
#endif // GRPC_SRC_CORE_CALL_METADATA_INFO_H

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/core/lib/transport/parsed_metadata.h"
#include "src/core/call/parsed_metadata.h"
#include <grpc/support/port_platform.h>

View File

@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GRPC_SRC_CORE_LIB_TRANSPORT_PARSED_METADATA_H
#define GRPC_SRC_CORE_LIB_TRANSPORT_PARSED_METADATA_H
#ifndef GRPC_SRC_CORE_CALL_PARSED_METADATA_H
#define GRPC_SRC_CORE_CALL_PARSED_METADATA_H
#include <grpc/slice.h>
#include <grpc/support/port_platform.h>
@ -426,4 +426,4 @@ ParsedMetadata<MetadataContainer>::KeyValueVTable(absl::string_view key) {
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_TRANSPORT_PARSED_METADATA_H
#endif // GRPC_SRC_CORE_CALL_PARSED_METADATA_H

View File

@ -17,9 +17,9 @@
#include <utility>
#include "src/core/lib/transport/call_spine.h"
#include "src/core/lib/transport/message.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/call/call_spine.h"
#include "src/core/call/message.h"
#include "src/core/call/metadata.h"
namespace grpc_core {

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/core/lib/surface/server_call.h"
#include "src/core/call/server_call.h"
#include <grpc/byte_buffer.h>
#include <grpc/compression.h>
@ -39,6 +39,8 @@
#include "absl/log/check.h"
#include "absl/strings/string_view.h"
#include "src/core/call/metadata.h"
#include "src/core/call/metadata_batch.h"
#include "src/core/lib/promise/all_ok.h"
#include "src/core/lib/promise/map.h"
#include "src/core/lib/promise/poll.h"
@ -47,8 +49,6 @@
#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"
#include "src/core/util/bitset.h"
#include "src/core/util/latent_see.h"

View File

@ -12,8 +12,8 @@
// 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
#ifndef GRPC_SRC_CORE_CALL_SERVER_CALL_H
#define GRPC_SRC_CORE_CALL_SERVER_CALL_H
#include <grpc/byte_buffer.h>
#include <grpc/compression.h>
@ -43,12 +43,12 @@
#include "absl/status/status.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "src/core/call/metadata.h"
#include "src/core/call/metadata_batch.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"
@ -166,4 +166,4 @@ grpc_call* MakeServerCall(CallHandler call_handler,
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_SURFACE_SERVER_CALL_H
#endif // GRPC_SRC_CORE_CALL_SERVER_CALL_H

View File

@ -12,14 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GRPC_SRC_CORE_LIB_TRANSPORT_SIMPLE_SLICE_BASED_METADATA_H
#define GRPC_SRC_CORE_LIB_TRANSPORT_SIMPLE_SLICE_BASED_METADATA_H
#ifndef GRPC_SRC_CORE_CALL_SIMPLE_SLICE_BASED_METADATA_H
#define GRPC_SRC_CORE_CALL_SIMPLE_SLICE_BASED_METADATA_H
#include <grpc/support/port_platform.h>
#include "absl/strings/string_view.h"
#include "src/core/call/parsed_metadata.h"
#include "src/core/lib/slice/slice.h"
#include "src/core/lib/transport/parsed_metadata.h"
namespace grpc_core {
@ -50,4 +50,4 @@ struct SimpleSliceBasedMetadata {
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_TRANSPORT_SIMPLE_SLICE_BASED_METADATA_H
#endif // GRPC_SRC_CORE_CALL_SIMPLE_SLICE_BASED_METADATA_H

View File

@ -16,7 +16,7 @@
//
//
#include "src/core/lib/channel/status_util.h"
#include "src/core/call/status_util.h"
#include <grpc/support/port_platform.h>
#include <string.h>

View File

@ -16,8 +16,8 @@
//
//
#ifndef GRPC_SRC_CORE_LIB_CHANNEL_STATUS_UTIL_H
#define GRPC_SRC_CORE_LIB_CHANNEL_STATUS_UTIL_H
#ifndef GRPC_SRC_CORE_CALL_STATUS_UTIL_H
#define GRPC_SRC_CORE_CALL_STATUS_UTIL_H
#include <grpc/status.h>
#include <grpc/support/port_platform.h>
@ -77,4 +77,4 @@ absl::Status MaybeRewriteIllegalStatusCode(absl::Status status,
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_CHANNEL_STATUS_UTIL_H
#endif // GRPC_SRC_CORE_CALL_STATUS_UTIL_H

View File

@ -29,7 +29,9 @@
#include "src/core/channelz/channelz.h"
#include "src/core/lib/slice/slice.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/util/ref_counted_ptr.h"
#include "src/core/util/string.h"
#include "src/core/util/sync.h"
#include "src/core/util/time.h"
namespace grpc_core {
@ -52,41 +54,8 @@ ChannelTrace::TraceEvent::TraceEvent(Severity severity, const grpc_slice& data)
ChannelTrace::TraceEvent::~TraceEvent() { CSliceUnref(data_); }
namespace {
const char* SeverityString(ChannelTrace::Severity severity) {
switch (severity) {
case ChannelTrace::Severity::Info:
return "CT_INFO";
case ChannelTrace::Severity::Warning:
return "CT_WARNING";
case ChannelTrace::Severity::Error:
return "CT_ERROR";
default:
GPR_UNREACHABLE_CODE(return "CT_UNKNOWN");
}
}
} // anonymous namespace
Json ChannelTrace::TraceEvent::RenderTraceEvent() const {
char* description = grpc_slice_to_c_string(data_);
Json::Object object = {
{"description", Json::FromString(description)},
{"severity", Json::FromString(SeverityString(severity_))},
{"timestamp", Json::FromString(gpr_format_timespec(timestamp_))},
};
gpr_free(description);
if (referenced_entity_ != nullptr) {
const bool is_channel =
(referenced_entity_->type() == BaseNode::EntityType::kTopLevelChannel ||
referenced_entity_->type() == BaseNode::EntityType::kInternalChannel);
object[is_channel ? "channelRef" : "subchannelRef"] = Json::FromObject({
{(is_channel ? "channelId" : "subchannelId"),
Json::FromString(absl::StrCat(referenced_entity_->uuid()))},
});
}
return Json::FromObject(std::move(object));
RefCountedPtr<BaseNode> ChannelTrace::TraceEvent::referenced_entity() const {
return referenced_entity_;
}
//
@ -115,9 +84,8 @@ void ChannelTrace::AddTraceEventHelper(TraceEvent* new_trace_event) {
// first event case
if (head_trace_ == nullptr) {
head_trace_ = tail_trace_ = new_trace_event;
}
// regular event add case
else {
} else {
// regular event add case
tail_trace_->set_next(new_trace_event);
tail_trace_ = tail_trace_->next();
}
@ -151,6 +119,25 @@ void ChannelTrace::AddTraceEventWithReference(
new TraceEvent(severity, data, std::move(referenced_entity)));
}
std::string ChannelTrace::TraceEvent::description() const {
char* description = grpc_slice_to_c_string(data_);
std::string s(description);
gpr_free(description);
return s;
}
void ChannelTrace::ForEachTraceEventLocked(
absl::FunctionRef<void(gpr_timespec, Severity, std::string,
RefCountedPtr<BaseNode>)>
callback) const {
TraceEvent* it = head_trace_;
while (it != nullptr) {
callback(it->timestamp(), it->severity(), it->description(),
it->referenced_entity());
it = it->next();
}
}
Json ChannelTrace::RenderJson() const {
// Tracing is disabled if max_event_memory_ == 0.
if (max_event_memory_ == 0) {
@ -166,15 +153,36 @@ Json ChannelTrace::RenderJson() const {
Json::FromString(absl::StrCat(num_events_logged_));
}
// Only add in the event list if it is non-empty.
if (head_trace_ != nullptr) {
Json::Array array;
for (TraceEvent* it = head_trace_; it != nullptr; it = it->next()) {
array.emplace_back(it->RenderTraceEvent());
Json::Array array;
ForEachTraceEventLocked([&array](gpr_timespec timestamp, Severity severity,
std::string description,
RefCountedPtr<BaseNode> referenced_entity) {
Json::Object object = {
{"description", Json::FromString(description)},
{"severity", Json::FromString(SeverityString(severity))},
{"timestamp", Json::FromString(gpr_format_timespec(timestamp))},
};
if (referenced_entity != nullptr) {
const bool is_channel =
(referenced_entity->type() ==
BaseNode::EntityType::kTopLevelChannel ||
referenced_entity->type() == BaseNode::EntityType::kInternalChannel);
object[is_channel ? "channelRef" : "subchannelRef"] = Json::FromObject({
{(is_channel ? "channelId" : "subchannelId"),
Json::FromString(absl::StrCat(referenced_entity->uuid()))},
});
}
array.emplace_back(Json::FromObject(std::move(object)));
});
if (!array.empty()) {
object["events"] = Json::FromArray(std::move(array));
}
return Json::FromObject(std::move(object));
}
std::string ChannelTrace::creation_timestamp() const {
return gpr_format_timespec(time_created_);
}
} // namespace channelz
} // namespace grpc_core

View File

@ -24,6 +24,7 @@
#include <grpc/support/time.h>
#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
#include "absl/base/thread_annotations.h"
#include "src/core/util/json/json.h"
@ -54,6 +55,19 @@ class ChannelTrace {
Error
};
static const char* SeverityString(ChannelTrace::Severity severity) {
switch (severity) {
case ChannelTrace::Severity::Info:
return "CT_INFO";
case ChannelTrace::Severity::Warning:
return "CT_WARNING";
case ChannelTrace::Severity::Error:
return "CT_ERROR";
default:
GPR_UNREACHABLE_CODE(return "CT_UNKNOWN");
}
}
// Adds a new trace event to the tracing object
//
// NOTE: each ChannelTrace tracks the memory used by its list of trace
@ -82,6 +96,19 @@ class ChannelTrace {
// object may incorporate the json before rendering.
Json RenderJson() const;
void ForEachTraceEvent(
absl::FunctionRef<void(gpr_timespec, Severity, std::string,
RefCountedPtr<BaseNode>)>
callback) const {
MutexLock lock(&mu_);
ForEachTraceEventLocked(callback);
}
std::string creation_timestamp() const;
uint64_t num_events_logged() const {
MutexLock lock(&mu_);
return num_events_logged_;
}
private:
friend size_t testing::GetSizeofTraceEvent(void);
@ -99,15 +126,15 @@ class ChannelTrace {
~TraceEvent();
// Renders the data inside of this TraceEvent into a json object. This is
// used by the ChannelTrace, when it is rendering itself.
Json RenderTraceEvent() const;
// set and get for the next_ pointer.
TraceEvent* next() const { return next_; }
void set_next(TraceEvent* next) { next_ = next; }
size_t memory_usage() const { return memory_usage_; }
gpr_timespec timestamp() const { return timestamp_; }
Severity severity() const { return severity_; }
std::string description() const;
RefCountedPtr<BaseNode> referenced_entity() const;
private:
const gpr_timespec timestamp_;
@ -121,6 +148,10 @@ class ChannelTrace {
// Internal helper to add and link in a trace event
void AddTraceEventHelper(TraceEvent* new_trace_event);
void ForEachTraceEventLocked(
absl::FunctionRef<void(gpr_timespec, Severity, std::string,
RefCountedPtr<BaseNode>)>) const
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
const size_t max_event_memory_;
const gpr_timespec time_created_;

View File

@ -25,6 +25,10 @@
#include <algorithm>
#include <atomic>
#include <cstdint>
#include <initializer_list>
#include <limits>
#include <string>
#include <tuple>
#include "absl/log/check.h"
#include "absl/status/statusor.h"
@ -39,12 +43,123 @@
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/util/json/json_writer.h"
#include "src/core/util/string.h"
#include "src/core/util/time.h"
#include "src/core/util/uri.h"
#include "src/core/util/useful.h"
namespace grpc_core {
namespace channelz {
//
// DataSink
//
namespace {
class ChildObjectCollector {
public:
void Add(RefCountedPtr<BaseNode> node) {
child_objects_[node->type()].insert(node->uuid());
}
void Add(std::vector<RefCountedPtr<BaseNode>> nodes) {
for (auto& node : nodes) Add(std::move(node));
}
// Calls AddAdditionalInfo to export the collected child objects.
void Finalize(DataSink& sink) {
if (child_objects_.empty()) return;
Json::Object subobjects;
for (const auto& [type, child_objects] : child_objects_) {
std::string key;
switch (type) {
case BaseNode::EntityType::kTopLevelChannel:
case BaseNode::EntityType::kSubchannel:
case BaseNode::EntityType::kListenSocket:
case BaseNode::EntityType::kServer:
case BaseNode::EntityType::kInternalChannel: {
LOG(ERROR)
<< "Nodes of type " << BaseNode::EntityTypeString(type)
<< " not supported for child object collection in DataSink";
continue;
}
case BaseNode::EntityType::kSocket:
key = "subSockets";
break;
case BaseNode::EntityType::kCall:
key = "calls";
break;
}
Json::Array uuids;
uuids.reserve(child_objects.size());
for (int64_t uuid : child_objects) {
uuids.push_back(Json::FromNumber(uuid));
}
subobjects[key] = Json::FromArray(std::move(uuids));
}
sink.AddAdditionalInfo("childObjects", std::move(subobjects));
}
private:
std::map<BaseNode::EntityType, std::set<int64_t>> child_objects_;
};
class JsonDataSink final : public DataSink {
public:
explicit JsonDataSink(Json::Object& output) : output_(output) {
CHECK(output_.find("additionalInfo") == output_.end());
}
~JsonDataSink() {
collector_.Finalize(*this);
if (additional_info_ != nullptr) {
output_["additionalInfo"] =
Json::FromObject(std::move(*additional_info_));
}
}
void AddAdditionalInfo(absl::string_view name,
Json::Object additional_info) override {
if (additional_info_ == nullptr) {
additional_info_ = std::make_unique<Json::Object>();
}
additional_info_->emplace(name,
Json::FromObject(std::move(additional_info)));
}
void AddChildObjects(
std::vector<RefCountedPtr<BaseNode>> child_objects) override {
collector_.Add(std::move(child_objects));
}
private:
Json::Object& output_;
std::unique_ptr<Json::Object> additional_info_;
ChildObjectCollector collector_;
};
class ExplicitJsonDataSink final : public DataSink {
public:
void AddAdditionalInfo(absl::string_view name,
Json::Object additional_info) override {
additional_info_.emplace(name,
Json::FromObject(std::move(additional_info)));
}
void AddChildObjects(
std::vector<RefCountedPtr<BaseNode>> child_objects) override {
collector_.Add(std::move(child_objects));
}
Json::Object Finalize() {
collector_.Finalize(*this);
return std::move(additional_info_);
}
private:
Json::Object additional_info_;
ChildObjectCollector collector_;
};
} // namespace
//
// BaseNode
//
@ -55,13 +170,95 @@ BaseNode::BaseNode(EntityType type, std::string name)
ChannelzRegistry::Register(this);
}
BaseNode::~BaseNode() { ChannelzRegistry::Unregister(uuid_); }
void BaseNode::Orphaned() { ChannelzRegistry::Unregister(this); }
intptr_t BaseNode::UuidSlow() { return ChannelzRegistry::NumberNode(this); }
std::string BaseNode::RenderJsonString() {
Json json = RenderJson();
return JsonDump(json);
}
void BaseNode::PopulateJsonFromDataSources(Json::Object& json) {
JsonDataSink sink(json);
MutexLock lock(&data_sources_mu_);
for (DataSource* data_source : data_sources_) {
data_source->AddData(sink);
}
}
Json::Object BaseNode::AdditionalInfo() {
ExplicitJsonDataSink sink;
MutexLock lock(&data_sources_mu_);
for (DataSource* data_source : data_sources_) {
data_source->AddData(sink);
}
return sink.Finalize();
}
void BaseNode::RunZTrace(
absl::string_view name, Timestamp deadline,
std::map<std::string, std::string> args,
std::shared_ptr<grpc_event_engine::experimental::EventEngine> event_engine,
absl::AnyInvocable<void(Json)> callback) {
// Limit deadline to help contain potential resource exhaustion due to
// tracing.
deadline = std::min(deadline, Timestamp::Now() + Duration::Minutes(10));
auto fail = [&callback, event_engine](absl::Status status) {
event_engine->Run(
[callback = std::move(callback), status = std::move(status)]() mutable {
Json::Object object;
object["status"] = Json::FromString(status.ToString());
callback(Json::FromObject(std::move(object)));
});
};
std::unique_ptr<ZTrace> ztrace;
{
MutexLock lock(&data_sources_mu_);
for (auto* data_source : data_sources_) {
if (auto found_ztrace = data_source->GetZTrace(name);
found_ztrace != nullptr) {
if (ztrace == nullptr) {
ztrace = std::move(found_ztrace);
} else {
fail(absl::InternalError(
absl::StrCat("Ambiguous ztrace handler: ", name)));
return;
}
}
}
}
if (ztrace == nullptr) {
fail(absl::NotFoundError(absl::StrCat("ztrace not found: ", name)));
return;
}
ztrace->Run(deadline, std::move(args), event_engine, std::move(callback));
}
//
// DataSource
//
DataSource::DataSource(RefCountedPtr<BaseNode> node) : node_(std::move(node)) {
if (node_ == nullptr) return;
MutexLock lock(&node_->data_sources_mu_);
node_->data_sources_.push_back(this);
}
DataSource::~DataSource() {
DCHECK(node_ == nullptr) << "DataSource must be ResetDataSource()'d in the "
"most derived class before destruction";
}
void DataSource::ResetDataSource() {
RefCountedPtr<BaseNode> node = std::move(node_);
if (node == nullptr) return;
MutexLock lock(&node->data_sources_mu_);
node->data_sources_.erase(
std::remove(node->data_sources_.begin(), node->data_sources_.end(), this),
node->data_sources_.end());
}
//
// CallCountingHelper
//
@ -80,24 +277,21 @@ void CallCountingHelper::RecordCallSucceeded() {
calls_succeeded_.fetch_add(1, std::memory_order_relaxed);
}
void CallCountingHelper::PopulateCallCounts(Json::Object* json) {
auto calls_started = calls_started_.load(std::memory_order_relaxed);
auto calls_succeeded = calls_succeeded_.load(std::memory_order_relaxed);
auto calls_failed = calls_failed_.load(std::memory_order_relaxed);
auto last_call_started_cycle =
last_call_started_cycle_.load(std::memory_order_relaxed);
//
// CallCounts
//
void CallCounts::PopulateJson(Json::Object& json) const {
if (calls_started != 0) {
(*json)["callsStarted"] = Json::FromString(absl::StrCat(calls_started));
gpr_timespec ts = gpr_convert_clock_type(
gpr_cycle_counter_to_time(last_call_started_cycle), GPR_CLOCK_REALTIME);
(*json)["lastCallStartedTimestamp"] =
Json::FromString(gpr_format_timespec(ts));
json["callsStarted"] = Json::FromString(absl::StrCat(calls_started));
json["lastCallStartedTimestamp"] =
Json::FromString(last_call_started_timestamp());
}
if (calls_succeeded != 0) {
(*json)["callsSucceeded"] = Json::FromString(absl::StrCat(calls_succeeded));
json["callsSucceeded"] = Json::FromString(absl::StrCat(calls_succeeded));
}
if (calls_failed != 0) {
(*json)["callsFailed"] = Json::FromString(absl::StrCat(calls_failed));
json["callsFailed"] = Json::FromString(absl::StrCat(calls_failed));
}
}
@ -121,33 +315,20 @@ void PerCpuCallCountingHelper::RecordCallSucceeded() {
std::memory_order_relaxed);
}
void PerCpuCallCountingHelper::PopulateCallCounts(Json::Object* json) {
int64_t calls_started = 0;
int64_t calls_succeeded = 0;
int64_t calls_failed = 0;
gpr_cycle_counter last_call_started_cycle = 0;
CallCounts PerCpuCallCountingHelper::GetCallCounts() const {
CallCounts call_counts;
for (const auto& cpu : per_cpu_data_) {
calls_started += cpu.calls_started.load(std::memory_order_relaxed);
calls_succeeded += cpu.calls_succeeded.load(std::memory_order_relaxed);
calls_failed += cpu.calls_failed.load(std::memory_order_relaxed);
last_call_started_cycle =
std::max(last_call_started_cycle,
call_counts.calls_started +=
cpu.calls_started.load(std::memory_order_relaxed);
call_counts.calls_succeeded +=
cpu.calls_succeeded.load(std::memory_order_relaxed);
call_counts.calls_failed +=
cpu.calls_failed.load(std::memory_order_relaxed);
call_counts.last_call_started_cycle =
std::max(call_counts.last_call_started_cycle,
cpu.last_call_started_cycle.load(std::memory_order_relaxed));
}
if (calls_started != 0) {
(*json)["callsStarted"] = Json::FromString(absl::StrCat(calls_started));
gpr_timespec ts = gpr_convert_clock_type(
gpr_cycle_counter_to_time(last_call_started_cycle), GPR_CLOCK_REALTIME);
(*json)["lastCallStartedTimestamp"] =
Json::FromString(gpr_format_timespec(ts));
}
if (calls_succeeded != 0) {
(*json)["callsSucceeded"] = Json::FromString(absl::StrCat(calls_succeeded));
}
if (calls_failed != 0) {
(*json)["callsFailed"] = Json::FromString(absl::StrCat(calls_failed));
}
return call_counts;
}
//
@ -179,18 +360,48 @@ const char* ChannelNode::GetChannelConnectivityStateChangeString(
GPR_UNREACHABLE_CODE(return "UNKNOWN");
}
Json ChannelNode::RenderJson() {
Json::Object data = {
{"target", Json::FromString(target_)},
};
namespace {
std::set<intptr_t> ChildIdSet(const BaseNode* parent,
BaseNode::EntityType type) {
std::set<intptr_t> ids;
auto [children, _] = ChannelzRegistry::GetChildrenOfType(
0, parent, type, std::numeric_limits<size_t>::max());
for (const auto& node : children) {
ids.insert(node->uuid());
}
return ids;
}
} // namespace
std::set<intptr_t> ChannelNode::child_channels() const {
return ChildIdSet(this, BaseNode::EntityType::kInternalChannel);
}
std::set<intptr_t> ChannelNode::child_subchannels() const {
return ChildIdSet(this, BaseNode::EntityType::kSubchannel);
}
std::optional<std::string> ChannelNode::connectivity_state() {
// Connectivity state.
// If low-order bit is on, then the field is set.
int state_field = connectivity_state_.load(std::memory_order_relaxed);
if ((state_field & 1) != 0) {
grpc_connectivity_state state =
static_cast<grpc_connectivity_state>(state_field >> 1);
return ConnectivityStateName(state);
}
return std::nullopt;
}
Json ChannelNode::RenderJson() {
Json::Object data = {
{"target", Json::FromString(target_)},
};
if (auto cs = connectivity_state(); cs.has_value()) {
data["state"] = Json::FromObject({
{"state", Json::FromString(ConnectivityStateName(state))},
{"state", Json::FromString(cs.value())},
});
}
// Fill in the channel trace if applicable.
@ -199,7 +410,7 @@ Json ChannelNode::RenderJson() {
data["trace"] = std::move(trace_json);
}
// Ask CallCountingHelper to populate call count data.
call_counter_.PopulateCallCounts(&data);
call_counter_.GetCallCounts().PopulateJson(data);
// Construct outer object.
Json::Object json = {
{"ref", Json::FromObject({
@ -210,23 +421,25 @@ Json ChannelNode::RenderJson() {
// Template method. Child classes may override this to add their specific
// functionality.
PopulateChildRefs(&json);
PopulateJsonFromDataSources(json);
return Json::FromObject(std::move(json));
}
void ChannelNode::PopulateChildRefs(Json::Object* json) {
MutexLock lock(&child_mu_);
if (!child_subchannels_.empty()) {
auto child_subchannels = this->child_subchannels();
auto child_channels = this->child_channels();
if (!child_subchannels.empty()) {
Json::Array array;
for (intptr_t subchannel_uuid : child_subchannels_) {
for (intptr_t subchannel_uuid : child_subchannels) {
array.emplace_back(Json::FromObject({
{"subchannelId", Json::FromString(absl::StrCat(subchannel_uuid))},
}));
}
(*json)["subchannelRef"] = Json::FromArray(std::move(array));
}
if (!child_channels_.empty()) {
if (!child_channels.empty()) {
Json::Array array;
for (intptr_t channel_uuid : child_channels_) {
for (intptr_t channel_uuid : child_channels) {
array.emplace_back(Json::FromObject({
{"channelId", Json::FromString(absl::StrCat(channel_uuid))},
}));
@ -241,26 +454,6 @@ void ChannelNode::SetConnectivityState(grpc_connectivity_state state) {
connectivity_state_.store(state_field, std::memory_order_relaxed);
}
void ChannelNode::AddChildChannel(intptr_t child_uuid) {
MutexLock lock(&child_mu_);
child_channels_.insert(child_uuid);
}
void ChannelNode::RemoveChildChannel(intptr_t child_uuid) {
MutexLock lock(&child_mu_);
child_channels_.erase(child_uuid);
}
void ChannelNode::AddChildSubchannel(intptr_t child_uuid) {
MutexLock lock(&child_mu_);
child_subchannels_.insert(child_uuid);
}
void ChannelNode::RemoveChildSubchannel(intptr_t child_uuid) {
MutexLock lock(&child_mu_);
child_subchannels_.erase(child_uuid);
}
//
// SubchannelNode
//
@ -282,13 +475,17 @@ void SubchannelNode::SetChildSocket(RefCountedPtr<SocketNode> socket) {
child_socket_ = std::move(socket);
}
Json SubchannelNode::RenderJson() {
// Create and fill the data child.
std::string SubchannelNode::connectivity_state() const {
grpc_connectivity_state state =
connectivity_state_.load(std::memory_order_relaxed);
return ConnectivityStateName(state);
}
Json SubchannelNode::RenderJson() {
// Create and fill the data child.
Json::Object data = {
{"state", Json::FromObject({
{"state", Json::FromString(ConnectivityStateName(state))},
{"state", Json::FromString(connectivity_state())},
})},
{"target", Json::FromString(target_)},
};
@ -298,7 +495,7 @@ Json SubchannelNode::RenderJson() {
data["trace"] = std::move(trace_json);
}
// Ask CallCountingHelper to populate call count data.
call_counter_.PopulateCallCounts(&data);
call_counter_.GetCallCounts().PopulateJson(data);
// Construct top-level object.
Json::Object object{
{"ref", Json::FromObject({
@ -320,7 +517,8 @@ Json SubchannelNode::RenderJson() {
}),
});
}
return Json::FromObject(object);
PopulateJsonFromDataSources(object);
return Json::FromObject(std::move(object));
}
//
@ -332,51 +530,25 @@ ServerNode::ServerNode(size_t channel_tracer_max_nodes)
ServerNode::~ServerNode() {}
void ServerNode::AddChildSocket(RefCountedPtr<SocketNode> node) {
MutexLock lock(&child_mu_);
child_sockets_.insert(std::pair(node->uuid(), std::move(node)));
}
void ServerNode::RemoveChildSocket(intptr_t child_uuid) {
MutexLock lock(&child_mu_);
child_sockets_.erase(child_uuid);
}
void ServerNode::AddChildListenSocket(RefCountedPtr<ListenSocketNode> node) {
MutexLock lock(&child_mu_);
child_listen_sockets_.insert(std::pair(node->uuid(), std::move(node)));
}
void ServerNode::RemoveChildListenSocket(intptr_t child_uuid) {
MutexLock lock(&child_mu_);
child_listen_sockets_.erase(child_uuid);
}
std::string ServerNode::RenderServerSockets(intptr_t start_socket_id,
intptr_t max_results) {
CHECK_GE(start_socket_id, 0);
CHECK_GE(max_results, 0);
// If user does not set max_results, we choose 500.
size_t pagination_limit = max_results == 0 ? 500 : max_results;
if (max_results == 0) max_results = 500;
Json::Object object;
{
MutexLock lock(&child_mu_);
size_t sockets_rendered = 0;
// Create list of socket refs.
Json::Array array;
auto it = child_sockets_.lower_bound(start_socket_id);
for (; it != child_sockets_.end() && sockets_rendered < pagination_limit;
++it, ++sockets_rendered) {
array.emplace_back(Json::FromObject({
{"socketId", Json::FromString(absl::StrCat(it->first))},
{"name", Json::FromString(it->second->name())},
}));
}
object["socketRef"] = Json::FromArray(std::move(array));
if (it == child_sockets_.end()) {
object["end"] = Json::FromBool(true);
}
auto [children, end] = ChannelzRegistry::GetChildrenOfType(
start_socket_id, this, BaseNode::EntityType::kSocket, max_results);
// Create list of socket refs.
Json::Array array;
for (const auto& child : children) {
array.emplace_back(Json::FromObject({
{"socketId", Json::FromString(absl::StrCat(child->uuid()))},
{"name", Json::FromString(child->name())},
}));
}
object["socketRef"] = Json::FromArray(std::move(array));
if (end) object["end"] = Json::FromBool(true);
return JsonDump(Json::FromObject(std::move(object)));
}
@ -388,7 +560,7 @@ Json ServerNode::RenderJson() {
data["trace"] = std::move(trace_json);
}
// Ask CallCountingHelper to populate call count data.
call_counter_.PopulateCallCounts(&data);
call_counter_.GetCallCounts().PopulateJson(data);
// Construct top-level object.
Json::Object object = {
{"ref", Json::FromObject({
@ -397,22 +569,47 @@ Json ServerNode::RenderJson() {
{"data", Json::FromObject(std::move(data))},
};
// Render listen sockets.
{
MutexLock lock(&child_mu_);
if (!child_listen_sockets_.empty()) {
Json::Array array;
for (const auto& it : child_listen_sockets_) {
array.emplace_back(Json::FromObject({
{"socketId", Json::FromString(absl::StrCat(it.first))},
{"name", Json::FromString(it.second->name())},
}));
}
object["listenSocket"] = Json::FromArray(std::move(array));
auto [children, _] = ChannelzRegistry::GetChildrenOfType(
0, this, BaseNode::EntityType::kListenSocket,
std::numeric_limits<size_t>::max());
if (!children.empty()) {
Json::Array array;
for (const auto& child : children) {
array.emplace_back(Json::FromObject({
{"socketId", Json::FromString(absl::StrCat(child->uuid()))},
{"name", Json::FromString(child->name())},
}));
}
object["listenSocket"] = Json::FromArray(std::move(array));
}
PopulateJsonFromDataSources(object);
return Json::FromObject(std::move(object));
}
std::map<intptr_t, RefCountedPtr<ListenSocketNode>>
ServerNode::child_listen_sockets() const {
std::map<intptr_t, RefCountedPtr<ListenSocketNode>> result;
auto [children, _] = ChannelzRegistry::GetChildrenOfType(
0, this, BaseNode::EntityType::kListenSocket,
std::numeric_limits<size_t>::max());
for (const auto& child : children) {
result[child->uuid()] = child->RefAsSubclass<ListenSocketNode>();
}
return result;
}
std::map<intptr_t, RefCountedPtr<SocketNode>> ServerNode::child_sockets()
const {
std::map<intptr_t, RefCountedPtr<SocketNode>> result;
auto [children, _] = ChannelzRegistry::GetChildrenOfType(
0, this, BaseNode::EntityType::kSocket,
std::numeric_limits<size_t>::max());
for (const auto& child : children) {
result[child->uuid()] = child->RefAsSubclass<SocketNode>();
}
return result;
}
//
// SocketNode::Security::Tls
//
@ -644,6 +841,7 @@ Json SocketNode::RenderJson() {
}
PopulateSocketAddressJson(&object, "remote", remote_.c_str());
PopulateSocketAddressJson(&object, "local", local_.c_str());
PopulateJsonFromDataSources(object);
return Json::FromObject(std::move(object));
}
@ -652,7 +850,7 @@ Json SocketNode::RenderJson() {
//
ListenSocketNode::ListenSocketNode(std::string local_addr, std::string name)
: BaseNode(EntityType::kSocket, std::move(name)),
: BaseNode(EntityType::kListenSocket, std::move(name)),
local_addr_(std::move(local_addr)) {}
Json ListenSocketNode::RenderJson() {
@ -663,6 +861,21 @@ Json ListenSocketNode::RenderJson() {
})},
};
PopulateSocketAddressJson(&object, "local", local_addr_.c_str());
PopulateJsonFromDataSources(object);
return Json::FromObject(std::move(object));
}
//
// CallNode
//
Json CallNode::RenderJson() {
Json::Object object = {
{"ref", Json::FromObject({
{"callId", Json::FromString(absl::StrCat(uuid()))},
})},
};
PopulateJsonFromDataSources(object);
return Json::FromObject(std::move(object));
}

View File

@ -27,6 +27,7 @@
#include <atomic>
#include <cstdint>
#include <initializer_list>
#include <map>
#include <optional>
#include <set>
@ -34,18 +35,29 @@
#include <utility>
#include "absl/base/thread_annotations.h"
#include "absl/container/flat_hash_set.h"
#include "absl/container/inlined_vector.h"
#include "absl/strings/string_view.h"
#include "src/core/channelz/channel_trace.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/util/dual_ref_counted.h"
#include "src/core/util/json/json.h"
#include "src/core/util/per_cpu.h"
#include "src/core/util/ref_counted.h"
#include "src/core/util/ref_counted_ptr.h"
#include "src/core/util/string.h"
#include "src/core/util/sync.h"
#include "src/core/util/time.h"
#include "src/core/util/time_precise.h"
#include "src/core/util/useful.h"
// Channel arg key for channelz node.
#define GRPC_ARG_CHANNELZ_CHANNEL_NODE "grpc.internal.channelz_channel_node"
#define GRPC_ARG_CHANNELZ_CHANNEL_NODE \
"grpc.internal.no_subchannel.channelz_channel_node"
// Channel arg key for the containing base node
#define GRPC_ARG_CHANNELZ_CONTAINING_BASE_NODE \
"grpc.internal.no_subchannel.channelz_containing_base_node"
// Channel arg key for indicating an internal channel.
#define GRPC_ARG_CHANNELZ_IS_INTERNAL_CHANNEL \
@ -67,6 +79,8 @@ namespace channelz {
class SocketNode;
class ListenSocketNode;
class DataSource;
class ZTrace;
namespace testing {
class CallCountingHelperPeer;
@ -74,7 +88,7 @@ class SubchannelNodePeer;
} // namespace testing
// base class for all channelz entities
class BaseNode : public RefCounted<BaseNode> {
class BaseNode : public DualRefCounted<BaseNode> {
public:
// There are only four high level channelz entities. However, to support
// GetTopChannelsRequest, we split the Channel entity into two different
@ -84,14 +98,58 @@ class BaseNode : public RefCounted<BaseNode> {
kInternalChannel,
kSubchannel,
kServer,
kListenSocket,
kSocket,
kCall,
};
static absl::string_view EntityTypeString(EntityType type) {
switch (type) {
case EntityType::kTopLevelChannel:
return "top_level_channel";
case EntityType::kInternalChannel:
return "internal_channel";
case EntityType::kSubchannel:
return "subchannel";
case EntityType::kServer:
return "server";
case EntityType::kListenSocket:
return "listen_socket";
case EntityType::kSocket:
return "socket";
case EntityType::kCall:
return "call";
}
return "unknown";
}
protected:
BaseNode(EntityType type, std::string name);
public:
~BaseNode() override;
void Orphaned() override;
bool HasParent(const BaseNode* parent) const {
MutexLock lock(&parent_mu_);
return parents_.find(parent) != parents_.end();
}
void AddParent(BaseNode* parent) {
MutexLock lock(&parent_mu_);
parents_.insert(parent->WeakRef());
}
void RemoveParent(BaseNode* parent) {
MutexLock lock(&parent_mu_);
parents_.erase(parent);
}
static absl::string_view ChannelArgName() {
return GRPC_ARG_CHANNELZ_CONTAINING_BASE_NODE;
}
static int ChannelArgsCompare(const BaseNode* a, const BaseNode* b) {
return QsortCompare(a, b);
}
// All children must implement this function.
virtual Json RenderJson() = 0;
@ -101,15 +159,107 @@ class BaseNode : public RefCounted<BaseNode> {
std::string RenderJsonString();
EntityType type() const { return type_; }
intptr_t uuid() const { return uuid_; }
intptr_t uuid() {
const intptr_t id = uuid_.load(std::memory_order_relaxed);
if (id > 0) return id;
return UuidSlow();
}
const std::string& name() const { return name_; }
void RunZTrace(absl::string_view name, Timestamp deadline,
std::map<std::string, std::string> args,
std::shared_ptr<grpc_event_engine::experimental::EventEngine>
event_engine,
absl::AnyInvocable<void(Json output)> callback);
Json::Object AdditionalInfo();
protected:
void PopulateJsonFromDataSources(Json::Object& json);
private:
// to allow the ChannelzRegistry to set uuid_ under its lock.
friend class ChannelzRegistry;
// allow data source to register/unregister itself
friend class DataSource;
using ParentSet = absl::flat_hash_set<WeakRefCountedPtr<BaseNode>,
WeakRefCountedPtrHash<BaseNode>,
WeakRefCountedPtrEq<BaseNode>>;
intptr_t UuidSlow();
const EntityType type_;
intptr_t uuid_;
uint64_t orphaned_index_ = 0; // updated by registry
std::atomic<intptr_t> uuid_;
std::string name_;
Mutex data_sources_mu_;
absl::InlinedVector<DataSource*, 3> data_sources_
ABSL_GUARDED_BY(data_sources_mu_);
BaseNode* prev_; // updated by registry
BaseNode* next_; // updated by registry
mutable Mutex parent_mu_;
ParentSet parents_ ABSL_GUARDED_BY(parent_mu_);
};
class ZTrace {
public:
virtual ~ZTrace() = default;
virtual void Run(Timestamp deadline, std::map<std::string, std::string> args,
std::shared_ptr<grpc_event_engine::experimental::EventEngine>
event_engine,
absl::AnyInvocable<void(Json)>) = 0;
};
class DataSink {
public:
virtual void AddAdditionalInfo(absl::string_view name,
Json::Object additional_info) = 0;
virtual void AddChildObjects(
std::vector<RefCountedPtr<BaseNode>> children) = 0;
protected:
~DataSink() = default;
};
class DataSource {
public:
explicit DataSource(RefCountedPtr<BaseNode> node);
// Add any relevant json fragments to the output.
// This method must not cause the DataSource to be deleted, or else there will
// be a deadlock.
virtual void AddData(DataSink&) {}
// If this data source exports some ztrace, return it here.
virtual std::unique_ptr<ZTrace> GetZTrace(absl::string_view /*name*/) {
return nullptr;
}
protected:
~DataSource();
RefCountedPtr<BaseNode> channelz_node() { return node_; }
// This method must be called in the most derived class's destructor.
// It removes this data source from the node's list of data sources.
// If it is not called, then the AddData() function pointer may be invalid
// when the node is queried.
void ResetDataSource();
private:
RefCountedPtr<BaseNode> node_;
};
struct CallCounts {
int64_t calls_started = 0;
int64_t calls_succeeded = 0;
int64_t calls_failed = 0;
gpr_cycle_counter last_call_started_cycle = 0;
std::string last_call_started_timestamp() const {
return gpr_format_timespec(
gpr_cycle_counter_to_time(last_call_started_cycle));
}
void PopulateJson(Json::Object& json) const;
};
// This class is a helper class for channelz entities that deal with Channels,
@ -124,8 +274,14 @@ class CallCountingHelper final {
void RecordCallFailed();
void RecordCallSucceeded();
// Common rendering of the call count data and last_call_started_timestamp.
void PopulateCallCounts(Json::Object* json);
CallCounts GetCallCounts() const {
return {
calls_started_.load(std::memory_order_relaxed),
calls_succeeded_.load(std::memory_order_relaxed),
calls_failed_.load(std::memory_order_relaxed),
last_call_started_cycle_.load(std::memory_order_relaxed),
};
}
private:
// testing peer friend.
@ -143,8 +299,7 @@ class PerCpuCallCountingHelper final {
void RecordCallFailed();
void RecordCallSucceeded();
// Common rendering of the call count data and last_call_started_timestamp.
void PopulateCallCounts(Json::Object* json);
CallCounts GetCallCounts() const;
private:
// testing peer friend.
@ -167,6 +322,11 @@ class ChannelNode final : public BaseNode {
ChannelNode(std::string target, size_t channel_tracer_max_nodes,
bool is_internal_channel);
void Orphaned() override {
channel_args_ = ChannelArgs();
BaseNode::Orphaned();
}
static absl::string_view ChannelArgName() {
return GRPC_ARG_CHANNELZ_CHANNEL_NODE;
}
@ -190,21 +350,22 @@ class ChannelNode final : public BaseNode {
trace_.AddTraceEventWithReference(severity, data,
std::move(referenced_channel));
}
void SetChannelArgs(const ChannelArgs& channel_args) {
channel_args_ = channel_args;
}
void RecordCallStarted() { call_counter_.RecordCallStarted(); }
void RecordCallFailed() { call_counter_.RecordCallFailed(); }
void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); }
void SetConnectivityState(grpc_connectivity_state state);
// TODO(roth): take in a RefCountedPtr to the child channel so we can retrieve
// the human-readable name.
void AddChildChannel(intptr_t child_uuid);
void RemoveChildChannel(intptr_t child_uuid);
// TODO(roth): take in a RefCountedPtr to the child subchannel so we can
// retrieve the human-readable name.
void AddChildSubchannel(intptr_t child_uuid);
void RemoveChildSubchannel(intptr_t child_uuid);
const std::string& target() const { return target_; }
std::optional<std::string> connectivity_state();
CallCounts GetCallCounts() const { return call_counter_.GetCallCounts(); }
std::set<intptr_t> child_channels() const;
std::set<intptr_t> child_subchannels() const;
const ChannelTrace& trace() const { return trace_; }
const ChannelArgs& channel_args() const { return channel_args_; }
private:
void PopulateChildRefs(Json::Object* json);
@ -212,14 +373,13 @@ class ChannelNode final : public BaseNode {
std::string target_;
CallCountingHelper call_counter_;
ChannelTrace trace_;
// TODO(ctiller): keeping channel args here can create odd circular references
// that are hard to reason about. Consider moving this to a DataSource.
ChannelArgs channel_args_;
// Least significant bit indicates whether the value is set. Remaining
// bits are a grpc_connectivity_state value.
std::atomic<int> connectivity_state_{0};
Mutex child_mu_; // Guards sets below.
std::set<intptr_t> child_channels_;
std::set<intptr_t> child_subchannels_;
};
// Handles channelz bookkeeping for subchannels
@ -228,6 +388,11 @@ class SubchannelNode final : public BaseNode {
SubchannelNode(std::string target_address, size_t channel_tracer_max_nodes);
~SubchannelNode() override;
void Orphaned() override {
channel_args_ = ChannelArgs();
BaseNode::Orphaned();
}
// Sets the subchannel's connectivity state without health checking.
void UpdateConnectivityState(grpc_connectivity_state state);
@ -242,6 +407,9 @@ class SubchannelNode final : public BaseNode {
void AddTraceEvent(ChannelTrace::Severity severity, const grpc_slice& data) {
trace_.AddTraceEvent(severity, data);
}
void SetChannelArgs(const ChannelArgs& channel_args) {
channel_args_ = channel_args;
}
void AddTraceEventWithReference(ChannelTrace::Severity severity,
const grpc_slice& data,
RefCountedPtr<BaseNode> referenced_channel) {
@ -252,16 +420,29 @@ class SubchannelNode final : public BaseNode {
void RecordCallFailed() { call_counter_.RecordCallFailed(); }
void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); }
const std::string& target() const { return target_; }
std::string connectivity_state() const;
CallCounts GetCallCounts() const { return call_counter_.GetCallCounts(); }
RefCountedPtr<SocketNode> child_socket() const {
MutexLock lock(&socket_mu_);
return child_socket_;
}
const ChannelTrace& trace() const { return trace_; }
const ChannelArgs& channel_args() const { return channel_args_; }
private:
// Allows the channel trace test to access trace_.
friend class testing::SubchannelNodePeer;
std::atomic<grpc_connectivity_state> connectivity_state_{GRPC_CHANNEL_IDLE};
Mutex socket_mu_;
mutable Mutex socket_mu_;
RefCountedPtr<SocketNode> child_socket_ ABSL_GUARDED_BY(socket_mu_);
std::string target_;
CallCountingHelper call_counter_;
ChannelTrace trace_;
// TODO(ctiller): keeping channel args here can create odd circular references
// that are hard to reason about. Consider moving this to a DataSource.
ChannelArgs channel_args_;
};
// Handles channelz bookkeeping for servers
@ -271,19 +452,16 @@ class ServerNode final : public BaseNode {
~ServerNode() override;
void Orphaned() override {
channel_args_ = ChannelArgs();
BaseNode::Orphaned();
}
Json RenderJson() override;
std::string RenderServerSockets(intptr_t start_socket_id,
intptr_t max_results);
void AddChildSocket(RefCountedPtr<SocketNode> node);
void RemoveChildSocket(intptr_t child_uuid);
void AddChildListenSocket(RefCountedPtr<ListenSocketNode> node);
void RemoveChildListenSocket(intptr_t child_uuid);
// proxy methods to composed classes.
void AddTraceEvent(ChannelTrace::Severity severity, const grpc_slice& data) {
trace_.AddTraceEvent(severity, data);
@ -294,16 +472,28 @@ class ServerNode final : public BaseNode {
trace_.AddTraceEventWithReference(severity, data,
std::move(referenced_channel));
}
void SetChannelArgs(const ChannelArgs& channel_args) {
channel_args_ = channel_args;
}
void RecordCallStarted() { call_counter_.RecordCallStarted(); }
void RecordCallFailed() { call_counter_.RecordCallFailed(); }
void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); }
CallCounts GetCallCounts() const { return call_counter_.GetCallCounts(); }
std::map<intptr_t, RefCountedPtr<ListenSocketNode>> child_listen_sockets()
const;
std::map<intptr_t, RefCountedPtr<SocketNode>> child_sockets() const;
const ChannelTrace& trace() const { return trace_; }
const ChannelArgs& channel_args() const { return channel_args_; }
private:
PerCpuCallCountingHelper call_counter_;
ChannelTrace trace_;
Mutex child_mu_; // Guards child maps below.
std::map<intptr_t, RefCountedPtr<SocketNode>> child_sockets_;
std::map<intptr_t, RefCountedPtr<ListenSocketNode>> child_listen_sockets_;
// TODO(ctiller): keeping channel args here can create odd circular references
// that are hard to reason about. Consider moving this to a DataSource.
ChannelArgs channel_args_;
};
#define GRPC_ARG_CHANNELZ_SECURITY "grpc.internal.channelz_security"
@ -368,7 +558,51 @@ class SocketNode final : public BaseNode {
const std::string& remote() { return remote_; }
int64_t streams_started() const {
return streams_started_.load(std::memory_order_relaxed);
}
int64_t streams_succeeded() const {
return streams_succeeded_.load(std::memory_order_relaxed);
}
int64_t streams_failed() const {
return streams_failed_.load(std::memory_order_relaxed);
}
int64_t messages_sent() const {
return messages_sent_.load(std::memory_order_relaxed);
}
int64_t messages_received() const {
return messages_received_.load(std::memory_order_relaxed);
}
int64_t keepalives_sent() const {
return keepalives_sent_.load(std::memory_order_relaxed);
}
auto last_local_stream_created_timestamp() const {
return CycleCounterToTimestamp(
last_local_stream_created_cycle_.load(std::memory_order_relaxed));
}
auto last_remote_stream_created_timestamp() const {
return CycleCounterToTimestamp(
last_remote_stream_created_cycle_.load(std::memory_order_relaxed));
}
auto last_message_sent_timestamp() const {
return CycleCounterToTimestamp(
last_message_sent_cycle_.load(std::memory_order_relaxed));
}
auto last_message_received_timestamp() const {
return CycleCounterToTimestamp(
last_message_received_cycle_.load(std::memory_order_relaxed));
}
const std::string& local() const { return local_; }
const std::string& remote() const { return remote_; }
RefCountedPtr<Security> security() const { return security_; }
private:
std::optional<std::string> CycleCounterToTimestamp(
gpr_cycle_counter cycle_counter) const {
return gpr_format_timespec(gpr_cycle_counter_to_time(cycle_counter));
}
std::atomic<int64_t> streams_started_{0};
std::atomic<int64_t> streams_succeeded_{0};
std::atomic<int64_t> streams_failed_{0};
@ -396,6 +630,14 @@ class ListenSocketNode final : public BaseNode {
std::string local_addr_;
};
class CallNode final : public BaseNode {
public:
explicit CallNode(std::string name)
: BaseNode(EntityType::kCall, std::move(name)) {}
Json RenderJson() override;
};
} // namespace channelz
} // namespace grpc_core

View File

@ -24,154 +24,356 @@
#include <grpc/support/string_util.h>
#include <algorithm>
#include <atomic>
#include <cstdint>
#include <cstring>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "absl/log/check.h"
#include "absl/log/log.h"
#include "src/core/channelz/channelz.h"
#include "src/core/config/config_vars.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/util/json/json.h"
#include "src/core/util/json/json_reader.h"
#include "src/core/util/json/json_writer.h"
#include "src/core/util/shared_bit_gen.h"
#include "src/core/util/sync.h"
namespace grpc_core {
namespace channelz {
namespace {
template <typename T>
std::string RenderArray(std::tuple<T, bool> values_and_end,
const std::string& key) {
auto& [values, end] = values_and_end;
Json::Object object;
if (!values.empty()) {
// Create list of channels.
Json::Array array;
for (size_t i = 0; i < values.size(); ++i) {
array.emplace_back(values[i]->RenderJson());
}
object[key] = Json::FromArray(std::move(array));
}
if (end) {
object["end"] = Json::FromBool(true);
}
return JsonDump(Json::FromObject(std::move(object)));
}
const int kPaginationLimit = 100;
Json RemoveAdditionalInfo(const Json& json) {
switch (json.type()) {
case Json::Type::kArray: {
Json::Array out;
for (const auto& node : json.array()) {
out.emplace_back(RemoveAdditionalInfo(node));
}
return Json::FromArray(std::move(out));
} break;
case Json::Type::kObject: {
Json::Object out;
for (const auto& [key, value] : json.object()) {
if (key == "additionalInfo") continue;
out[key] = RemoveAdditionalInfo(value);
}
return Json::FromObject(std::move(out));
} break;
default:
return json;
}
}
} // anonymous namespace
// TODO(ctiller): Temporary hack to remove fields that are objectionable to the
// protobuf parser (because we've not published them in protobuf yet).
char* ApplyHacks(const std::string& json_str) {
return gpr_strdup(StripAdditionalInfoFromJson(json_str).c_str());
}
} // namespace
std::string StripAdditionalInfoFromJson(absl::string_view json_str) {
auto json = JsonParse(json_str);
if (!json.ok()) return gpr_strdup(std::string(json_str).c_str());
return JsonDump(RemoveAdditionalInfo(*json));
}
ChannelzRegistry* ChannelzRegistry::Default() {
static ChannelzRegistry* singleton = new ChannelzRegistry();
return singleton;
}
void ChannelzRegistry::InternalRegister(BaseNode* node) {
MutexLock lock(&mu_);
node->uuid_ = ++uuid_generator_;
node_map_[node->uuid_] = node;
}
void ChannelzRegistry::InternalUnregister(intptr_t uuid) {
CHECK_GE(uuid, 1);
MutexLock lock(&mu_);
CHECK(uuid <= uuid_generator_);
node_map_.erase(uuid);
}
RefCountedPtr<BaseNode> ChannelzRegistry::InternalGet(intptr_t uuid) {
MutexLock lock(&mu_);
if (uuid < 1 || uuid > uuid_generator_) {
return nullptr;
}
auto it = node_map_.find(uuid);
if (it == node_map_.end()) return nullptr;
// Found node. Return only if its refcount is not zero (i.e., when we
// know that there is no other thread about to destroy it).
BaseNode* node = it->second;
return node->RefIfNonZero();
}
std::string ChannelzRegistry::InternalGetTopChannels(
intptr_t start_channel_id) {
std::vector<RefCountedPtr<BaseNode>> top_level_channels;
RefCountedPtr<BaseNode> node_after_pagination_limit;
{
MutexLock lock(&mu_);
for (auto it = node_map_.lower_bound(start_channel_id);
it != node_map_.end(); ++it) {
BaseNode* node = it->second;
RefCountedPtr<BaseNode> node_ref;
if (node->type() == BaseNode::EntityType::kTopLevelChannel &&
(node_ref = node->RefIfNonZero()) != nullptr) {
// Check if we are over pagination limit to determine if we need to set
// the "end" element. If we don't go through this block, we know that
// when the loop terminates, we have <= to kPaginationLimit.
// Note that because we have already increased this node's
// refcount, we need to decrease it, but we can't unref while
// holding the lock, because this may lead to a deadlock.
if (top_level_channels.size() == kPaginationLimit) {
node_after_pagination_limit = std::move(node_ref);
break;
}
top_level_channels.emplace_back(std::move(node_ref));
}
}
}
Json::Object object;
if (!top_level_channels.empty()) {
// Create list of channels.
Json::Array array;
for (size_t i = 0; i < top_level_channels.size(); ++i) {
array.emplace_back(top_level_channels[i]->RenderJson());
}
object["channel"] = Json::FromArray(std::move(array));
}
if (node_after_pagination_limit == nullptr) {
object["end"] = Json::FromBool(true);
}
return JsonDump(Json::FromObject(std::move(object)));
}
std::string ChannelzRegistry::InternalGetServers(intptr_t start_server_id) {
std::vector<RefCountedPtr<BaseNode>> servers;
RefCountedPtr<BaseNode> node_after_pagination_limit;
{
MutexLock lock(&mu_);
for (auto it = node_map_.lower_bound(start_server_id);
it != node_map_.end(); ++it) {
BaseNode* node = it->second;
RefCountedPtr<BaseNode> node_ref;
if (node->type() == BaseNode::EntityType::kServer &&
(node_ref = node->RefIfNonZero()) != nullptr) {
// Check if we are over pagination limit to determine if we need to set
// the "end" element. If we don't go through this block, we know that
// when the loop terminates, we have <= to kPaginationLimit.
// Note that because we have already increased this node's
// refcount, we need to decrease it, but we can't unref while
// holding the lock, because this may lead to a deadlock.
if (servers.size() == kPaginationLimit) {
node_after_pagination_limit = std::move(node_ref);
break;
}
servers.emplace_back(std::move(node_ref));
}
}
}
Json::Object object;
if (!servers.empty()) {
// Create list of servers.
Json::Array array;
for (size_t i = 0; i < servers.size(); ++i) {
array.emplace_back(servers[i]->RenderJson());
}
object["server"] = Json::FromArray(std::move(array));
}
if (node_after_pagination_limit == nullptr) {
object["end"] = Json::FromBool(true);
}
return JsonDump(Json::FromObject(std::move(object)));
std::vector<WeakRefCountedPtr<BaseNode>>
ChannelzRegistry::InternalGetAllEntities() {
return std::get<0>(QueryNodes(
0, [](const BaseNode*) { return true; },
std::numeric_limits<size_t>::max()));
}
void ChannelzRegistry::InternalLogAllEntities() {
std::vector<RefCountedPtr<BaseNode>> nodes;
{
MutexLock lock(&mu_);
for (auto& p : node_map_) {
RefCountedPtr<BaseNode> node = p.second->RefIfNonZero();
if (node != nullptr) {
nodes.emplace_back(std::move(node));
for (const auto& p : InternalGetAllEntities()) {
std::string json = p->RenderJsonString();
LOG(INFO) << json;
}
}
std::string ChannelzRegistry::GetTopChannelsJson(intptr_t start_channel_id) {
return RenderArray(GetTopChannels(start_channel_id), "channel");
}
std::string ChannelzRegistry::GetServersJson(intptr_t start_server_id) {
return RenderArray(GetServers(start_server_id), "server");
}
void ChannelzRegistry::InternalRegister(BaseNode* node) {
DCHECK_EQ(node->uuid_, -1);
const size_t node_shard_index = NodeShardIndex(node);
NodeShard& node_shard = node_shards_[node_shard_index];
MutexLock lock(&node_shard.mu);
node_shard.nursery.AddToHead(node);
}
void ChannelzRegistry::InternalUnregister(BaseNode* node) {
const size_t node_shard_index = NodeShardIndex(node);
NodeShard& node_shard = node_shards_[node_shard_index];
node_shard.mu.Lock();
CHECK_EQ(node->orphaned_index_, 0u);
intptr_t uuid = node->uuid_.load(std::memory_order_relaxed);
NodeList& remove_list = uuid == -1 ? node_shard.nursery : node_shard.numbered;
remove_list.Remove(node);
if (max_orphaned_per_shard_ == 0) {
// We are not tracking orphaned nodes... remove from the index
// if necessary, then exit out.
node_shard.mu.Unlock();
if (uuid != -1) {
MutexLock lock(&index_mu_);
index_.erase(uuid);
}
return;
}
NodeList& add_list =
uuid != -1 ? node_shard.orphaned_numbered : node_shard.orphaned;
// Ref counting: once a node becomes orphaned we add a single weak ref to it.
// We hold that ref until it gets garbage collected later.
node->WeakRef().release();
node->orphaned_index_ = node_shard.next_orphan_index;
CHECK_GT(node->orphaned_index_, 0u);
++node_shard.next_orphan_index;
add_list.AddToHead(node);
if (node_shard.TotalOrphaned() <= max_orphaned_per_shard_) {
// Below recycling thresholds: just exit out
node_shard.mu.Unlock();
return;
}
CHECK_EQ(node_shard.TotalOrphaned(), max_orphaned_per_shard_ + 1);
NodeList* gc_list;
// choose the oldest node to evict, regardless of numbered or not
if (node_shard.orphaned.tail == nullptr) {
CHECK_NE(node_shard.orphaned_numbered.tail, nullptr);
gc_list = &node_shard.orphaned_numbered;
} else if (node_shard.orphaned_numbered.tail == nullptr) {
gc_list = &node_shard.orphaned;
} else if (node_shard.orphaned.tail->orphaned_index_ <
node_shard.orphaned_numbered.tail->orphaned_index_) {
gc_list = &node_shard.orphaned;
} else {
gc_list = &node_shard.orphaned_numbered;
}
auto* n = gc_list->tail;
CHECK_GT(n->orphaned_index_, 0u);
gc_list->Remove(n);
// Note: we capture the reference to n previously added here, and release
// it when this smart pointer is destroyed, outside of any locks.
WeakRefCountedPtr<BaseNode> gcd_node(n);
node_shard.mu.Unlock();
if (gc_list == &node_shard.orphaned_numbered) {
MutexLock lock(&index_mu_);
intptr_t uuid = n->uuid_.load(std::memory_order_relaxed);
index_.erase(uuid);
}
}
void ChannelzRegistry::LoadConfig() {
const auto max_orphaned = ConfigVars::Get().ChannelzMaxOrphanedNodes();
if (max_orphaned == 0) {
max_orphaned_per_shard_ = 0;
} else {
max_orphaned_per_shard_ = std::max<int>(max_orphaned / kNodeShards, 1);
}
}
std::tuple<std::vector<WeakRefCountedPtr<BaseNode>>, bool>
ChannelzRegistry::QueryNodes(
intptr_t start_node, absl::FunctionRef<bool(const BaseNode*)> discriminator,
size_t max_results) {
// Mitigate drain hotspotting by randomizing the drain order each query.
std::vector<size_t> nursery_visitation_order;
for (size_t i = 0; i < kNodeShards; ++i) {
nursery_visitation_order.push_back(i);
}
absl::c_shuffle(nursery_visitation_order, SharedBitGen());
// In the iteration below, even once we have max_results nodes, we need
// to find the next node in order to know if we've hit the end. If we get
// through the loop without returning, then we return end=true. But if we
// find a node to add after we already have max_results nodes, then we
// return with end=false before exiting the loop. However, in the latter
// case, we will have already increased the ref count of the next node,
// so we need to unref it, but we can't do that while holding the lock.
// So instead, we store it in node_after_end, which will be unreffed
// after releasing the lock.
WeakRefCountedPtr<BaseNode> node_after_end;
std::vector<WeakRefCountedPtr<BaseNode>> result;
MutexLock index_lock(&index_mu_);
for (auto it = index_.lower_bound(start_node); it != index_.end(); ++it) {
BaseNode* node = it->second;
if (!discriminator(node)) continue;
auto node_ref = node->WeakRefIfNonZero();
if (node_ref == nullptr) continue;
if (result.size() == max_results) {
node_after_end = std::move(node_ref);
return std::tuple(std::move(result), false);
}
result.emplace_back(std::move(node_ref));
}
for (auto nursery_index : nursery_visitation_order) {
NodeShard& node_shard = node_shards_[nursery_index];
MutexLock shard_lock(&node_shard.mu);
for (auto [nursery, numbered] :
{std::pair(&node_shard.nursery, &node_shard.numbered),
std::pair(&node_shard.orphaned, &node_shard.orphaned_numbered)}) {
if (nursery->head == nullptr) continue;
BaseNode* n = nursery->head;
while (n != nullptr) {
if (!discriminator(n)) {
n = n->next_;
continue;
}
auto node_ref = n->WeakRefIfNonZero();
if (node_ref == nullptr) {
n = n->next_;
continue;
}
BaseNode* next = n->next_;
nursery->Remove(n);
numbered->AddToHead(n);
n->uuid_ = uuid_generator_;
++uuid_generator_;
index_.emplace(n->uuid_, n);
if (n->uuid_ >= start_node) {
if (result.size() == max_results) {
node_after_end = std::move(node_ref);
return std::tuple(std::move(result), false);
}
result.emplace_back(std::move(node_ref));
}
n = next;
}
}
}
for (size_t i = 0; i < nodes.size(); ++i) {
std::string json = nodes[i]->RenderJsonString();
LOG(INFO) << json;
CHECK(node_after_end == nullptr);
return std::tuple(std::move(result), true);
}
WeakRefCountedPtr<BaseNode> ChannelzRegistry::InternalGet(intptr_t uuid) {
MutexLock index_lock(&index_mu_);
auto it = index_.find(uuid);
if (it == index_.end()) return nullptr;
BaseNode* node = it->second;
return node->WeakRefIfNonZero();
}
intptr_t ChannelzRegistry::InternalNumberNode(BaseNode* node) {
// node must be strongly owned still
node->AssertStronglyOwned();
const size_t node_shard_index = NodeShardIndex(node);
NodeShard& node_shard = node_shards_[node_shard_index];
MutexLock index_lock(&index_mu_);
MutexLock lock(&node_shard.mu);
intptr_t uuid = node->uuid_.load(std::memory_order_relaxed);
if (uuid != -1) return uuid;
uuid = uuid_generator_;
++uuid_generator_;
node->uuid_ = uuid;
if (node->orphaned_index_ > 0) {
node_shard.orphaned.Remove(node);
node_shard.orphaned_numbered.AddToHead(node);
} else {
node_shard.nursery.Remove(node);
node_shard.numbered.AddToHead(node);
}
index_.emplace(uuid, node);
return uuid;
}
bool ChannelzRegistry::NodeList::Holds(BaseNode* node) const {
BaseNode* n = head;
while (n != nullptr) {
if (n == node) return true;
n = n->next_;
}
return false;
}
void ChannelzRegistry::NodeList::AddToHead(BaseNode* node) {
DCHECK(!Holds(node));
++count;
if (head != nullptr) head->prev_ = node;
node->next_ = head;
node->prev_ = nullptr;
head = node;
if (tail == nullptr) tail = node;
DCHECK(Holds(node));
}
void ChannelzRegistry::NodeList::Remove(BaseNode* node) {
DCHECK(Holds(node));
DCHECK_GT(count, 0u);
--count;
if (node->prev_ == nullptr) {
head = node->next_;
if (head == nullptr) {
DCHECK_EQ(count, 0u);
tail = nullptr;
DCHECK(!Holds(node));
return;
}
} else {
node->prev_->next_ = node->next_;
}
if (node->next_ == nullptr) {
tail = node->prev_;
} else {
node->next_->prev_ = node->prev_;
}
DCHECK(!Holds(node));
}
void ChannelzRegistry::TestOnlyReset() {
auto* p = Default();
p->uuid_generator_ = 1;
p->LoadConfig();
std::vector<WeakRefCountedPtr<BaseNode>> free_nodes;
for (size_t i = 0; i < kNodeShards; i++) {
MutexLock lock(&p->node_shards_[i].mu);
CHECK(p->node_shards_[i].nursery.head == nullptr);
CHECK(p->node_shards_[i].numbered.head == nullptr);
while (p->node_shards_[i].orphaned.head != nullptr) {
free_nodes.emplace_back(p->node_shards_[i].orphaned.head);
p->node_shards_[i].orphaned.Remove(p->node_shards_[i].orphaned.head);
}
while (p->node_shards_[i].orphaned_numbered.head != nullptr) {
free_nodes.emplace_back(p->node_shards_[i].orphaned_numbered.head);
p->node_shards_[i].orphaned_numbered.Remove(
p->node_shards_[i].orphaned_numbered.head);
}
}
std::vector<NodeShard> replace_node_shards(kNodeShards);
replace_node_shards.swap(p->node_shards_);
MutexLock lock(&p->index_mu_);
p->index_.clear();
}
} // namespace channelz
@ -179,21 +381,22 @@ void ChannelzRegistry::InternalLogAllEntities() {
char* grpc_channelz_get_top_channels(intptr_t start_channel_id) {
grpc_core::ExecCtx exec_ctx;
return gpr_strdup(
grpc_core::channelz::ChannelzRegistry::GetTopChannels(start_channel_id)
return grpc_core::channelz::ApplyHacks(
grpc_core::channelz::ChannelzRegistry::GetTopChannelsJson(
start_channel_id)
.c_str());
}
char* grpc_channelz_get_servers(intptr_t start_server_id) {
grpc_core::ExecCtx exec_ctx;
return gpr_strdup(
grpc_core::channelz::ChannelzRegistry::GetServers(start_server_id)
return grpc_core::channelz::ApplyHacks(
grpc_core::channelz::ChannelzRegistry::GetServersJson(start_server_id)
.c_str());
}
char* grpc_channelz_get_server(intptr_t server_id) {
grpc_core::ExecCtx exec_ctx;
grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> server_node =
grpc_core::WeakRefCountedPtr<grpc_core::channelz::BaseNode> server_node =
grpc_core::channelz::ChannelzRegistry::Get(server_id);
if (server_node == nullptr ||
server_node->type() !=
@ -203,7 +406,7 @@ char* grpc_channelz_get_server(intptr_t server_id) {
grpc_core::Json json = grpc_core::Json::FromObject({
{"server", server_node->RenderJson()},
});
return gpr_strdup(grpc_core::JsonDump(json).c_str());
return grpc_core::channelz::ApplyHacks(grpc_core::JsonDump(json).c_str());
}
char* grpc_channelz_get_server_sockets(intptr_t server_id,
@ -211,7 +414,7 @@ char* grpc_channelz_get_server_sockets(intptr_t server_id,
intptr_t max_results) {
grpc_core::ExecCtx exec_ctx;
// Validate inputs before handing them of to the renderer.
grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> base_node =
grpc_core::WeakRefCountedPtr<grpc_core::channelz::BaseNode> base_node =
grpc_core::channelz::ChannelzRegistry::Get(server_id);
if (base_node == nullptr ||
base_node->type() != grpc_core::channelz::BaseNode::EntityType::kServer ||
@ -222,13 +425,13 @@ char* grpc_channelz_get_server_sockets(intptr_t server_id,
// actually a server node.
grpc_core::channelz::ServerNode* server_node =
static_cast<grpc_core::channelz::ServerNode*>(base_node.get());
return gpr_strdup(
return grpc_core::channelz::ApplyHacks(
server_node->RenderServerSockets(start_socket_id, max_results).c_str());
}
char* grpc_channelz_get_channel(intptr_t channel_id) {
grpc_core::ExecCtx exec_ctx;
grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> channel_node =
grpc_core::WeakRefCountedPtr<grpc_core::channelz::BaseNode> channel_node =
grpc_core::channelz::ChannelzRegistry::Get(channel_id);
if (channel_node == nullptr ||
(channel_node->type() !=
@ -240,12 +443,12 @@ char* grpc_channelz_get_channel(intptr_t channel_id) {
grpc_core::Json json = grpc_core::Json::FromObject({
{"channel", channel_node->RenderJson()},
});
return gpr_strdup(grpc_core::JsonDump(json).c_str());
return grpc_core::channelz::ApplyHacks(grpc_core::JsonDump(json).c_str());
}
char* grpc_channelz_get_subchannel(intptr_t subchannel_id) {
grpc_core::ExecCtx exec_ctx;
grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> subchannel_node =
grpc_core::WeakRefCountedPtr<grpc_core::channelz::BaseNode> subchannel_node =
grpc_core::channelz::ChannelzRegistry::Get(subchannel_id);
if (subchannel_node == nullptr ||
subchannel_node->type() !=
@ -255,20 +458,22 @@ char* grpc_channelz_get_subchannel(intptr_t subchannel_id) {
grpc_core::Json json = grpc_core::Json::FromObject({
{"subchannel", subchannel_node->RenderJson()},
});
return gpr_strdup(grpc_core::JsonDump(json).c_str());
return grpc_core::channelz::ApplyHacks(grpc_core::JsonDump(json).c_str());
}
char* grpc_channelz_get_socket(intptr_t socket_id) {
grpc_core::ExecCtx exec_ctx;
grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> socket_node =
grpc_core::WeakRefCountedPtr<grpc_core::channelz::BaseNode> socket_node =
grpc_core::channelz::ChannelzRegistry::Get(socket_id);
if (socket_node == nullptr ||
socket_node->type() !=
grpc_core::channelz::BaseNode::EntityType::kSocket) {
(socket_node->type() !=
grpc_core::channelz::BaseNode::EntityType::kSocket &&
socket_node->type() !=
grpc_core::channelz::BaseNode::EntityType::kListenSocket)) {
return nullptr;
}
grpc_core::Json json = grpc_core::Json::FromObject({
{"socket", socket_node->RenderJson()},
});
return gpr_strdup(grpc_core::JsonDump(json).c_str());
return grpc_core::channelz::ApplyHacks(grpc_core::JsonDump(json).c_str());
}

View File

@ -25,8 +25,10 @@
#include <map>
#include <string>
#include "absl/base/thread_annotations.h"
#include "absl/container/btree_map.h"
#include "absl/functional/function_ref.h"
#include "src/core/channelz/channelz.h"
#include "src/core/util/json/json_writer.h"
#include "src/core/util/ref_counted_ptr.h"
#include "src/core/util/sync.h"
@ -40,36 +42,134 @@ class ChannelzRegistry final {
static void Register(BaseNode* node) {
return Default()->InternalRegister(node);
}
static void Unregister(intptr_t uuid) { Default()->InternalUnregister(uuid); }
static RefCountedPtr<BaseNode> Get(intptr_t uuid) {
static void Unregister(BaseNode* node) {
Default()->InternalUnregister(node);
}
static WeakRefCountedPtr<BaseNode> Get(intptr_t uuid) {
return Default()->InternalGet(uuid);
}
static intptr_t NumberNode(BaseNode* node) {
return Default()->InternalNumberNode(node);
}
static WeakRefCountedPtr<SubchannelNode> GetSubchannel(intptr_t uuid) {
return Default()
->InternalGetTyped<SubchannelNode, BaseNode::EntityType::kSubchannel>(
uuid);
}
static WeakRefCountedPtr<ChannelNode> GetChannel(intptr_t uuid) {
auto node = Default()->InternalGet(uuid);
if (node == nullptr) return nullptr;
if (node->type() == BaseNode::EntityType::kTopLevelChannel) {
return node->WeakRefAsSubclass<ChannelNode>();
}
if (node->type() == BaseNode::EntityType::kInternalChannel) {
return node->WeakRefAsSubclass<ChannelNode>();
}
return nullptr;
}
static WeakRefCountedPtr<ServerNode> GetServer(intptr_t uuid) {
return Default()
->InternalGetTyped<ServerNode, BaseNode::EntityType::kServer>(uuid);
}
static WeakRefCountedPtr<SocketNode> GetSocket(intptr_t uuid) {
return Default()
->InternalGetTyped<SocketNode, BaseNode::EntityType::kSocket>(uuid);
}
// Returns the allocated JSON string that represents the proto
// GetTopChannelsResponse as per channelz.proto.
static std::string GetTopChannels(intptr_t start_channel_id) {
return Default()->InternalGetTopChannels(start_channel_id);
static auto GetTopChannels(intptr_t start_channel_id) {
return Default()
->InternalGetObjects<ChannelNode,
BaseNode::EntityType::kTopLevelChannel>(
start_channel_id);
}
static std::string GetTopChannelsJson(intptr_t start_channel_id);
static std::string GetServersJson(intptr_t start_server_id);
// Returns the allocated JSON string that represents the proto
// GetServersResponse as per channelz.proto.
static std::string GetServers(intptr_t start_server_id) {
return Default()->InternalGetServers(start_server_id);
static auto GetServers(intptr_t start_server_id) {
return Default()
->InternalGetObjects<ServerNode, BaseNode::EntityType::kServer>(
start_server_id);
}
static std::tuple<std::vector<WeakRefCountedPtr<BaseNode>>, bool>
GetChildrenOfType(intptr_t start_node, const BaseNode* parent,
BaseNode::EntityType type, size_t max_results) {
return Default()->InternalGetChildrenOfType(start_node, parent, type,
max_results);
}
// Test only helper function to dump the JSON representation to std out.
// This can aid in debugging channelz code.
static void LogAllEntities() { Default()->InternalLogAllEntities(); }
// Test only helper function to reset to initial state.
static void TestOnlyReset() {
auto* p = Default();
MutexLock lock(&p->mu_);
p->node_map_.clear();
p->uuid_generator_ = 0;
static std::vector<WeakRefCountedPtr<BaseNode>> GetAllEntities() {
return Default()->InternalGetAllEntities();
}
// Test only helper function to reset to initial state.
static void TestOnlyReset();
private:
ChannelzRegistry() { LoadConfig(); }
void LoadConfig();
// Takes a callable F: (WeakRefCountedPtr<BaseNode>) -> bool, and returns
// a (BaseNode*) -> bool that filters unreffed objects and returns true.
// The ref must be unreffed outside the NodeMapInterface iteration.
template <typename F>
static auto CollectReferences(F fn) {
return [fn = std::move(fn)](BaseNode* n) {
auto node = n->RefIfNonZero();
if (node == nullptr) return true;
return fn(std::move(node));
};
}
struct NodeList {
BaseNode* head = nullptr;
BaseNode* tail = nullptr;
size_t count = 0;
bool Holds(BaseNode* node) const;
void AddToHead(BaseNode* node);
void Remove(BaseNode* node);
};
// Nodes traverse through up to four lists, depending on
// whether they have a uuid (this is becoming numbered),
// and whether they have been orphaned or not.
// The lists help us find un-numbered nodes when needed for
// queries, and the oldest orphaned node when needed for
// garbage collection.
// Nodes are organized into shards based on their pointer
// address. A shard tracks the four lists of nodes
// independently - we strive to have no cross-talk between
// shards as these are very global objects.
struct alignas(GPR_CACHELINE_SIZE) NodeShard {
Mutex mu;
// Nursery nodes have no uuid and are not orphaned.
NodeList nursery ABSL_GUARDED_BY(mu);
// Numbered nodes have been assigned a uuid, and are not orphaned.
NodeList numbered ABSL_GUARDED_BY(mu);
// Orphaned nodes have no uuid, but have been orphaned.
NodeList orphaned ABSL_GUARDED_BY(mu);
// Finally, orphaned numbered nodes are orphaned, and have been assigned a
// uuid.
NodeList orphaned_numbered ABSL_GUARDED_BY(mu);
uint64_t next_orphan_index ABSL_GUARDED_BY(mu) = 1;
size_t TotalOrphaned() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu) {
return orphaned.count + orphaned_numbered.count;
}
};
// Returned the singleton instance of ChannelzRegistry;
static ChannelzRegistry* Default();
@ -78,23 +178,81 @@ class ChannelzRegistry final {
// globally unregisters the object that is associated to uuid. Also does
// sanity check that an object doesn't try to unregister the wrong type.
void InternalUnregister(intptr_t uuid);
void InternalUnregister(BaseNode* node);
intptr_t InternalNumberNode(BaseNode* node);
// if object with uuid has previously been registered as the correct type,
// returns the void* associated with that uuid. Else returns nullptr.
RefCountedPtr<BaseNode> InternalGet(intptr_t uuid);
WeakRefCountedPtr<BaseNode> InternalGet(intptr_t uuid);
std::string InternalGetTopChannels(intptr_t start_channel_id);
std::string InternalGetServers(intptr_t start_server_id);
// Generic query over nodes.
// This function takes care of all the gnarly locking, and allows high level
// code to request a start node and maximum number of results (for pagination
// purposes).
// `discriminator` allows callers to choose which nodes will be returned - if
// it returns true, the node is included in the result.
// `discriminator` *MUST NOT* ref the node, nor call into ChannelzRegistry via
// any code path (locks are held during the call).
std::tuple<std::vector<WeakRefCountedPtr<BaseNode>>, bool> QueryNodes(
intptr_t start_node,
absl::FunctionRef<bool(const BaseNode*)> discriminator,
size_t max_results);
std::tuple<std::vector<WeakRefCountedPtr<BaseNode>>, bool>
InternalGetChildrenOfType(intptr_t start_node, const BaseNode* parent,
BaseNode::EntityType type, size_t max_results) {
return QueryNodes(
start_node,
[type, parent](const BaseNode* n) {
return n->type() == type && n->HasParent(parent);
},
max_results);
}
template <typename T, BaseNode::EntityType entity_type>
WeakRefCountedPtr<T> InternalGetTyped(intptr_t uuid) {
WeakRefCountedPtr<BaseNode> node = InternalGet(uuid);
if (node == nullptr || node->type() != entity_type) {
return nullptr;
}
return node->WeakRefAsSubclass<T>();
}
template <typename T, BaseNode::EntityType entity_type>
std::tuple<std::vector<WeakRefCountedPtr<T>>, bool> InternalGetObjects(
intptr_t start_id) {
const int kPaginationLimit = 100;
std::vector<WeakRefCountedPtr<T>> top_level_channels;
const auto [nodes, end] = QueryNodes(
start_id,
[](const BaseNode* node) { return node->type() == entity_type; },
kPaginationLimit);
for (const auto& p : nodes) {
top_level_channels.emplace_back(p->template WeakRefAsSubclass<T>());
}
return std::tuple(std::move(top_level_channels), end);
}
void InternalLogAllEntities();
std::vector<WeakRefCountedPtr<BaseNode>> InternalGetAllEntities();
// protects members
Mutex mu_;
std::map<intptr_t, BaseNode*> node_map_ ABSL_GUARDED_BY(mu_);
intptr_t uuid_generator_ ABSL_GUARDED_BY(mu_) = 0;
static constexpr size_t kNodeShards = 63;
size_t NodeShardIndex(BaseNode* node) {
return absl::HashOf(node) % kNodeShards;
}
int64_t uuid_generator_{1};
std::vector<NodeShard> node_shards_{kNodeShards};
Mutex index_mu_;
absl::btree_map<intptr_t, BaseNode*> index_ ABSL_GUARDED_BY(index_mu_);
size_t max_orphaned_per_shard_;
};
// `additionalInfo` section is not yet in the protobuf format, so we
// provide a utility to strip it for compatibility.
std::string StripAdditionalInfoFromJson(absl::string_view json);
} // namespace channelz
} // namespace grpc_core

View File

@ -0,0 +1,315 @@
// Copyright 2025 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_CHANNELZ_ZTRACE_COLLECTOR_H
#define GRPC_SRC_CORE_CHANNELZ_ZTRACE_COLLECTOR_H
#include <grpc/support/time.h>
#include <memory>
#include <tuple>
#include <vector>
#include "absl/container/flat_hash_set.h"
#include "src/core/channelz/channelz.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/util/json/json_writer.h"
#include "src/core/util/single_set_ptr.h"
#include "src/core/util/string.h"
#include "src/core/util/sync.h"
#include "src/core/util/time.h"
#ifdef GRPC_NO_ZTRACE
namespace grpc_core::channelz {
namespace ztrace_collector_detail {
class ZTraceImpl final : public ZTrace {
public:
explicit ZTraceImpl() {}
void Run(Timestamp deadline, std::map<std::string, std::string> args,
std::shared_ptr<grpc_event_engine::experimental::EventEngine>
event_engine,
absl::AnyInvocable<void(Json)> callback) override {
event_engine->Run([callback = std::move(callback)]() mutable {
callback(Json::FromBool(false));
});
}
};
class StubImpl {
public:
template <typename T>
void Append(const T&) {}
std::unique_ptr<ZTrace> MakeZTrace() {
return std::make_unique<ZTraceImpl>();
}
};
} // namespace ztrace_collector_detail
template <typename...>
class ZTraceCollector : public ztrace_collector_detail::StubImpl {};
} // namespace grpc_core::channelz
#else
namespace grpc_core::channelz {
namespace ztrace_collector_detail {
template <typename T>
using Collection = std::deque<std::pair<gpr_cycle_counter, T> >;
template <typename T>
void AppendResults(const Collection<T>& data, Json::Array& results) {
for (const auto& value : data) {
Json::Object object;
object["timestamp"] =
Json::FromString(gpr_format_timespec(gpr_convert_clock_type(
gpr_cycle_counter_to_time(value.first), GPR_CLOCK_REALTIME)));
value.second.RenderJson(object);
results.emplace_back(Json::FromObject(std::move(object)));
}
}
template <typename Needle, typename... Haystack>
constexpr bool kIsElement = false;
template <typename Needle, typename... Haystack>
constexpr bool kIsElement<Needle, Needle, Haystack...> = true;
template <typename Needle, typename H, typename... Haystack>
constexpr bool kIsElement<Needle, H, Haystack...> =
kIsElement<Needle, Haystack...>;
} // namespace ztrace_collector_detail
inline std::optional<int64_t> IntFromArgs(
const std::map<std::string, std::string>& args, const std::string& name) {
auto it = args.find(name);
if (it == args.end()) return std::nullopt;
int64_t out;
if (!absl::SimpleAtoi(it->second, &out)) return std::nullopt;
return out;
}
// Generic collector infrastructure for ztrace queries.
// Abstracts away most of the ztrace requirements in an efficient manner,
// allowing system authors to concentrate on emitting useful data.
// If no trace is performed, overhead is one pointer and one relaxed atomic read
// per trace event.
//
// Two kinds of objects are required:
// 1. A `Config`
// - This type should be constructible with a std::map<std::string,
// std::string>
// and provides overall query configuration - the map can be used to pull
// predicates from the calling system.
// - Needs a `bool Finishes(T)` method for each Data type (see 2).
// This allows the config to terminate a query in the event of reaching
// some configured predicate.
// 2. N `Data` types
// - One for each kind of data captured in the trace
// - Allows avoiding e.g. variant<> data types; these are inefficient
// in this context because they force every recorded entry to use the
// same number of bytes whilst pending.
template <typename Config, typename... Data>
class ZTraceCollector {
public:
template <typename X>
void Append(X producer_or_value) {
GRPC_TRACE_LOG(ztrace, INFO) << "ZTRACE[" << this << "]: " << [&]() {
Json::Object obj;
if constexpr (ztrace_collector_detail::kIsElement<X, Data...>) {
producer_or_value.RenderJson(obj);
} else {
producer_or_value().RenderJson(obj);
}
return JsonDump(Json::FromObject(std::move(obj)));
}();
if (!impl_.is_set()) return;
if constexpr (ztrace_collector_detail::kIsElement<X, Data...>) {
AppendValue(std::move(producer_or_value));
} else {
AppendValue(producer_or_value());
}
}
std::unique_ptr<ZTrace> MakeZTrace() {
return std::make_unique<ZTraceImpl>(impl_.GetOrCreate());
}
private:
template <typename T>
using Collection = ztrace_collector_detail::Collection<T>;
struct Instance : public RefCounted<Instance> {
Instance(std::map<std::string, std::string> args,
std::shared_ptr<grpc_event_engine::experimental::EventEngine>
event_engine,
absl::AnyInvocable<void(Json)> done)
: memory_cap_(IntFromArgs(args, "memory_cap").value_or(1024 * 1024)),
config(args),
event_engine(std::move(event_engine)),
done(std::move(done)) {}
using Collections = std::tuple<Collection<Data>...>;
struct RemoveMostRecentState {
void (*enact)(Instance*) = nullptr;
gpr_cycle_counter most_recent =
std::numeric_limits<gpr_cycle_counter>::max();
};
template <typename T>
void Append(std::pair<gpr_cycle_counter, T> value) {
memory_used_ += value.second.MemoryUsage();
while (memory_used_ > memory_cap_) RemoveMostRecent();
std::get<Collection<T> >(data).push_back(std::move(value));
}
void RemoveMostRecent() {
RemoveMostRecentState state;
(UpdateRemoveMostRecentState<Data>(&state), ...);
CHECK(state.enact != nullptr);
state.enact(this);
++items_removed_;
}
template <typename T>
void UpdateRemoveMostRecentState(RemoveMostRecentState* state) {
auto& collection = std::get<Collection<T> >(data);
if (collection.empty()) return;
if (state->enact == nullptr ||
collection.front().first < state->most_recent) {
state->enact = +[](Instance* instance) {
auto& collection = std::get<Collection<T> >(instance->data);
const size_t ent_usage = collection.front().second.MemoryUsage();
CHECK_GE(instance->memory_used_, ent_usage);
instance->memory_used_ -= ent_usage;
collection.pop_front();
};
state->most_recent = collection.front().first;
}
}
void Finish(absl::Status status) {
event_engine->Run([data = std::move(data), done = std::move(done),
status = std::move(status), memory_used = memory_used_,
items_removed = items_removed_]() mutable {
Json::Array entries;
(ztrace_collector_detail::AppendResults(
std::get<Collection<Data> >(data), entries),
...);
Json::Object result;
result["entries"] = Json::FromArray(entries);
result["status"] = Json::FromString(status.ToString());
result["memory_used"] =
Json::FromNumber(static_cast<uint64_t>(memory_used));
result["items_removed"] = Json::FromNumber(items_removed);
done(Json::FromObject(std::move(result)));
});
}
size_t memory_used_ = 0;
size_t memory_cap_ = 0;
uint64_t items_removed_ = 0;
Config config;
const Timestamp start_time = Timestamp::Now();
std::shared_ptr<grpc_event_engine::experimental::EventEngine> event_engine;
grpc_event_engine::experimental::EventEngine::TaskHandle task_handle{
grpc_event_engine::experimental::EventEngine::TaskHandle::kInvalid};
Collections data;
absl::AnyInvocable<void(Json)> done;
};
struct Impl : public RefCounted<Impl> {
Mutex mu;
absl::flat_hash_set<RefCountedPtr<Instance> > instances ABSL_GUARDED_BY(mu);
};
class ZTraceImpl final : public ZTrace {
public:
explicit ZTraceImpl(RefCountedPtr<Impl> impl) : impl_(std::move(impl)) {}
void Run(Timestamp deadline, std::map<std::string, std::string> args,
std::shared_ptr<grpc_event_engine::experimental::EventEngine>
event_engine,
absl::AnyInvocable<void(Json)> callback) override {
auto instance = MakeRefCounted<Instance>(std::move(args), event_engine,
std::move(callback));
auto impl = std::move(impl_);
RefCountedPtr<Instance> oldest_instance;
MutexLock lock(&impl->mu);
if (impl->instances.size() > 20) {
// Eject oldest running trace
Timestamp oldest_time = Timestamp::InfFuture();
for (auto& instance : impl->instances) {
if (instance->start_time < oldest_time) {
oldest_time = instance->start_time;
oldest_instance = instance;
}
}
CHECK(oldest_instance != nullptr);
impl->instances.erase(oldest_instance);
oldest_instance->Finish(
absl::ResourceExhaustedError("Too many concurrent ztrace queries"));
}
instance->task_handle = event_engine->RunAfter(
deadline - Timestamp::Now(), [instance, impl]() {
bool finish;
{
MutexLock lock(&impl->mu);
finish = impl->instances.erase(instance);
}
if (finish) instance->Finish(absl::DeadlineExceededError(""));
});
impl->instances.insert(instance);
}
private:
RefCountedPtr<Impl> impl_;
};
template <typename T>
void AppendValue(T&& data) {
auto value = std::pair(gpr_get_cycle_counter(), std::forward<T>(data));
auto* impl = impl_.Get();
{
MutexLock lock(&impl->mu);
switch (impl->instances.size()) {
case 0:
return;
case 1: {
auto& instances = impl->instances;
auto& instance = *instances.begin();
const bool finishes = instance->config.Finishes(value.second);
instance->Append(std::move(value));
if (finishes) {
instance->Finish(absl::OkStatus());
instances.clear();
}
} break;
default: {
std::vector<RefCountedPtr<Instance> > finished;
for (auto& instance : impl->instances) {
const bool finishes = instance->config.Finishes(value.second);
instance->Append(value);
if (finishes) {
finished.push_back(instance);
}
}
for (const auto& instance : finished) {
instance->Finish(absl::OkStatus());
impl->instances.erase(instance);
}
}
}
}
}
SingleSetRefCountedPtr<Impl> impl_;
};
} // namespace grpc_core::channelz
#endif // GRPC_NO_ZTRACE
#endif // GRPC_SRC_CORE_CHANNELZ_ZTRACE_COLLECTOR_H

View File

@ -62,10 +62,15 @@ static grpc_core::Duration g_poll_interval =
static bool g_backup_polling_disabled;
void grpc_client_channel_global_init_backup_polling() {
#ifndef GRPC_DO_NOT_INSTANTIATE_POSIX_POLLER
// Disable backup polling if EventEngine is used everywhere.
g_backup_polling_disabled = grpc_core::IsEventEngineClientEnabled() &&
grpc_core::IsEventEngineListenerEnabled() &&
grpc_core::IsEventEngineDnsEnabled();
#else
// EventEngine polling not supported, keep using the backup poller.
g_backup_polling_disabled = false;
#endif
if (g_backup_polling_disabled) {
return;
}
@ -155,11 +160,21 @@ static void g_poller_init_locked() {
}
}
static bool g_can_poll_in_background() {
#ifndef GRPC_DO_NOT_INSTANTIATE_POSIX_POLLER
return grpc_iomgr_run_in_background();
#else
// No iomgr "event_engines" (not to be confused with the new EventEngine)
// are able to run in backgroung.
return false;
#endif
}
void grpc_client_channel_start_backup_polling(
grpc_pollset_set* interested_parties) {
if (g_backup_polling_disabled ||
g_poll_interval == grpc_core::Duration::Zero() ||
grpc_iomgr_run_in_background()) {
g_can_poll_in_background()) {
return;
}
gpr_mu_lock(&g_poller_mu);
@ -179,7 +194,7 @@ void grpc_client_channel_stop_backup_polling(
grpc_pollset_set* interested_parties) {
if (g_backup_polling_disabled ||
g_poll_interval == grpc_core::Duration::Zero() ||
grpc_iomgr_run_in_background()) {
g_can_poll_in_background()) {
return;
}
grpc_pollset_set_del_pollset(interested_parties, g_poller->pollset);

View File

@ -45,6 +45,10 @@
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h"
#include "src/core/call/call_spine.h"
#include "src/core/call/client_call.h"
#include "src/core/call/metadata_batch.h"
#include "src/core/call/status_util.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"
@ -59,7 +63,6 @@
#include "src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h"
#include "src/core/lib/address_utils/sockaddr_utils.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/status_util.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/event_engine/channel_args_endpoint_config.h"
#include "src/core/lib/iomgr/resolved_address.h"
@ -75,11 +78,8 @@
#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/metadata_batch.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"
@ -228,21 +228,19 @@ class ClientChannel::SubchannelWrapper::WatcherWrapper
subchannel_wrapper_.reset(DEBUG_LOCATION, "WatcherWrapper");
}
void OnConnectivityStateChange(
RefCountedPtr<ConnectivityStateWatcherInterface> self,
grpc_connectivity_state state, const absl::Status& status) override {
void OnConnectivityStateChange(grpc_connectivity_state state,
const absl::Status& status) override {
GRPC_TRACE_LOG(client_channel, INFO)
<< "client_channel=" << subchannel_wrapper_->client_channel_.get()
<< ": connectivity change for subchannel wrapper "
<< subchannel_wrapper_.get() << " subchannel "
<< subchannel_wrapper_->subchannel_.get()
<< "; hopping into work_serializer";
self.release(); // Held by callback.
auto self = RefAsSubclass<WatcherWrapper>();
subchannel_wrapper_->client_channel_->work_serializer_->Run(
[this, state, status]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(
*subchannel_wrapper_->client_channel_->work_serializer_) {
ApplyUpdateInControlPlaneWorkSerializer(state, status);
Unref();
[self, state, status]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(
*self->subchannel_wrapper_->client_channel_->work_serializer_) {
self->ApplyUpdateInControlPlaneWorkSerializer(state, status);
});
}
@ -324,8 +322,7 @@ ClientChannel::SubchannelWrapper::SubchannelWrapper(
auto it =
client_channel_->subchannel_refcount_map_.find(subchannel_.get());
if (it == client_channel_->subchannel_refcount_map_.end()) {
client_channel_->channelz_node_->AddChildSubchannel(
subchannel_node->uuid());
subchannel_node->AddParent(client_channel_->channelz_node_);
it = client_channel_->subchannel_refcount_map_
.emplace(subchannel_.get(), 0)
.first;
@ -360,8 +357,8 @@ void ClientChannel::SubchannelWrapper::Orphaned() {
CHECK(it != self->client_channel_->subchannel_refcount_map_.end());
--it->second;
if (it->second == 0) {
self->client_channel_->channelz_node_->RemoveChildSubchannel(
subchannel_node->uuid());
subchannel_node->RemoveParent(
self->client_channel_->channelz_node_);
self->client_channel_->subchannel_refcount_map_.erase(it);
}
}
@ -495,7 +492,7 @@ class ClientChannel::ClientChannelControlHelper
}
GlobalStatsPluginRegistry::StatsPluginGroup& GetStatsPluginGroup() override {
return client_channel_->stats_plugin_group_;
return *client_channel_->stats_plugin_group_;
}
void AddTraceEvent(TraceSeverity severity, absl::string_view message) override
@ -530,7 +527,11 @@ RefCountedPtr<SubchannelPoolInterface> GetSubchannelPool(
if (args.GetBool(GRPC_ARG_USE_LOCAL_SUBCHANNEL_POOL).value_or(false)) {
return MakeRefCounted<LocalSubchannelPool>();
}
return GlobalSubchannelPool::instance();
if (IsShardGlobalConnectionPoolEnabled()) {
return GlobalSubchannelPool::instance();
} else {
return LegacyGlobalSubchannelPool::instance();
}
}
} // namespace
@ -587,6 +588,7 @@ absl::StatusOr<RefCountedPtr<Channel>> ClientChannel::Create(
}
namespace {
std::string GetDefaultAuthorityFromChannelArgs(const ChannelArgs& channel_args,
absl::string_view target) {
std::optional<std::string> default_authority =
@ -598,6 +600,18 @@ std::string GetDefaultAuthorityFromChannelArgs(const ChannelArgs& channel_args,
return std::move(*default_authority);
}
}
std::shared_ptr<GlobalStatsPluginRegistry::StatsPluginGroup>
GetStatsPluginGroupFromChannelArgs(const ChannelArgs& channel_args,
absl::string_view target,
absl::string_view default_authority) {
grpc_event_engine::experimental::ChannelArgsEndpointConfig endpoint_config(
channel_args);
experimental::StatsPluginChannelScope scope(target, default_authority,
endpoint_config);
return GlobalStatsPluginRegistry::GetStatsPluginsForChannel(scope);
}
} // namespace
ClientChannel::ClientChannel(
@ -606,15 +620,17 @@ ClientChannel::ClientChannel(
ClientChannelFactory* client_channel_factory,
CallDestinationFactory* call_destination_factory)
: Channel(std::move(target), channel_args),
channel_args_(std::move(channel_args)),
default_authority_(
GetDefaultAuthorityFromChannelArgs(channel_args, this->target())),
stats_plugin_group_(GetStatsPluginGroupFromChannelArgs(
channel_args, this->target(), default_authority_)),
channel_args_(channel_args.SetObject(stats_plugin_group_)),
event_engine_(channel_args_.GetObjectRef<EventEngine>()),
uri_to_resolve_(std::move(uri_to_resolve)),
service_config_parser_index_(
internal::ClientChannelServiceConfigParser::ParserIndex()),
default_service_config_(std::move(default_service_config)),
client_channel_factory_(client_channel_factory),
default_authority_(
GetDefaultAuthorityFromChannelArgs(channel_args_, this->target())),
channelz_node_(channel_args_.GetObject<channelz::ChannelNode>()),
idle_timeout_(GetClientIdleTimeout(channel_args_)),
resolver_data_for_calls_(ResolverDataForCalls{}),
@ -634,13 +650,6 @@ ClientChannel::ClientChannel(
} else {
keepalive_time_ = -1; // unset
}
// Get stats plugins for channel.
grpc_event_engine::experimental::ChannelArgsEndpointConfig endpoint_config(
channel_args_);
experimental::StatsPluginChannelScope scope(
this->target(), default_authority_, endpoint_config);
stats_plugin_group_ =
GlobalStatsPluginRegistry::GetStatsPluginsForChannel(scope);
}
ClientChannel::~ClientChannel() {
@ -693,6 +702,7 @@ class ExternalStateWatcher : public RefCounted<ExternalStateWatcher> {
grpc_connectivity_state last_observed_state,
Timestamp deadline)
: channel_(std::move(channel)), cq_(cq), tag_(tag) {
grpc_cq_begin_op(cq, tag);
MutexLock lock(&mu_);
// Start watch. This inherits the ref from creation.
auto watcher =
@ -772,17 +782,14 @@ void ClientChannel::WatchConnectivityState(grpc_connectivity_state state,
}
void ClientChannel::AddConnectivityWatcher(
grpc_connectivity_state,
OrphanablePtr<AsyncConnectivityStateWatcherInterface>) {
Crash("not implemented");
// TODO(ctiller): to make this work, need to change WorkSerializer to use
// absl::AnyInvocable<> instead of std::function<>
// work_serializer_->Run(
// [self = RefAsSubclass<ClientChannel>(), initial_state,
// watcher = std::move(watcher)]()
// ABSL_EXCLUSIVE_LOCKS_REQUIRED(*work_serializer_) {
// self->state_tracker_.AddWatcher(initial_state, std::move(watcher));
// });
grpc_connectivity_state initial_state,
OrphanablePtr<AsyncConnectivityStateWatcherInterface> watcher) {
auto self = RefAsSubclass<ClientChannel>();
work_serializer_->Run(
[self, initial_state, watcher = std::move(watcher)]()
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*self->work_serializer_) mutable {
self->state_tracker_.AddWatcher(initial_state, std::move(watcher));
});
}
void ClientChannel::RemoveConnectivityWatcher(
@ -1312,11 +1319,13 @@ void ClientChannel::UpdateStateLocked(grpc_connectivity_state state,
state_tracker_.SetState(state, status, reason);
if (channelz_node_ != nullptr) {
channelz_node_->SetConnectivityState(state);
channelz_node_->AddTraceEvent(
channelz::ChannelTrace::Severity::Info,
grpc_slice_from_static_string(
channelz::ChannelNode::GetChannelConnectivityStateChangeString(
state)));
std::string trace =
channelz::ChannelNode::GetChannelConnectivityStateChangeString(state);
if (!status.ok() || state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
absl::StrAppend(&trace, " status:", status.ToString());
}
channelz_node_->AddTraceEvent(channelz::ChannelTrace::Severity::Info,
grpc_slice_from_cpp_string(std::move(trace)));
}
}

View File

@ -22,6 +22,7 @@
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "src/core/call/metadata.h"
#include "src/core/client_channel/client_channel_factory.h"
#include "src/core/client_channel/config_selector.h"
#include "src/core/client_channel/subchannel.h"
@ -29,7 +30,6 @@
#include "src/core/filter/blackboard.h"
#include "src/core/lib/promise/observable.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/load_balancing/lb_policy.h"
#include "src/core/resolver/resolver.h"
#include "src/core/service_config/service_config.h"
@ -170,6 +170,9 @@ class ClientChannel : public Channel {
ConfigSelector& config_selector,
ClientMetadata& client_initial_metadata) const;
const std::string default_authority_;
const std::shared_ptr<GlobalStatsPluginRegistry::StatsPluginGroup>
stats_plugin_group_;
const ChannelArgs channel_args_;
const std::shared_ptr<grpc_event_engine::experimental::EventEngine>
event_engine_;
@ -177,9 +180,7 @@ class ClientChannel : public Channel {
const size_t service_config_parser_index_;
const RefCountedPtr<ServiceConfig> default_service_config_;
ClientChannelFactory* const client_channel_factory_;
const std::string default_authority_;
channelz::ChannelNode* const channelz_node_;
GlobalStatsPluginRegistry::StatsPluginGroup stats_plugin_group_;
//
// Idleness state.

View File

@ -47,6 +47,8 @@
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h"
#include "src/core/call/metadata_batch.h"
#include "src/core/call/status_util.h"
#include "src/core/channelz/channel_trace.h"
#include "src/core/client_channel/backup_poller.h"
#include "src/core/client_channel/client_channel_internal.h"
@ -65,7 +67,6 @@
#include "src/core/lib/address_utils/sockaddr_utils.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/channel/status_util.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/experiments/experiments.h"
#include "src/core/lib/iomgr/exec_ctx.h"
@ -85,7 +86,6 @@
#include "src/core/lib/surface/call.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_registry.h"
@ -268,7 +268,6 @@ class ClientChannelFilter::FilterBasedCallData final
static void RecvTrailingMetadataReadyForConfigSelectorCommitCallback(
void* arg, grpc_error_handle error);
grpc_slice path_; // Request path.
gpr_cycle_counter call_start_time_;
Timestamp deadline_;
@ -398,7 +397,6 @@ class DynamicTerminationFilter::CallData final {
auto* chand = static_cast<DynamicTerminationFilter*>(elem->channel_data);
ClientChannelFilter* client_channel = chand->chand_;
grpc_call_element_args args = {calld->owning_call_, nullptr,
calld->path_,
/*start_time=*/0, calld->deadline_,
calld->arena_, calld->call_combiner_};
auto* service_config_call_data = GetServiceConfigCallData(calld->arena_);
@ -413,15 +411,11 @@ class DynamicTerminationFilter::CallData final {
private:
explicit CallData(const grpc_call_element_args& args)
: path_(CSliceRef(args.path)),
deadline_(args.deadline),
: deadline_(args.deadline),
arena_(args.arena),
owning_call_(args.call_stack),
call_combiner_(args.call_combiner) {}
~CallData() { CSliceUnref(path_); }
grpc_slice path_; // Request path.
Timestamp deadline_;
Arena* arena_;
grpc_call_stack* owning_call_;
@ -507,7 +501,7 @@ class ClientChannelFilter::SubchannelWrapper final
if (subchannel_node != nullptr) {
auto it = chand_->subchannel_refcount_map_.find(subchannel_.get());
if (it == chand_->subchannel_refcount_map_.end()) {
chand_->channelz_node_->AddChildSubchannel(subchannel_node->uuid());
subchannel_node->AddParent(chand_->channelz_node_);
it = chand_->subchannel_refcount_map_.emplace(subchannel_.get(), 0)
.first;
}
@ -539,8 +533,7 @@ class ClientChannelFilter::SubchannelWrapper final
CHECK(it != chand_->subchannel_refcount_map_.end());
--it->second;
if (it->second == 0) {
chand_->channelz_node_->RemoveChildSubchannel(
subchannel_node->uuid());
subchannel_node->RemoveParent(chand_->channelz_node_);
chand_->subchannel_refcount_map_.erase(it);
}
}
@ -623,20 +616,18 @@ class ClientChannelFilter::SubchannelWrapper final
parent_.reset(DEBUG_LOCATION, "WatcherWrapper");
}
void OnConnectivityStateChange(
RefCountedPtr<ConnectivityStateWatcherInterface> self,
grpc_connectivity_state state, const absl::Status& status) override {
void OnConnectivityStateChange(grpc_connectivity_state state,
const absl::Status& status) override {
GRPC_TRACE_LOG(client_channel, INFO)
<< "chand=" << parent_->chand_
<< ": connectivity change for subchannel wrapper " << parent_.get()
<< " subchannel " << parent_->subchannel_.get()
<< "hopping into work_serializer";
self.release(); // Held by callback.
auto self = RefAsSubclass<WatcherWrapper>();
parent_->chand_->work_serializer_->Run(
[this, state, status]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(
*parent_->chand_->work_serializer_) {
ApplyUpdateInControlPlaneWorkSerializer(state, status);
Unref();
[self, state, status]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(
*self->parent_->chand_->work_serializer_) {
self->ApplyUpdateInControlPlaneWorkSerializer(state, status);
});
}
@ -986,7 +977,7 @@ class ClientChannelFilter::ClientChannelControlHelper final
}
GlobalStatsPluginRegistry::StatsPluginGroup& GetStatsPluginGroup() override {
return *chand_->owning_stack_->stats_plugin_group;
return **chand_->owning_stack_->stats_plugin_group;
}
void AddTraceEvent(TraceSeverity severity, absl::string_view message) override
@ -1035,7 +1026,11 @@ RefCountedPtr<SubchannelPoolInterface> GetSubchannelPool(
if (args.GetBool(GRPC_ARG_USE_LOCAL_SUBCHANNEL_POOL).value_or(false)) {
return MakeRefCounted<LocalSubchannelPool>();
}
return GlobalSubchannelPool::instance();
if (IsShardGlobalConnectionPoolEnabled()) {
return GlobalSubchannelPool::instance();
} else {
return LegacyGlobalSubchannelPool::instance();
}
}
} // namespace
@ -1557,11 +1552,13 @@ void ClientChannelFilter::UpdateStateLocked(grpc_connectivity_state state,
state_tracker_.SetState(state, status, reason);
if (channelz_node_ != nullptr) {
channelz_node_->SetConnectivityState(state);
channelz_node_->AddTraceEvent(
channelz::ChannelTrace::Severity::Info,
grpc_slice_from_static_string(
channelz::ChannelNode::GetChannelConnectivityStateChangeString(
state)));
std::string trace =
channelz::ChannelNode::GetChannelConnectivityStateChangeString(state);
if (!status.ok() || state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
absl::StrAppend(&trace, " status:", status.ToString());
}
channelz_node_->AddTraceEvent(channelz::ChannelTrace::Severity::Info,
grpc_slice_from_cpp_string(std::move(trace)));
}
}
@ -1928,8 +1925,7 @@ bool ClientChannelFilter::CallData::CheckResolutionLocked(
ClientChannelFilter::FilterBasedCallData::FilterBasedCallData(
grpc_call_element* elem, const grpc_call_element_args& args)
: path_(CSliceRef(args.path)),
call_start_time_(args.start_time),
: call_start_time_(args.start_time),
deadline_(args.deadline),
arena_(args.arena),
elem_(elem),
@ -1940,7 +1936,6 @@ ClientChannelFilter::FilterBasedCallData::FilterBasedCallData(
}
ClientChannelFilter::FilterBasedCallData::~FilterBasedCallData() {
CSliceUnref(path_);
// Make sure there are no remaining pending batches.
for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
CHECK_EQ(pending_batches_[i], nullptr);
@ -2252,9 +2247,9 @@ void ClientChannelFilter::FilterBasedCallData::RetryCheckResolutionLocked() {
}
void ClientChannelFilter::FilterBasedCallData::CreateDynamicCall() {
DynamicFilters::Call::Args args = {dynamic_filters(), pollent_, path_,
call_start_time_, deadline_, arena(),
call_combiner()};
DynamicFilters::Call::Args args = {dynamic_filters(), pollent_,
call_start_time_, deadline_,
arena(), call_combiner()};
grpc_error_handle error;
DynamicFilters* channel_stack = args.channel_stack.get();
GRPC_TRACE_LOG(client_channel_call, INFO)
@ -2436,9 +2431,7 @@ void ClientChannelFilter::LoadBalancedCall::RecordCallCompletion(
void ClientChannelFilter::LoadBalancedCall::RecordLatency() {
// Compute latency and report it to the tracer.
if (call_attempt_tracer() != nullptr) {
gpr_timespec latency =
gpr_cycle_counter_sub(gpr_get_cycle_counter(), lb_call_start_time_);
call_attempt_tracer()->RecordEnd(latency);
call_attempt_tracer()->RecordEnd();
}
}
@ -3042,10 +3035,8 @@ void ClientChannelFilter::FilterBasedLoadBalancedCall::RetryPickLocked() {
}
void ClientChannelFilter::FilterBasedLoadBalancedCall::CreateSubchannelCall() {
Slice* path = send_initial_metadata()->get_pointer(HttpPathMetadata());
CHECK_NE(path, nullptr);
SubchannelCall::Args call_args = {
connected_subchannel()->Ref(), pollent_, path->Ref(), /*start_time=*/0,
connected_subchannel()->Ref(), pollent_, /*start_time=*/0,
arena()->GetContext<Call>()->deadline(),
// TODO(roth): When we implement hedging support, we will probably
// need to use a separate call arena for each subchannel call.

View File

@ -34,6 +34,7 @@
#include "absl/functional/any_invocable.h"
#include "absl/status/status.h"
#include "absl/strings/string_view.h"
#include "src/core/call/metadata_batch.h"
#include "src/core/channelz/channelz.h"
#include "src/core/client_channel/client_channel_args.h"
#include "src/core/client_channel/client_channel_factory.h"
@ -53,7 +54,6 @@
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/slice/slice.h"
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/transport.h"
#include "src/core/load_balancing/backend_metric_data.h"
#include "src/core/load_balancing/lb_policy.h"
@ -438,8 +438,6 @@ class ClientChannelFilter::LoadBalancedCall
absl::AnyInvocable<void()> on_commit_;
gpr_cycle_counter lb_call_start_time_ = gpr_get_cycle_counter();
RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
const BackendMetricData* backend_metric_data_ = nullptr;
std::unique_ptr<LoadBalancingPolicy::SubchannelCallTrackerInterface>

View File

@ -23,8 +23,8 @@
#include "absl/functional/any_invocable.h"
#include "absl/log/check.h"
#include "src/core/call/call_destination.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/transport/call_destination.h"
#include "src/core/load_balancing/lb_policy.h"
#include "src/core/service_config/service_config_call_data.h"
#include "src/core/telemetry/call_tracer.h"

View File

@ -27,12 +27,12 @@
#include "absl/log/check.h"
#include "absl/status/status.h"
#include "absl/strings/string_view.h"
#include "src/core/call/interception_chain.h"
#include "src/core/call/metadata_batch.h"
#include "src/core/client_channel/client_channel_internal.h"
#include "src/core/lib/channel/channel_fwd.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/slice/slice.h"
#include "src/core/lib/transport/interception_chain.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/service_config/service_config.h"
#include "src/core/util/ref_counted.h"
#include "src/core/util/ref_counted_ptr.h"

View File

@ -53,8 +53,6 @@ class SubchannelConnector : public InternallyRefCounted<SubchannelConnector> {
Transport* transport = nullptr;
// Channel args to be passed to filters.
ChannelArgs channel_args;
// Channelz socket node of the connected transport, if any.
RefCountedPtr<channelz::SocketNode> socket_node;
void Reset() {
if (transport != nullptr) {
@ -62,7 +60,6 @@ class SubchannelConnector : public InternallyRefCounted<SubchannelConnector> {
transport = nullptr;
}
channel_args = ChannelArgs();
socket_node.reset();
}
};

View File

@ -14,11 +14,11 @@
#include "src/core/client_channel/direct_channel.h"
#include "src/core/call/client_call.h"
#include "src/core/call/interception_chain.h"
#include "src/core/config/core_configuration.h"
#include "src/core/lib/event_engine/event_engine_context.h"
#include "src/core/lib/surface/channel_stack_type.h"
#include "src/core/lib/surface/client_call.h"
#include "src/core/lib/transport/interception_chain.h"
#include "src/core/util/orphanable.h"
namespace grpc_core {

View File

@ -55,7 +55,6 @@ DynamicFilters::Call::Call(Args args, grpc_error_handle* error)
const grpc_call_element_args call_args = {
call_stack, // call_stack
nullptr, // server_transport_data
args.path, // path
args.start_time, // start_time
args.deadline, // deadline
args.arena, // arena

View File

@ -49,7 +49,6 @@ class DynamicFilters final : public RefCounted<DynamicFilters> {
struct Args {
RefCountedPtr<DynamicFilters> channel_stack;
grpc_polling_entity* pollent;
grpc_slice path;
gpr_cycle_counter start_time;
Timestamp deadline;
Arena* arena;

View File

@ -26,12 +26,13 @@
namespace grpc_core {
RefCountedPtr<GlobalSubchannelPool> GlobalSubchannelPool::instance() {
static GlobalSubchannelPool* p = new GlobalSubchannelPool();
return p->RefAsSubclass<GlobalSubchannelPool>();
RefCountedPtr<LegacyGlobalSubchannelPool>
LegacyGlobalSubchannelPool::instance() {
static LegacyGlobalSubchannelPool* p = new LegacyGlobalSubchannelPool();
return p->RefAsSubclass<LegacyGlobalSubchannelPool>();
}
RefCountedPtr<Subchannel> GlobalSubchannelPool::RegisterSubchannel(
RefCountedPtr<Subchannel> LegacyGlobalSubchannelPool::RegisterSubchannel(
const SubchannelKey& key, RefCountedPtr<Subchannel> constructed) {
MutexLock lock(&mu_);
auto it = subchannel_map_.find(key);
@ -43,8 +44,8 @@ RefCountedPtr<Subchannel> GlobalSubchannelPool::RegisterSubchannel(
return constructed;
}
void GlobalSubchannelPool::UnregisterSubchannel(const SubchannelKey& key,
Subchannel* subchannel) {
void LegacyGlobalSubchannelPool::UnregisterSubchannel(const SubchannelKey& key,
Subchannel* subchannel) {
MutexLock lock(&mu_);
auto it = subchannel_map_.find(key);
// delete only if key hasn't been re-registered to a different subchannel
@ -54,7 +55,7 @@ void GlobalSubchannelPool::UnregisterSubchannel(const SubchannelKey& key,
}
}
RefCountedPtr<Subchannel> GlobalSubchannelPool::FindSubchannel(
RefCountedPtr<Subchannel> LegacyGlobalSubchannelPool::FindSubchannel(
const SubchannelKey& key) {
MutexLock lock(&mu_);
auto it = subchannel_map_.find(key);
@ -62,4 +63,64 @@ RefCountedPtr<Subchannel> GlobalSubchannelPool::FindSubchannel(
return it->second->RefIfNonZero();
}
RefCountedPtr<GlobalSubchannelPool> GlobalSubchannelPool::instance() {
static GlobalSubchannelPool* p = new GlobalSubchannelPool();
return p->RefAsSubclass<GlobalSubchannelPool>();
}
RefCountedPtr<Subchannel> GlobalSubchannelPool::RegisterSubchannel(
const SubchannelKey& key, RefCountedPtr<Subchannel> constructed) {
auto shard_index = ShardIndex(key);
auto& write_shard = write_shards_[shard_index];
auto& read_shard = read_shards_[shard_index];
SubchannelMap old_map1;
SubchannelMap old_map2;
MutexLock lock(&write_shard.mu);
auto* existing = write_shard.map.Lookup(key);
if (existing != nullptr) return (*existing)->RefIfNonZero();
old_map1 = std::exchange(write_shard.map,
write_shard.map.Add(key, constructed->WeakRef()));
MutexLock lock_read(&read_shard.mu);
old_map2 = std::exchange(read_shard.map, write_shard.map);
return constructed;
}
void GlobalSubchannelPool::UnregisterSubchannel(const SubchannelKey& key,
Subchannel* subchannel) {
auto shard_index = ShardIndex(key);
auto& write_shard = write_shards_[shard_index];
auto& read_shard = read_shards_[shard_index];
SubchannelMap old_map1;
SubchannelMap old_map2;
MutexLock lock(&write_shard.mu);
auto* existing = write_shard.map.Lookup(key);
// delete only if key hasn't been re-registered to a different subchannel
// between strong-unreffing and unregistration of subchannel.
if (existing == nullptr || existing->get() != subchannel) return;
old_map1 = std::exchange(write_shard.map, write_shard.map.Remove(key));
MutexLock lock_read(&read_shard.mu);
old_map2 = std::exchange(read_shard.map, write_shard.map);
}
RefCountedPtr<Subchannel> GlobalSubchannelPool::FindSubchannel(
const SubchannelKey& key) {
auto shard_index = ShardIndex(key);
auto& read_shard = read_shards_[shard_index];
read_shard.mu.Lock();
auto map = read_shard.map;
read_shard.mu.Unlock();
auto* subchannel = map.Lookup(key);
if (subchannel == nullptr) return nullptr;
return (*subchannel)->RefIfNonZero();
}
size_t GlobalSubchannelPool::ShardIndex(const SubchannelKey& key) {
absl::string_view addr(key.address().addr, key.address().len);
return absl::HashOf(addr) % kShards;
}
GlobalSubchannelPool::GlobalSubchannelPool() = default;
GlobalSubchannelPool::~GlobalSubchannelPool() = default;
} // namespace grpc_core

View File

@ -32,10 +32,10 @@ namespace grpc_core {
// The global subchannel pool. It shares subchannels among channels. There
// should be only one instance of this class.
class GlobalSubchannelPool final : public SubchannelPoolInterface {
class LegacyGlobalSubchannelPool final : public SubchannelPoolInterface {
public:
// Gets the singleton instance.
static RefCountedPtr<GlobalSubchannelPool> instance();
static RefCountedPtr<LegacyGlobalSubchannelPool> instance();
// Implements interface methods.
RefCountedPtr<Subchannel> RegisterSubchannel(
@ -48,8 +48,8 @@ class GlobalSubchannelPool final : public SubchannelPoolInterface {
ABSL_LOCKS_EXCLUDED(mu_);
private:
GlobalSubchannelPool() {}
~GlobalSubchannelPool() override {}
LegacyGlobalSubchannelPool() {}
~LegacyGlobalSubchannelPool() override {}
// A map from subchannel key to subchannel.
std::map<SubchannelKey, Subchannel*> subchannel_map_ ABSL_GUARDED_BY(mu_);
@ -57,6 +57,39 @@ class GlobalSubchannelPool final : public SubchannelPoolInterface {
Mutex mu_;
};
// The global subchannel pool. It shares subchannels among channels. There
// should be only one instance of this class.
class GlobalSubchannelPool final : public SubchannelPoolInterface {
public:
// Gets the singleton instance.
static RefCountedPtr<GlobalSubchannelPool> instance();
// Implements interface methods.
RefCountedPtr<Subchannel> RegisterSubchannel(
const SubchannelKey& key, RefCountedPtr<Subchannel> constructed) override;
void UnregisterSubchannel(const SubchannelKey& key,
Subchannel* subchannel) override;
RefCountedPtr<Subchannel> FindSubchannel(const SubchannelKey& key) override;
private:
GlobalSubchannelPool();
~GlobalSubchannelPool() override;
static const size_t kShards = 127;
using SubchannelMap = AVL<SubchannelKey, WeakRefCountedPtr<Subchannel>>;
struct LockedMap {
Mutex mu;
SubchannelMap map ABSL_GUARDED_BY(mu);
};
using ShardedMap = std::array<LockedMap, kShards>;
static size_t ShardIndex(const SubchannelKey& key);
ShardedMap write_shards_;
ShardedMap read_shards_;
};
} // namespace grpc_core
#endif // GRPC_SRC_CORE_CLIENT_CHANNEL_GLOBAL_SUBCHANNEL_POOL_H

View File

@ -22,7 +22,7 @@
#include <vector>
#include "absl/strings/string_view.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/call/metadata_batch.h"
#include "src/core/load_balancing/lb_policy.h"
namespace grpc_core {

View File

@ -15,12 +15,12 @@
#include "src/core/client_channel/load_balanced_call_destination.h"
#include "absl/log/log.h"
#include "src/core/call/status_util.h"
#include "src/core/client_channel/client_channel.h"
#include "src/core/client_channel/client_channel_internal.h"
#include "src/core/client_channel/lb_metadata.h"
#include "src/core/client_channel/subchannel.h"
#include "src/core/config/core_configuration.h"
#include "src/core/lib/channel/status_util.h"
#include "src/core/lib/promise/loop.h"
#include "src/core/telemetry/call_tracer.h"

View File

@ -16,9 +16,9 @@
#define GRPC_SRC_CORE_CLIENT_CHANNEL_LOAD_BALANCED_CALL_DESTINATION_H
#include "absl/functional/any_invocable.h"
#include "src/core/call/call_destination.h"
#include "src/core/client_channel/client_channel.h"
#include "src/core/lib/promise/context.h"
#include "src/core/lib/transport/call_destination.h"
#include "src/core/load_balancing/lb_policy.h"
namespace grpc_core {

View File

@ -24,11 +24,12 @@
#include "absl/log/log.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "src/core/call/metadata_batch.h"
#include "src/core/call/status_util.h"
#include "src/core/client_channel/client_channel_internal.h"
#include "src/core/client_channel/retry_service_config.h"
#include "src/core/client_channel/retry_throttle.h"
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/channel/status_util.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/iomgr/call_combiner.h"
#include "src/core/lib/iomgr/closure.h"
@ -39,7 +40,6 @@
#include "src/core/lib/slice/slice.h"
#include "src/core/lib/slice/slice_buffer.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/util/backoff.h"
#include "src/core/util/construct_destruct.h"
@ -53,6 +53,8 @@
namespace grpc_core {
using TaskHandle = grpc_event_engine::experimental::EventEngine::TaskHandle;
//
// RetryFilter::LegacyCallData::CallStackDestructionBarrier
//
@ -220,7 +222,7 @@ void RetryFilter::LegacyCallData::CallAttempt::MaybeSwitchToFastPath() {
// If we've already switched to fast path, there's nothing to do here.
if (calld_->committed_call_ != nullptr) return;
// If the perAttemptRecvTimeout timer is pending, we can't switch yet.
if (per_attempt_recv_timer_handle_.has_value()) return;
if (per_attempt_recv_timer_handle_ != TaskHandle::kInvalid) return;
// If there are still send ops to replay, we can't switch yet.
if (HaveSendOpsToReplay()) return;
// If we started an internal batch for recv_trailing_metadata but have not
@ -643,31 +645,33 @@ void RetryFilter::LegacyCallData::CallAttempt::OnPerAttemptRecvTimerLocked(
<< "chand=" << calld->chand_ << " calld=" << calld
<< " attempt=" << call_attempt
<< ": perAttemptRecvTimeout timer fired: error=" << StatusToString(error)
<< ", per_attempt_recv_timer_handle_.has_value()="
<< call_attempt->per_attempt_recv_timer_handle_.has_value();
<< ", per_attempt_recv_timer_handle_ is valid ="
<< (call_attempt->per_attempt_recv_timer_handle_ != TaskHandle::kInvalid);
CallCombinerClosureList closures;
call_attempt->per_attempt_recv_timer_handle_.reset();
// Cancel this attempt.
// TODO(roth): When implementing hedging, we should not cancel the
// current attempt.
call_attempt->MaybeAddBatchForCancelOp(
grpc_error_set_int(
GRPC_ERROR_CREATE("retry perAttemptRecvTimeout exceeded"),
StatusIntProperty::kRpcStatus, GRPC_STATUS_CANCELLED),
&closures);
// Check whether we should retry.
if (call_attempt->ShouldRetry(/*status=*/std::nullopt,
/*server_pushback_ms=*/std::nullopt)) {
// Mark current attempt as abandoned.
call_attempt->Abandon();
// We are retrying. Start backoff timer.
calld->StartRetryTimer(/*server_pushback=*/std::nullopt);
} else {
// Not retrying, so commit the call.
calld->RetryCommit(call_attempt);
// If retry state is no longer needed, switch to fast path for
// subsequent batches.
call_attempt->MaybeSwitchToFastPath();
if (call_attempt->per_attempt_recv_timer_handle_ != TaskHandle::kInvalid) {
call_attempt->per_attempt_recv_timer_handle_ = TaskHandle::kInvalid;
// Cancel this attempt.
// TODO(roth): When implementing hedging, we should not cancel the
// current attempt.
call_attempt->MaybeAddBatchForCancelOp(
grpc_error_set_int(
GRPC_ERROR_CREATE("retry perAttemptRecvTimeout exceeded"),
StatusIntProperty::kRpcStatus, GRPC_STATUS_CANCELLED),
&closures);
// Check whether we should retry.
if (call_attempt->ShouldRetry(/*status=*/std::nullopt,
/*server_pushback_ms=*/std::nullopt)) {
// Mark current attempt as abandoned.
call_attempt->Abandon();
// We are retrying. Start backoff timer.
calld->StartRetryTimer(/*server_pushback=*/std::nullopt);
} else {
// Not retrying, so commit the call.
calld->RetryCommit(call_attempt);
// If retry state is no longer needed, switch to fast path for
// subsequent batches.
call_attempt->MaybeSwitchToFastPath();
}
}
closures.RunClosures(calld->call_combiner_);
call_attempt->Unref(DEBUG_LOCATION, "OnPerAttemptRecvTimer");
@ -676,16 +680,16 @@ void RetryFilter::LegacyCallData::CallAttempt::OnPerAttemptRecvTimerLocked(
void RetryFilter::LegacyCallData::CallAttempt::
MaybeCancelPerAttemptRecvTimer() {
if (per_attempt_recv_timer_handle_.has_value()) {
if (per_attempt_recv_timer_handle_ != TaskHandle::kInvalid) {
GRPC_TRACE_LOG(retry, INFO)
<< "chand=" << calld_->chand_ << " calld=" << calld_
<< " attempt=" << this << ": cancelling perAttemptRecvTimeout timer";
if (calld_->chand_->event_engine()->Cancel(
*per_attempt_recv_timer_handle_)) {
per_attempt_recv_timer_handle_)) {
Unref(DEBUG_LOCATION, "OnPerAttemptRecvTimer");
GRPC_CALL_STACK_UNREF(calld_->owning_call_, "OnPerAttemptRecvTimer");
}
per_attempt_recv_timer_handle_.reset();
per_attempt_recv_timer_handle_ = TaskHandle::kInvalid;
}
}
@ -1481,7 +1485,6 @@ RetryFilter::LegacyCallData::LegacyCallData(RetryFilter* chand,
.set_max_backoff(retry_policy_ == nullptr
? Duration::Zero()
: retry_policy_->max_backoff())),
path_(CSliceRef(args.path)),
deadline_(args.deadline),
arena_(args.arena),
owning_call_(args.call_stack),
@ -1497,7 +1500,6 @@ RetryFilter::LegacyCallData::LegacyCallData(RetryFilter* chand,
RetryFilter::LegacyCallData::~LegacyCallData() {
FreeAllCachedSendOpData();
CSliceUnref(path_);
// Make sure there are no remaining pending batches.
for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) {
CHECK_EQ(pending_batches_[i].batch, nullptr);
@ -1550,13 +1552,13 @@ void RetryFilter::LegacyCallData::StartTransportStreamOpBatch(
return;
}
// Cancel retry timer if needed.
if (retry_timer_handle_.has_value()) {
if (retry_timer_handle_ != TaskHandle::kInvalid) {
GRPC_TRACE_LOG(retry, INFO) << "chand=" << chand_ << " calld=" << this
<< ": cancelling retry timer";
if (chand_->event_engine()->Cancel(*retry_timer_handle_)) {
if (chand_->event_engine()->Cancel(retry_timer_handle_)) {
GRPC_CALL_STACK_UNREF(owning_call_, "OnRetryTimer");
}
retry_timer_handle_.reset();
retry_timer_handle_ = TaskHandle::kInvalid;
FreeAllCachedSendOpData();
}
// We have no call attempt, so there's nowhere to send the cancellation
@ -1570,7 +1572,7 @@ void RetryFilter::LegacyCallData::StartTransportStreamOpBatch(
PendingBatch* pending = PendingBatchesAdd(batch);
// If the timer is pending, yield the call combiner and wait for it to
// run, since we don't want to start another call attempt until it does.
if (retry_timer_handle_.has_value()) {
if (retry_timer_handle_ != TaskHandle::kInvalid) {
GRPC_CALL_COMBINER_STOP(call_combiner_,
"added pending batch while retry timer pending");
return;
@ -1627,9 +1629,9 @@ void RetryFilter::LegacyCallData::StartTransportStreamOpBatch(
OrphanablePtr<ClientChannelFilter::FilterBasedLoadBalancedCall>
RetryFilter::LegacyCallData::CreateLoadBalancedCall(
absl::AnyInvocable<void()> on_commit, bool is_transparent_retry) {
grpc_call_element_args args = {owning_call_, nullptr, path_,
/*start_time=*/0, deadline_, arena_,
call_combiner_};
grpc_call_element_args args = {owning_call_, nullptr,
/*start_time=*/0, deadline_,
arena_, call_combiner_};
return chand_->client_channel()->CreateLoadBalancedCall(
args, pollent_,
// This callback holds a ref to the CallStackDestructionBarrier
@ -1912,8 +1914,8 @@ void RetryFilter::LegacyCallData::OnRetryTimer() {
void RetryFilter::LegacyCallData::OnRetryTimerLocked(
void* arg, grpc_error_handle /*error*/) {
auto* calld = static_cast<RetryFilter::LegacyCallData*>(arg);
if (calld->retry_timer_handle_.has_value()) {
calld->retry_timer_handle_.reset();
if (calld->retry_timer_handle_ != TaskHandle::kInvalid) {
calld->retry_timer_handle_ = TaskHandle::kInvalid;
calld->CreateCallAttempt(/*is_transparent_retry=*/false);
}
GRPC_CALL_STACK_UNREF(calld->owning_call_, "OnRetryTimer");

View File

@ -27,6 +27,7 @@
#include "absl/container/inlined_vector.h"
#include "absl/functional/any_invocable.h"
#include "src/core/call/metadata_batch.h"
#include "src/core/client_channel/client_channel_filter.h"
#include "src/core/client_channel/retry_filter.h"
#include "src/core/client_channel/retry_service_config.h"
@ -39,7 +40,6 @@
#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/transport/metadata_batch.h"
#include "src/core/lib/transport/transport.h"
#include "src/core/util/backoff.h"
#include "src/core/util/debug_location.h"
@ -256,8 +256,9 @@ class RetryFilter::LegacyCallData final {
bool lb_call_committed_ = false;
grpc_closure on_per_attempt_recv_timer_;
std::optional<grpc_event_engine::experimental::EventEngine::TaskHandle>
per_attempt_recv_timer_handle_;
grpc_event_engine::experimental::EventEngine::TaskHandle
per_attempt_recv_timer_handle_ =
grpc_event_engine::experimental::EventEngine::TaskHandle::kInvalid;
// BatchData.batch.payload points to this.
grpc_transport_stream_op_batch_payload batch_payload_;
@ -373,7 +374,6 @@ class RetryFilter::LegacyCallData final {
const internal::RetryMethodConfig* retry_policy_ = nullptr;
BackOff retry_backoff_;
grpc_slice path_; // Request path.
Timestamp deadline_;
Arena* arena_;
grpc_call_stack* owning_call_;
@ -410,8 +410,8 @@ class RetryFilter::LegacyCallData final {
bool retry_codepath_started_ : 1;
bool sent_transparent_retry_not_seen_by_server_ : 1;
int num_attempts_completed_ = 0;
std::optional<grpc_event_engine::experimental::EventEngine::TaskHandle>
retry_timer_handle_;
grpc_event_engine::experimental::EventEngine::TaskHandle retry_timer_handle_ =
grpc_event_engine::experimental::EventEngine::TaskHandle::kInvalid;
grpc_closure retry_closure_;
// Cached data for retrying send ops.

View File

@ -15,12 +15,12 @@
#ifndef GRPC_SRC_CORE_CLIENT_CHANNEL_RETRY_INTERCEPTOR_H
#define GRPC_SRC_CORE_CLIENT_CHANNEL_RETRY_INTERCEPTOR_H
#include "src/core/call/interception_chain.h"
#include "src/core/call/request_buffer.h"
#include "src/core/client_channel/client_channel_args.h"
#include "src/core/client_channel/retry_service_config.h"
#include "src/core/client_channel/retry_throttle.h"
#include "src/core/filter/filter_args.h"
#include "src/core/lib/transport/interception_chain.h"
#include "src/core/util/backoff.h"
namespace grpc_core {

View File

@ -30,9 +30,9 @@
#include "absl/log/log.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "src/core/call/status_util.h"
#include "src/core/config/core_configuration.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/status_util.h"
#include "src/core/util/json/json_channel_args.h"
// As per the retry design, we do not allow more than 5 retry attempts.

View File

@ -25,9 +25,9 @@
#include <optional>
#include "absl/strings/string_view.h"
#include "src/core/call/status_util.h"
#include "src/core/config/core_configuration.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/status_util.h"
#include "src/core/service_config/service_config_parser.h"
#include "src/core/util/json/json.h"
#include "src/core/util/json/json_args.h"

View File

@ -49,32 +49,12 @@ T ClampedAdd(std::atomic<T>& value, T delta, T min, T max) {
// ServerRetryThrottleData
//
ServerRetryThrottleData::ServerRetryThrottleData(
uintptr_t max_milli_tokens, uintptr_t milli_token_ratio,
ServerRetryThrottleData* old_throttle_data)
ServerRetryThrottleData::ServerRetryThrottleData(uintptr_t max_milli_tokens,
uintptr_t milli_token_ratio,
uintptr_t milli_tokens)
: max_milli_tokens_(max_milli_tokens),
milli_token_ratio_(milli_token_ratio) {
uintptr_t initial_milli_tokens = max_milli_tokens;
// If there was a pre-existing entry for this server name, initialize
// the token count by scaling proportionately to the old data. This
// ensures that if we're already throttling retries on the old scale,
// we will start out doing the same thing on the new one.
if (old_throttle_data != nullptr) {
double token_fraction =
static_cast<double>(
old_throttle_data->milli_tokens_.load(std::memory_order_relaxed)) /
static_cast<double>(old_throttle_data->max_milli_tokens_);
initial_milli_tokens =
static_cast<uintptr_t>(token_fraction * max_milli_tokens);
}
milli_tokens_.store(initial_milli_tokens, std::memory_order_relaxed);
// If there was a pre-existing entry, mark it as stale and give it a
// pointer to the new entry, which is its replacement.
if (old_throttle_data != nullptr) {
Ref().release(); // Ref held by pre-existing entry.
old_throttle_data->replacement_.store(this, std::memory_order_release);
}
}
milli_token_ratio_(milli_token_ratio),
milli_tokens_(milli_tokens) {}
ServerRetryThrottleData::~ServerRetryThrottleData() {
ServerRetryThrottleData* replacement =
@ -84,6 +64,11 @@ ServerRetryThrottleData::~ServerRetryThrottleData() {
}
}
void ServerRetryThrottleData::SetReplacement(
RefCountedPtr<ServerRetryThrottleData> replacement) {
replacement_.store(replacement.release(), std::memory_order_release);
}
void ServerRetryThrottleData::GetReplacementThrottleDataIfNeeded(
ServerRetryThrottleData** throttle_data) {
while (true) {
@ -133,20 +118,31 @@ RefCountedPtr<ServerRetryThrottleData> ServerRetryThrottleMap::GetDataForServer(
const std::string& server_name, uintptr_t max_milli_tokens,
uintptr_t milli_token_ratio) {
MutexLock lock(&mu_);
auto it = map_.find(server_name);
ServerRetryThrottleData* throttle_data =
it == map_.end() ? nullptr : it->second.get();
auto& throttle_data = map_[server_name];
if (throttle_data == nullptr ||
throttle_data->max_milli_tokens() != max_milli_tokens ||
throttle_data->milli_token_ratio() != milli_token_ratio) {
// Entry not found, or found with old parameters. Create a new one.
it = map_.emplace(server_name,
MakeRefCounted<ServerRetryThrottleData>(
max_milli_tokens, milli_token_ratio, throttle_data))
.first;
throttle_data = it->second.get();
auto old_throttle_data = std::move(throttle_data);
uintptr_t initial_milli_tokens = max_milli_tokens;
// If there was a pre-existing entry for this server name, initialize
// the token count by scaling proportionately to the old data. This
// ensures that if we're already throttling retries on the old scale,
// we will start out doing the same thing on the new one.
if (old_throttle_data != nullptr) {
double token_fraction =
static_cast<double>(old_throttle_data->milli_tokens()) /
static_cast<double>(old_throttle_data->max_milli_tokens());
initial_milli_tokens =
static_cast<uintptr_t>(token_fraction * max_milli_tokens);
}
throttle_data = MakeRefCounted<ServerRetryThrottleData>(
max_milli_tokens, milli_token_ratio, initial_milli_tokens);
if (old_throttle_data != nullptr) {
old_throttle_data->SetReplacement(throttle_data);
}
}
return throttle_data->Ref();
return throttle_data;
}
} // namespace internal

View File

@ -34,13 +34,14 @@
namespace grpc_core {
namespace internal {
class ServerRetryThrottleMap;
/// Tracks retry throttling data for an individual server name.
class ServerRetryThrottleData final
: public RefCounted<ServerRetryThrottleData> {
public:
ServerRetryThrottleData(uintptr_t max_milli_tokens,
uintptr_t milli_token_ratio,
ServerRetryThrottleData* old_throttle_data);
uintptr_t milli_token_ratio, uintptr_t milli_tokens);
~ServerRetryThrottleData() override;
/// Records a failure. Returns true if it's okay to send a retry.
@ -51,8 +52,15 @@ class ServerRetryThrottleData final
uintptr_t max_milli_tokens() const { return max_milli_tokens_; }
uintptr_t milli_token_ratio() const { return milli_token_ratio_; }
intptr_t milli_tokens() const {
return milli_tokens_.load(std::memory_order_relaxed);
}
private:
friend ServerRetryThrottleMap;
void SetReplacement(RefCountedPtr<ServerRetryThrottleData> replacement);
void GetReplacementThrottleDataIfNeeded(
ServerRetryThrottleData** throttle_data);

View File

@ -35,6 +35,7 @@
#include "absl/strings/cord.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "src/core/call/interception_chain.h"
#include "src/core/channelz/channel_trace.h"
#include "src/core/channelz/channelz.h"
#include "src/core/client_channel/client_channel_internal.h"
@ -57,7 +58,6 @@
#include "src/core/lib/surface/init_internally.h"
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/error_utils.h"
#include "src/core/lib/transport/interception_chain.h"
#include "src/core/lib/transport/transport.h"
#include "src/core/telemetry/stats.h"
#include "src/core/telemetry/stats_data.h"
@ -244,13 +244,12 @@ SubchannelCall::SubchannelCall(Args args, grpc_error_handle* error)
deadline_(args.deadline) {
grpc_call_stack* callstk = SUBCHANNEL_CALL_TO_CALL_STACK(this);
const grpc_call_element_args call_args = {
callstk, // call_stack
nullptr, // server_transport_data
args.path.c_slice(), // path
args.start_time, // start_time
args.deadline, // deadline
args.arena, // arena
args.call_combiner // call_combiner
callstk, // call_stack
nullptr, // server_transport_data
args.start_time, // start_time
args.deadline, // deadline
args.arena, // arena
args.call_combiner // call_combiner
};
*error = grpc_call_stack_init(connected_subchannel_->channel_stack(), 1,
SubchannelCall::Destroy, this, &call_args);
@ -453,10 +452,8 @@ void Subchannel::ConnectivityStateWatcherList::RemoveWatcherLocked(
void Subchannel::ConnectivityStateWatcherList::NotifyLocked(
grpc_connectivity_state state, const absl::Status& status) {
for (const auto& watcher : watchers_) {
subchannel_->work_serializer_.Run([watcher = watcher->Ref(), state,
status]() mutable {
auto* watcher_ptr = watcher.get();
watcher_ptr->OnConnectivityStateChange(std::move(watcher), state, status);
subchannel_->work_serializer_.Run([watcher, state, status]() {
watcher->OnConnectivityStateChange(state, status);
});
}
}
@ -552,6 +549,8 @@ Subchannel::Subchannel(SubchannelKey key,
channelz_node_->AddTraceEvent(
channelz::ChannelTrace::Severity::Info,
grpc_slice_from_static_string("subchannel created"));
channelz_node_->SetChannelArgs(args_);
args_ = args_.SetObject<channelz::BaseNode>(channelz_node_);
}
}
@ -613,10 +612,8 @@ void Subchannel::WatchConnectivityState(
grpc_pollset_set_add_pollset_set(pollset_set_, interested_parties);
}
work_serializer_.Run(
[watcher = watcher->Ref(), state = state_, status = status_]() mutable {
auto* watcher_ptr = watcher.get();
watcher_ptr->OnConnectivityStateChange(std::move(watcher), state,
status);
[watcher, state = state_, status = status_]() {
watcher->OnConnectivityStateChange(state, status);
},
DEBUG_LOCATION);
watcher_list_.AddWatcherLocked(std::move(watcher));
@ -793,7 +790,7 @@ void Subchannel::OnConnectingFinishedLocked(grpc_error_handle error) {
}
bool Subchannel::PublishTransportLocked() {
auto socket_node = std::move(connecting_result_.socket_node);
auto socket_node = connecting_result_.transport->GetSocketNode();
if (connecting_result_.transport->filter_stack_transport() != nullptr) {
// Construct channel stack.
// Builder takes ownership of transport.

View File

@ -29,6 +29,7 @@
#include "absl/base/thread_annotations.h"
#include "absl/container/flat_hash_set.h"
#include "absl/status/status.h"
#include "src/core/call/metadata_batch.h"
#include "src/core/client_channel/connector.h"
#include "src/core/client_channel/subchannel_pool_interface.h"
#include "src/core/lib/address_utils/sockaddr_utils.h"
@ -44,7 +45,6 @@
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/slice/slice.h"
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/transport.h"
#include "src/core/util/backoff.h"
#include "src/core/util/debug_location.h"
@ -95,7 +95,6 @@ class SubchannelCall final {
struct Args {
RefCountedPtr<ConnectedSubchannel> connected_subchannel;
grpc_polling_entity* pollent;
Slice path;
gpr_cycle_counter start_time;
Timestamp deadline;
Arena* arena;
@ -169,14 +168,8 @@ class Subchannel final : public DualRefCounted<Subchannel> {
// Invoked whenever the subchannel's connectivity state changes.
// There will be only one invocation of this method on a given watcher
// instance at any given time.
// A ref to the watcher is passed in here so that the implementation
// can unref it in the appropriate synchronization context (e.g.,
// inside a WorkSerializer).
// TODO(roth): Figure out a cleaner way to guarantee that the ref is
// released in the right context.
virtual void OnConnectivityStateChange(
RefCountedPtr<ConnectivityStateWatcherInterface> self,
grpc_connectivity_state state, const absl::Status& status) = 0;
virtual void OnConnectivityStateChange(grpc_connectivity_state state,
const absl::Status& status) = 0;
virtual grpc_pollset_set* interested_parties() = 0;
};

View File

@ -38,13 +38,12 @@ SubchannelKey::SubchannelKey(const grpc_resolved_address& address,
const ChannelArgs& args)
: address_(address), args_(args) {}
bool SubchannelKey::operator<(const SubchannelKey& other) const {
if (address_.len < other.address_.len) return true;
if (address_.len > other.address_.len) return false;
int SubchannelKey::Compare(const SubchannelKey& other) const {
if (address_.len < other.address_.len) return -1;
if (address_.len > other.address_.len) return 1;
int r = memcmp(address_.addr, other.address_.addr, address_.len);
if (r < 0) return true;
if (r > 0) return false;
return args_ < other.args();
if (r != 0) return r;
return QsortCompare(args_, other.args_);
}
std::string SubchannelKey::ToString() const {

View File

@ -45,7 +45,17 @@ class SubchannelKey final {
SubchannelKey(SubchannelKey&& other) noexcept = default;
SubchannelKey& operator=(SubchannelKey&& other) noexcept = default;
bool operator<(const SubchannelKey& other) const;
bool operator<(const SubchannelKey& other) const {
return Compare(other) < 0;
}
bool operator>(const SubchannelKey& other) const {
return Compare(other) > 0;
}
bool operator==(const SubchannelKey& other) const {
return Compare(other) == 0;
}
int Compare(const SubchannelKey& other) const;
const grpc_resolved_address& address() const { return address_; }
const ChannelArgs& args() const { return args_; }

View File

@ -130,7 +130,7 @@ void SubchannelStreamClient::StartRetryTimerLocked() {
const Duration timeout = retry_backoff_.NextAttemptDelay();
if (GPR_UNLIKELY(tracer_ != nullptr)) {
LOG(INFO) << tracer_ << " " << this
<< ": SubchannelStreamClient health check call lost...";
<< ": SubchannelStreamClient call lost...";
if (timeout > Duration::Zero()) {
LOG(INFO) << tracer_ << " " << this << ": ... will retry in "
<< timeout.millis() << "ms.";
@ -139,10 +139,10 @@ void SubchannelStreamClient::StartRetryTimerLocked() {
}
}
retry_timer_handle_ = event_engine_->RunAfter(
timeout, [self = Ref(DEBUG_LOCATION, "health_retry_timer")]() mutable {
timeout, [self = Ref(DEBUG_LOCATION, "retry_timer")]() mutable {
ExecCtx exec_ctx;
self->OnRetryTimer();
self.reset(DEBUG_LOCATION, "health_retry_timer");
self.reset(DEBUG_LOCATION, "retry_timer");
});
}
@ -152,7 +152,7 @@ void SubchannelStreamClient::OnRetryTimer() {
call_state_ == nullptr) {
if (GPR_UNLIKELY(tracer_ != nullptr)) {
LOG(INFO) << tracer_ << " " << this
<< ": SubchannelStreamClient restarting health check call";
<< ": SubchannelStreamClient restarting call";
}
StartCallLocked();
}
@ -164,9 +164,9 @@ void SubchannelStreamClient::OnRetryTimer() {
//
SubchannelStreamClient::CallState::CallState(
RefCountedPtr<SubchannelStreamClient> health_check_client,
RefCountedPtr<SubchannelStreamClient> subchannel_stream_client,
grpc_pollset_set* interested_parties)
: subchannel_stream_client_(std::move(health_check_client)),
: subchannel_stream_client_(std::move(subchannel_stream_client)),
pollent_(grpc_polling_entity_create_from_pollset_set(interested_parties)),
arena_(subchannel_stream_client_->call_allocator_->MakeArena()) {}
@ -192,7 +192,6 @@ void SubchannelStreamClient::CallState::StartCallLocked() {
SubchannelCall::Args args = {
subchannel_stream_client_->connected_subchannel_,
&pollent_,
Slice::FromStaticString("/grpc.health.v1.Health/Watch"),
gpr_get_cycle_counter(), // start_time
Timestamp::InfFuture(), // deadline
arena_.get(),
@ -299,7 +298,7 @@ void SubchannelStreamClient::CallState::AfterCallStackDestruction(
void SubchannelStreamClient::CallState::OnCancelComplete(
void* arg, grpc_error_handle /*error*/) {
auto* self = static_cast<SubchannelStreamClient::CallState*>(arg);
GRPC_CALL_COMBINER_STOP(&self->call_combiner_, "health_cancel");
GRPC_CALL_COMBINER_STOP(&self->call_combiner_, "cancel_batch");
self->call_->Unref(DEBUG_LOCATION, "cancel");
}
@ -322,7 +321,7 @@ void SubchannelStreamClient::CallState::Cancel() {
GRPC_CALL_COMBINER_START(
&call_combiner_,
GRPC_CLOSURE_CREATE(StartCancel, this, grpc_schedule_on_exec_ctx),
absl::OkStatus(), "health_cancel");
absl::OkStatus(), "cancel_batch");
}
}
@ -406,18 +405,22 @@ void SubchannelStreamClient::CallState::RecvTrailingMetadataReady(
LOG(INFO) << self->subchannel_stream_client_->tracer_ << " "
<< self->subchannel_stream_client_.get()
<< ": SubchannelStreamClient CallState " << self
<< ": health watch failed with status " << status;
<< ": call failed with status " << status;
}
// Clean up.
self->recv_trailing_metadata_.Clear();
// Report call end.
// Note: We hold a ref to the SubchannelStreamClient here to ensure
// that it lives long enough for us to release the mutex, since the
// call to CallEndedLocked() may release the last ref.
auto subchannel_stream_client = self->subchannel_stream_client_->Ref();
MutexLock lock(&self->subchannel_stream_client_->mu_);
if (self->subchannel_stream_client_->event_handler_ != nullptr) {
self->subchannel_stream_client_->event_handler_
->RecvTrailingMetadataReadyLocked(self->subchannel_stream_client_.get(),
status);
}
// For status UNIMPLEMENTED, give up and assume always healthy.
// For status UNIMPLEMENTED, give up.
self->CallEndedLocked(/*retry=*/status != GRPC_STATUS_UNIMPLEMENTED);
}

View File

@ -30,6 +30,7 @@
#include "absl/base/thread_annotations.h"
#include "absl/status/status.h"
#include "absl/strings/string_view.h"
#include "src/core/call/metadata_batch.h"
#include "src/core/client_channel/subchannel.h"
#include "src/core/lib/iomgr/call_combiner.h"
#include "src/core/lib/iomgr/closure.h"
@ -40,7 +41,6 @@
#include "src/core/lib/resource_quota/memory_quota.h"
#include "src/core/lib/slice/slice.h"
#include "src/core/lib/slice/slice_buffer.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/transport.h"
#include "src/core/util/backoff.h"
#include "src/core/util/orphanable.h"
@ -202,7 +202,7 @@ class SubchannelStreamClient final
Mutex mu_;
std::unique_ptr<CallEventHandler> event_handler_ ABSL_GUARDED_BY(mu_);
// The data associated with the current health check call. It holds a ref
// The data associated with the current call. It holds a ref
// to this SubchannelStreamClient object.
OrphanablePtr<CallState> call_state_ ABSL_GUARDED_BY(mu_);

View File

@ -76,6 +76,11 @@ ABSL_FLAG(absl::optional<bool>, grpc_cpp_experimental_disable_reflection, {},
"EXPERIMENTAL. Only respected when there is a dependency on "
":grpc++_reflection. If true, no reflection server will be "
"automatically added.");
ABSL_FLAG(
absl::optional<int32_t>, grpc_channelz_max_orphaned_nodes, {},
"EXPERIMENTAL: If non-zero, extend the lifetime of channelz nodes past the "
"underlying object lifetime, up to this many nodes. The value may be "
"adjusted slightly to account for implementation limits.");
namespace grpc_core {
@ -84,6 +89,10 @@ ConfigVars::ConfigVars(const Overrides& overrides)
LoadConfig(FLAGS_grpc_client_channel_backup_poll_interval_ms,
"GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS",
overrides.client_channel_backup_poll_interval_ms, 5000)),
channelz_max_orphaned_nodes_(
LoadConfig(FLAGS_grpc_channelz_max_orphaned_nodes,
"GRPC_CHANNELZ_MAX_ORPHANED_NODES",
overrides.channelz_max_orphaned_nodes, 0)),
enable_fork_support_(LoadConfig(
FLAGS_grpc_enable_fork_support, "GRPC_ENABLE_FORK_SUPPORT",
overrides.enable_fork_support, GRPC_ENABLE_FORK_SUPPORT_DEFAULT)),
@ -146,7 +155,8 @@ std::string ConfigVars::ToString() const {
", not_use_system_ssl_roots: ", NotUseSystemSslRoots() ? "true" : "false",
", ssl_cipher_suites: ", "\"", absl::CEscape(SslCipherSuites()), "\"",
", cpp_experimental_disable_reflection: ",
CppExperimentalDisableReflection() ? "true" : "false");
CppExperimentalDisableReflection() ? "true" : "false",
", channelz_max_orphaned_nodes: ", ChannelzMaxOrphanedNodes());
}
} // namespace grpc_core

View File

@ -35,6 +35,7 @@ class GPR_DLL ConfigVars {
public:
struct Overrides {
absl::optional<int32_t> client_channel_backup_poll_interval_ms;
absl::optional<int32_t> channelz_max_orphaned_nodes;
absl::optional<bool> enable_fork_support;
absl::optional<bool> abort_on_leaks;
absl::optional<bool> not_use_system_ssl_roots;
@ -104,12 +105,19 @@ class GPR_DLL ConfigVars {
bool CppExperimentalDisableReflection() const {
return cpp_experimental_disable_reflection_;
}
// EXPERIMENTAL: If non-zero, extend the lifetime of channelz nodes past the
// underlying object lifetime, up to this many nodes. The value may be
// adjusted slightly to account for implementation limits.
int32_t ChannelzMaxOrphanedNodes() const {
return channelz_max_orphaned_nodes_;
}
private:
explicit ConfigVars(const Overrides& overrides);
static const ConfigVars& Load();
static std::atomic<ConfigVars*> config_vars_;
int32_t client_channel_backup_poll_interval_ms_;
int32_t channelz_max_orphaned_nodes_;
bool enable_fork_support_;
bool abort_on_leaks_;
bool not_use_system_ssl_roots_;

View File

@ -25,8 +25,10 @@
namespace grpc_core {
std::atomic<CoreConfiguration*> CoreConfiguration::config_{nullptr};
std::atomic<CoreConfiguration::RegisteredBuilder*> CoreConfiguration::builders_{
nullptr};
std::atomic<CoreConfiguration::RegisteredBuilder*>
CoreConfiguration::builders_[static_cast<size_t>(BuilderScope::kCount)]{
nullptr, nullptr};
std::atomic<bool> CoreConfiguration::has_config_ever_been_produced_{false};
void (*CoreConfiguration::default_builder_)(CoreConfiguration::Builder*);
CoreConfiguration::Builder::Builder() = default;
@ -46,18 +48,31 @@ CoreConfiguration::CoreConfiguration(Builder* builder)
lb_policy_registry_(builder->lb_policy_registry_.Build()),
proxy_mapper_registry_(builder->proxy_mapper_registry_.Build()),
certificate_provider_registry_(
builder->certificate_provider_registry_.Build()) {}
builder->certificate_provider_registry_.Build()),
endpoint_transport_registry_(
builder->endpoint_transport_registry_.Build()) {}
void CoreConfiguration::RegisterBuilder(
absl::AnyInvocable<void(Builder*)> builder) {
BuilderScope scope, absl::AnyInvocable<void(Builder*)> builder,
SourceLocation whence) {
CHECK(config_.load(std::memory_order_relaxed) == nullptr)
<< "CoreConfiguration was already instantiated before builder "
"registration was completed";
if (scope == BuilderScope::kPersistent) {
CHECK(!has_config_ever_been_produced_.load(std::memory_order_relaxed))
<< "Persistent builders cannot be registered after the first "
"CoreConfiguration has been produced";
}
CHECK_NE(scope, BuilderScope::kCount);
auto& head = builders_[static_cast<size_t>(scope)];
RegisteredBuilder* n = new RegisteredBuilder();
VLOG(4) << "Registering " << scope << " builder from " << whence.file() << ":"
<< whence.line();
n->builder = std::move(builder);
n->next = builders_.load(std::memory_order_relaxed);
while (!builders_.compare_exchange_weak(n->next, n, std::memory_order_acq_rel,
std::memory_order_relaxed)) {
n->whence = whence;
n->next = head.load(std::memory_order_relaxed);
while (!head.compare_exchange_weak(n->next, n, std::memory_order_acq_rel,
std::memory_order_relaxed)) {
}
CHECK(config_.load(std::memory_order_relaxed) == nullptr)
<< "CoreConfiguration was already instantiated before builder "
@ -65,6 +80,7 @@ void CoreConfiguration::RegisterBuilder(
}
const CoreConfiguration& CoreConfiguration::BuildNewAndMaybeSet() {
has_config_ever_been_produced_.store(true, std::memory_order_relaxed);
// Construct builder, pass it up to code that knows about build configuration
Builder builder;
// The linked list of builders stores things in reverse registration order.
@ -72,13 +88,21 @@ const CoreConfiguration& CoreConfiguration::BuildNewAndMaybeSet() {
// actually need to run things in forward registration order, so we iterate
// once over the linked list to build a vector of builders, and then iterate
// over said vector in reverse to actually run the builders.
// Note that we also iterate scopes in reverse order here too, so that when
// we run the builders in the reverse generated order we'll actually run
// persistent builders before ephemeral ones.
std::vector<RegisteredBuilder*> registered_builders;
for (RegisteredBuilder* b = builders_.load(std::memory_order_acquire);
b != nullptr; b = b->next) {
registered_builders.push_back(b);
for (auto scope : {BuilderScope::kEphemeral, BuilderScope::kPersistent}) {
for (RegisteredBuilder* b = builders_[static_cast<size_t>(scope)].load(
std::memory_order_acquire);
b != nullptr; b = b->next) {
registered_builders.push_back(b);
}
}
for (auto it = registered_builders.rbegin(); it != registered_builders.rend();
++it) {
VLOG(4) << "Running builder from " << (*it)->whence.file() << ":"
<< (*it)->whence.line();
(*it)->builder(&builder);
}
// Finally, call the built in configuration builder.
@ -100,7 +124,8 @@ const CoreConfiguration& CoreConfiguration::BuildNewAndMaybeSet() {
void CoreConfiguration::Reset() {
delete config_.exchange(nullptr, std::memory_order_acquire);
RegisteredBuilder* builder =
builders_.exchange(nullptr, std::memory_order_acquire);
builders_[static_cast<size_t>(BuilderScope::kEphemeral)].exchange(
nullptr, std::memory_order_acquire);
while (builder != nullptr) {
RegisteredBuilder* next = builder->next;
delete builder;
@ -108,4 +133,18 @@ void CoreConfiguration::Reset() {
}
}
void CoreConfiguration::
ResetEverythingIncludingPersistentBuildersAbsolutelyNotRecommended() {
has_config_ever_been_produced_.store(false, std::memory_order_relaxed);
RegisteredBuilder* builder =
builders_[static_cast<size_t>(BuilderScope::kPersistent)].exchange(
nullptr, std::memory_order_acquire);
while (builder != nullptr) {
RegisteredBuilder* next = builder->next;
delete builder;
builder = next;
}
Reset();
}
} // namespace grpc_core

View File

@ -16,6 +16,7 @@
#define GRPC_SRC_CORE_CONFIG_CORE_CONFIGURATION_H
#include <grpc/support/port_platform.h>
#include <sys/stat.h>
#include <atomic>
@ -30,6 +31,8 @@
#include "src/core/load_balancing/lb_policy_registry.h"
#include "src/core/resolver/resolver_registry.h"
#include "src/core/service_config/service_config_parser.h"
#include "src/core/transport/endpoint_transport.h"
#include "src/core/util/debug_location.h"
namespace grpc_core {
@ -40,6 +43,27 @@ class GRPC_DLL CoreConfiguration {
CoreConfiguration(const CoreConfiguration&) = delete;
CoreConfiguration& operator=(const CoreConfiguration&) = delete;
// BulderScope is used to indicate whether a builder is persistent - these
// are builders that are used every time the configuration is built, or
// ephemeral - each time the configuration is built these are thrown away.
//
// Considerations for choosing persistent vs ephemeral:
// - For testing we want ephemeral builders, so the next test can throw away
// configuration.
// - For adapting gRPC to different environments we typically want persistent
// builders.
// - However, if the adaption should run only once per process, then
// ephemeral is better.
//
// Builders are instantiated in scope order - persistent first, ephemeral
// second.
enum class BuilderScope {
kPersistent,
kEphemeral,
// Must be last, do not use as a scope.
kCount,
};
// Builder is passed to plugins, etc... at initialization time to collect
// their configuration and assemble the published CoreConfiguration.
class Builder {
@ -78,6 +102,10 @@ class GRPC_DLL CoreConfiguration {
return &certificate_provider_registry_;
}
EndpointTransportRegistry::Builder* endpoint_transport_registry() {
return &endpoint_transport_registry_;
}
private:
friend class CoreConfiguration;
@ -90,6 +118,7 @@ class GRPC_DLL CoreConfiguration {
LoadBalancingPolicyRegistry::Builder lb_policy_registry_;
ProxyMapperRegistry::Builder proxy_mapper_registry_;
CertificateProviderRegistry::Builder certificate_provider_registry_;
EndpointTransportRegistry::Builder endpoint_transport_registry_;
Builder();
CoreConfiguration* Build();
@ -99,6 +128,7 @@ class GRPC_DLL CoreConfiguration {
struct RegisteredBuilder {
absl::AnyInvocable<void(Builder*)> builder;
RegisteredBuilder* next;
SourceLocation whence;
};
// Temporarily replaces core configuration with what is built from the
@ -121,8 +151,10 @@ class GRPC_DLL CoreConfiguration {
// Backup current core configuration and replace/reset.
config_restore_ =
CoreConfiguration::config_.exchange(p, std::memory_order_acquire);
builders_restore_ = CoreConfiguration::builders_.exchange(
nullptr, std::memory_order_acquire);
builders_restore_ =
CoreConfiguration::builders_[static_cast<size_t>(
BuilderScope::kEphemeral)]
.exchange(nullptr, std::memory_order_acquire);
}
~WithSubstituteBuilder() {
@ -130,8 +162,10 @@ class GRPC_DLL CoreConfiguration {
Reset();
CHECK(CoreConfiguration::config_.exchange(
config_restore_, std::memory_order_acquire) == nullptr);
CHECK(CoreConfiguration::builders_.exchange(
builders_restore_, std::memory_order_acquire) == nullptr);
CHECK(CoreConfiguration::builders_[static_cast<size_t>(
BuilderScope::kEphemeral)]
.exchange(builders_restore_, std::memory_order_acquire) ==
nullptr);
}
private:
@ -153,13 +187,34 @@ class GRPC_DLL CoreConfiguration {
// Attach a registration function globally.
// Each registration function is called *in addition to*
// BuildCoreConfiguration for the default core configuration.
static void RegisterBuilder(absl::AnyInvocable<void(Builder*)> builder);
static void RegisterBuilder(BuilderScope scope,
absl::AnyInvocable<void(Builder*)> builder,
SourceLocation whence);
static void RegisterPersistentBuilder(
absl::AnyInvocable<void(Builder*)> builder, SourceLocation whence = {}) {
RegisterBuilder(BuilderScope::kPersistent, std::move(builder), whence);
}
static void RegisterEphemeralBuilder(
absl::AnyInvocable<void(Builder*)> builder, SourceLocation whence = {}) {
RegisterBuilder(BuilderScope::kEphemeral, std::move(builder), whence);
}
// Drop the core configuration. Users must ensure no other threads are
// accessing the configuration.
// Clears any dynamically registered builders.
// Clears any dynamically registered ephemeral builders.
static void Reset();
// Reset, but also reset persistent builders. This is not recommended, but
// is useful for tests that assume exactly the default open source
// configuration when running in other environments.
//
// TODO(ctiller, roth, yashkt): Remove the need for this method, and then
// move the legacy plugin registration mechanism to be a persistent builder.
static void
ResetEverythingIncludingPersistentBuildersAbsolutelyNotRecommended();
// Helper for tests: Reset the configuration, build a special one, run some
// code, and then reset the configuration again.
// Templatized to be sure no codegen in normal builds.
@ -206,6 +261,10 @@ class GRPC_DLL CoreConfiguration {
return certificate_provider_registry_;
}
const EndpointTransportRegistry& endpoint_transport_registry() const {
return endpoint_transport_registry_;
}
static void SetDefaultBuilder(void (*builder)(CoreConfiguration::Builder*)) {
default_builder_ = builder;
}
@ -219,8 +278,13 @@ class GRPC_DLL CoreConfiguration {
// The configuration
static std::atomic<CoreConfiguration*> config_;
// Has a configuration *ever* been produced - we verify this is false for
// persistent builders so that we can prove consistency build to build for
// these.
static std::atomic<bool> has_config_ever_been_produced_;
// Extra registered builders
static std::atomic<RegisteredBuilder*> builders_;
static std::atomic<RegisteredBuilder*>
builders_[static_cast<size_t>(BuilderScope::kCount)];
// Default builder
static void (*default_builder_)(CoreConfiguration::Builder*);
@ -233,8 +297,26 @@ class GRPC_DLL CoreConfiguration {
LoadBalancingPolicyRegistry lb_policy_registry_;
ProxyMapperRegistry proxy_mapper_registry_;
CertificateProviderRegistry certificate_provider_registry_;
EndpointTransportRegistry endpoint_transport_registry_;
};
template <typename Sink>
void AbslStringify(Sink& sink, CoreConfiguration::BuilderScope scope) {
switch (scope) {
case CoreConfiguration::BuilderScope::kPersistent:
sink.Append("Persistent");
break;
case CoreConfiguration::BuilderScope::kEphemeral:
sink.Append("Ephemeral");
break;
case CoreConfiguration::BuilderScope::kCount:
sink.Append("Count(");
sink.Append(std::to_string(static_cast<size_t>(scope)));
sink.Append(")");
break;
}
}
extern void BuildCoreConfiguration(CoreConfiguration::Builder* builder);
} // namespace grpc_core

View File

@ -24,8 +24,8 @@
#include "absl/log/log.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "src/core/call/metadata_batch.h"
#include "src/core/credentials/transport/security_connector.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/transport/auth_context.h"
#include "src/core/util/ref_counted_ptr.h"

View File

@ -25,9 +25,9 @@
#include "absl/log/check.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "src/core/call/metadata_batch.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/promise/try_seq.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/util/ref_counted_ptr.h"
grpc_core::ArenaPromise<absl::StatusOr<grpc_core::ClientMetadataHandle>>

Some files were not shown because too many files have changed in this diff Show More