Merge branch 'master' of https://github.com/grpc/grpc into bazel-0.26

pull/19258/head
Nicolas "Pixel" Noble 6 years ago
commit 29b5a83920
  1. 2
      .gitignore
  2. 2
      BUILD
  3. 2
      BUILD.gn
  4. 16
      CMakeLists.txt
  5. 10
      Makefile
  6. 2
      build.yaml
  7. 10
      doc/environment_variables.md
  8. 2
      gRPC-C++.podspec
  9. 2
      include/grpc/grpc_security.h
  10. 2
      include/grpc/grpc_security_constants.h
  11. 2
      include/grpc/impl/codegen/gpr_types.h
  12. 4
      include/grpc/slice.h
  13. 7
      include/grpcpp/channel_impl.h
  14. 8
      include/grpcpp/impl/codegen/channel_interface.h
  15. 5
      include/grpcpp/impl/codegen/client_callback.h
  16. 470
      include/grpcpp/impl/codegen/client_context.h
  17. 491
      include/grpcpp/impl/codegen/client_context_impl.h
  18. 16
      include/grpcpp/impl/codegen/client_interceptor.h
  19. 12
      include/grpcpp/impl/codegen/client_unary_call.h
  20. 5
      include/grpcpp/impl/codegen/completion_queue_impl.h
  21. 12
      include/grpcpp/impl/codegen/interceptor.h
  22. 8
      include/grpcpp/impl/codegen/rpc_service_method.h
  23. 42
      include/grpcpp/impl/codegen/server_callback.h
  24. 355
      include/grpcpp/impl/codegen/server_context.h
  25. 376
      include/grpcpp/impl/codegen/server_context_impl.h
  26. 14
      include/grpcpp/impl/codegen/server_interceptor.h
  27. 22
      include/grpcpp/impl/codegen/server_interface.h
  28. 11
      include/grpcpp/impl/codegen/service_type.h
  29. 2
      include/grpcpp/opencensus.h
  30. 8
      include/grpcpp/opencensus_impl.h
  31. 6
      include/grpcpp/server_impl.h
  32. 2
      requirements.bazel.txt
  33. 2
      requirements.txt
  34. 2
      src/compiler/cpp_generator.cc
  35. 473
      src/core/ext/filters/client_channel/client_channel.cc
  36. 8
      src/core/ext/filters/client_channel/client_channel.h
  37. 83
      src/core/ext/filters/client_channel/client_channel_channelz.cc
  38. 30
      src/core/ext/filters/client_channel/client_channel_channelz.h
  39. 8
      src/core/ext/filters/client_channel/client_channel_plugin.cc
  40. 19
      src/core/ext/filters/client_channel/lb_policy.cc
  41. 36
      src/core/ext/filters/client_channel/lb_policy.h
  42. 110
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
  43. 103
      src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
  44. 82
      src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
  45. 139
      src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
  46. 331
      src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
  47. 16
      src/core/ext/filters/client_channel/resolver.h
  48. 83
      src/core/ext/filters/client_channel/resolving_lb_policy.cc
  49. 8
      src/core/ext/filters/client_channel/resolving_lb_policy.h
  50. 10
      src/core/ext/filters/client_channel/server_address.cc
  51. 4
      src/core/ext/filters/client_channel/server_address.h
  52. 30
      src/core/ext/filters/client_channel/subchannel.cc
  53. 71
      src/core/ext/filters/client_channel/subchannel.h
  54. 55
      src/core/ext/filters/client_channel/subchannel_interface.h
  55. 10
      src/core/ext/transport/chttp2/transport/frame_data.cc
  56. 5
      src/core/ext/transport/chttp2/transport/frame_rst_stream.cc
  57. 155
      src/core/lib/channel/channelz.cc
  58. 76
      src/core/lib/channel/channelz.h
  59. 110
      src/core/lib/channel/channelz_registry.cc
  60. 32
      src/core/lib/channel/channelz_registry.h
  61. 9
      src/core/lib/gpr/string.cc
  62. 7
      src/core/lib/gpr/string.h
  63. 8
      src/core/lib/gprpp/inlined_vector.h
  64. 38
      src/core/lib/gprpp/map.h
  65. 4
      src/core/lib/gprpp/memory.h
  66. 2
      src/core/lib/gprpp/orphanable.h
  67. 6
      src/core/lib/gprpp/ref_counted.h
  68. 6
      src/core/lib/http/httpcli.cc
  69. 2
      src/core/lib/iomgr/buffer_list.h
  70. 2
      src/core/lib/iomgr/call_combiner.cc
  71. 2
      src/core/lib/iomgr/call_combiner.h
  72. 5
      src/core/lib/iomgr/cfstream_handle.cc
  73. 4
      src/core/lib/iomgr/cfstream_handle.h
  74. 6
      src/core/lib/iomgr/ev_posix.cc
  75. 5
      src/core/lib/iomgr/ev_posix.h
  76. 4
      src/core/lib/iomgr/ev_windows.cc
  77. 2
      src/core/lib/iomgr/lockfree_event.cc
  78. 6
      src/core/lib/iomgr/port.h
  79. 1
      src/core/lib/iomgr/tcp_posix.cc
  80. 11
      src/core/lib/iomgr/tcp_uv.cc
  81. 4
      src/core/lib/security/transport/security_handshaker.cc
  82. 64
      src/core/lib/slice/slice.cc
  83. 5
      src/core/lib/slice/slice_internal.h
  84. 9
      src/core/lib/slice/slice_string_helpers.cc
  85. 2
      src/core/lib/slice/slice_string_helpers.h
  86. 133
      src/core/lib/surface/channel.cc
  87. 4
      src/core/lib/surface/channel.h
  88. 4
      src/core/lib/surface/server.cc
  89. 6
      src/core/lib/surface/validate_metadata.cc
  90. 5
      src/core/lib/transport/metadata.cc
  91. 2
      src/core/lib/transport/transport.cc
  92. 10
      src/core/lib/transport/transport.h
  93. 2
      src/cpp/client/channel_cc.cc
  94. 11
      src/cpp/client/client_context.cc
  95. 5
      src/cpp/ext/filters/census/grpc_plugin.h
  96. 38
      src/cpp/server/server_context.cc
  97. 0
      src/csharp/Grpc.Core.Api/Interceptors/CallInvokerExtensions.cs
  98. 0
      src/csharp/Grpc.Core.Api/Interceptors/InterceptingCallInvoker.cs
  99. 2
      src/csharp/Grpc.Core/ForwardedTypes.cs
  100. 2
      src/csharp/Grpc.Core/ServerCredentials.cs
  101. Some files were not shown because too many files have changed in this diff Show More

2
.gitignore vendored

@ -144,3 +144,5 @@ bm_*.json
!.vscode/launch.json
!.vscode/extensions.json
# Clion artifacts
cmake-build-debug/

@ -2164,6 +2164,7 @@ grpc_cc_library(
"include/grpcpp/impl/codegen/channel_interface.h",
"include/grpcpp/impl/codegen/client_callback.h",
"include/grpcpp/impl/codegen/client_context.h",
"include/grpcpp/impl/codegen/client_context_impl.h",
"include/grpcpp/impl/codegen/client_interceptor.h",
"include/grpcpp/impl/codegen/client_unary_call.h",
"include/grpcpp/impl/codegen/completion_queue.h",
@ -2185,6 +2186,7 @@ grpc_cc_library(
"include/grpcpp/impl/codegen/serialization_traits.h",
"include/grpcpp/impl/codegen/server_callback.h",
"include/grpcpp/impl/codegen/server_context.h",
"include/grpcpp/impl/codegen/server_context_impl.h",
"include/grpcpp/impl/codegen/server_interceptor.h",
"include/grpcpp/impl/codegen/server_interface.h",
"include/grpcpp/impl/codegen/service_type.h",

@ -1054,6 +1054,7 @@ config("grpc_config") {
"include/grpcpp/impl/codegen/channel_interface.h",
"include/grpcpp/impl/codegen/client_callback.h",
"include/grpcpp/impl/codegen/client_context.h",
"include/grpcpp/impl/codegen/client_context_impl.h",
"include/grpcpp/impl/codegen/client_interceptor.h",
"include/grpcpp/impl/codegen/client_unary_call.h",
"include/grpcpp/impl/codegen/completion_queue.h",
@ -1081,6 +1082,7 @@ config("grpc_config") {
"include/grpcpp/impl/codegen/serialization_traits.h",
"include/grpcpp/impl/codegen/server_callback.h",
"include/grpcpp/impl/codegen/server_context.h",
"include/grpcpp/impl/codegen/server_context_impl.h",
"include/grpcpp/impl/codegen/server_interceptor.h",
"include/grpcpp/impl/codegen/server_interface.h",
"include/grpcpp/impl/codegen/service_type.h",

@ -82,6 +82,8 @@ if(UNIX)
set(_gRPC_PLATFORM_LINUX ON)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(_gRPC_PLATFORM_MAC ON)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "iOS")
set(_gRPC_PLATFORM_IOS ON)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Android")
set(_gRPC_PLATFORM_ANDROID ON)
else()
@ -124,7 +126,7 @@ if(gRPC_BACKWARDS_COMPATIBILITY_MODE)
endif()
endif()
if (_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC)
if (_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_IOS)
# C core has C++ source code, but should not depend on libstc++ (for better portability).
# We need to use a few tricks to convince cmake to do that.
# https://stackoverflow.com/questions/15058403/how-to-stop-cmake-from-linking-against-libstdc
@ -149,7 +151,7 @@ if(NOT MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif()
if(_gRPC_PLATFORM_MAC)
if(_gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_IOS)
set(_gRPC_ALLTARGETS_LIBRARIES ${CMAKE_DL_LIBS} m pthread)
elseif(_gRPC_PLATFORM_ANDROID)
set(_gRPC_ALLTARGETS_LIBRARIES ${CMAKE_DL_LIBS} m)
@ -3313,6 +3315,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/channel_interface.h
include/grpcpp/impl/codegen/client_callback.h
include/grpcpp/impl/codegen/client_context.h
include/grpcpp/impl/codegen/client_context_impl.h
include/grpcpp/impl/codegen/client_interceptor.h
include/grpcpp/impl/codegen/client_unary_call.h
include/grpcpp/impl/codegen/completion_queue.h
@ -3334,6 +3337,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/serialization_traits.h
include/grpcpp/impl/codegen/server_callback.h
include/grpcpp/impl/codegen/server_context.h
include/grpcpp/impl/codegen/server_context_impl.h
include/grpcpp/impl/codegen/server_interceptor.h
include/grpcpp/impl/codegen/server_interface.h
include/grpcpp/impl/codegen/service_type.h
@ -3932,6 +3936,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/channel_interface.h
include/grpcpp/impl/codegen/client_callback.h
include/grpcpp/impl/codegen/client_context.h
include/grpcpp/impl/codegen/client_context_impl.h
include/grpcpp/impl/codegen/client_interceptor.h
include/grpcpp/impl/codegen/client_unary_call.h
include/grpcpp/impl/codegen/completion_queue.h
@ -3953,6 +3958,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/serialization_traits.h
include/grpcpp/impl/codegen/server_callback.h
include/grpcpp/impl/codegen/server_context.h
include/grpcpp/impl/codegen/server_context_impl.h
include/grpcpp/impl/codegen/server_interceptor.h
include/grpcpp/impl/codegen/server_interface.h
include/grpcpp/impl/codegen/service_type.h
@ -4367,6 +4373,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/channel_interface.h
include/grpcpp/impl/codegen/client_callback.h
include/grpcpp/impl/codegen/client_context.h
include/grpcpp/impl/codegen/client_context_impl.h
include/grpcpp/impl/codegen/client_interceptor.h
include/grpcpp/impl/codegen/client_unary_call.h
include/grpcpp/impl/codegen/completion_queue.h
@ -4388,6 +4395,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/serialization_traits.h
include/grpcpp/impl/codegen/server_callback.h
include/grpcpp/impl/codegen/server_context.h
include/grpcpp/impl/codegen/server_context_impl.h
include/grpcpp/impl/codegen/server_interceptor.h
include/grpcpp/impl/codegen/server_interface.h
include/grpcpp/impl/codegen/service_type.h
@ -4566,6 +4574,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/channel_interface.h
include/grpcpp/impl/codegen/client_callback.h
include/grpcpp/impl/codegen/client_context.h
include/grpcpp/impl/codegen/client_context_impl.h
include/grpcpp/impl/codegen/client_interceptor.h
include/grpcpp/impl/codegen/client_unary_call.h
include/grpcpp/impl/codegen/completion_queue.h
@ -4587,6 +4596,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/serialization_traits.h
include/grpcpp/impl/codegen/server_callback.h
include/grpcpp/impl/codegen/server_context.h
include/grpcpp/impl/codegen/server_context_impl.h
include/grpcpp/impl/codegen/server_interceptor.h
include/grpcpp/impl/codegen/server_interface.h
include/grpcpp/impl/codegen/service_type.h
@ -4925,6 +4935,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/channel_interface.h
include/grpcpp/impl/codegen/client_callback.h
include/grpcpp/impl/codegen/client_context.h
include/grpcpp/impl/codegen/client_context_impl.h
include/grpcpp/impl/codegen/client_interceptor.h
include/grpcpp/impl/codegen/client_unary_call.h
include/grpcpp/impl/codegen/completion_queue.h
@ -4946,6 +4957,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/serialization_traits.h
include/grpcpp/impl/codegen/server_callback.h
include/grpcpp/impl/codegen/server_context.h
include/grpcpp/impl/codegen/server_context_impl.h
include/grpcpp/impl/codegen/server_interceptor.h
include/grpcpp/impl/codegen/server_interface.h
include/grpcpp/impl/codegen/service_type.h

@ -5670,6 +5670,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/channel_interface.h \
include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_context.h \
include/grpcpp/impl/codegen/client_context_impl.h \
include/grpcpp/impl/codegen/client_interceptor.h \
include/grpcpp/impl/codegen/client_unary_call.h \
include/grpcpp/impl/codegen/completion_queue.h \
@ -5691,6 +5692,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/serialization_traits.h \
include/grpcpp/impl/codegen/server_callback.h \
include/grpcpp/impl/codegen/server_context.h \
include/grpcpp/impl/codegen/server_context_impl.h \
include/grpcpp/impl/codegen/server_interceptor.h \
include/grpcpp/impl/codegen/server_interface.h \
include/grpcpp/impl/codegen/service_type.h \
@ -6297,6 +6299,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/channel_interface.h \
include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_context.h \
include/grpcpp/impl/codegen/client_context_impl.h \
include/grpcpp/impl/codegen/client_interceptor.h \
include/grpcpp/impl/codegen/client_unary_call.h \
include/grpcpp/impl/codegen/completion_queue.h \
@ -6318,6 +6321,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/serialization_traits.h \
include/grpcpp/impl/codegen/server_callback.h \
include/grpcpp/impl/codegen/server_context.h \
include/grpcpp/impl/codegen/server_context_impl.h \
include/grpcpp/impl/codegen/server_interceptor.h \
include/grpcpp/impl/codegen/server_interface.h \
include/grpcpp/impl/codegen/service_type.h \
@ -6704,6 +6708,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/channel_interface.h \
include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_context.h \
include/grpcpp/impl/codegen/client_context_impl.h \
include/grpcpp/impl/codegen/client_interceptor.h \
include/grpcpp/impl/codegen/client_unary_call.h \
include/grpcpp/impl/codegen/completion_queue.h \
@ -6725,6 +6730,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/serialization_traits.h \
include/grpcpp/impl/codegen/server_callback.h \
include/grpcpp/impl/codegen/server_context.h \
include/grpcpp/impl/codegen/server_context_impl.h \
include/grpcpp/impl/codegen/server_interceptor.h \
include/grpcpp/impl/codegen/server_interface.h \
include/grpcpp/impl/codegen/service_type.h \
@ -6874,6 +6880,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/channel_interface.h \
include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_context.h \
include/grpcpp/impl/codegen/client_context_impl.h \
include/grpcpp/impl/codegen/client_interceptor.h \
include/grpcpp/impl/codegen/client_unary_call.h \
include/grpcpp/impl/codegen/completion_queue.h \
@ -6895,6 +6902,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/serialization_traits.h \
include/grpcpp/impl/codegen/server_callback.h \
include/grpcpp/impl/codegen/server_context.h \
include/grpcpp/impl/codegen/server_context_impl.h \
include/grpcpp/impl/codegen/server_interceptor.h \
include/grpcpp/impl/codegen/server_interface.h \
include/grpcpp/impl/codegen/service_type.h \
@ -7239,6 +7247,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/channel_interface.h \
include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_context.h \
include/grpcpp/impl/codegen/client_context_impl.h \
include/grpcpp/impl/codegen/client_interceptor.h \
include/grpcpp/impl/codegen/client_unary_call.h \
include/grpcpp/impl/codegen/completion_queue.h \
@ -7260,6 +7269,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/serialization_traits.h \
include/grpcpp/impl/codegen/server_callback.h \
include/grpcpp/impl/codegen/server_context.h \
include/grpcpp/impl/codegen/server_context_impl.h \
include/grpcpp/impl/codegen/server_interceptor.h \
include/grpcpp/impl/codegen/server_interface.h \
include/grpcpp/impl/codegen/service_type.h \

@ -1260,6 +1260,7 @@ filegroups:
- include/grpcpp/impl/codegen/channel_interface.h
- include/grpcpp/impl/codegen/client_callback.h
- include/grpcpp/impl/codegen/client_context.h
- include/grpcpp/impl/codegen/client_context_impl.h
- include/grpcpp/impl/codegen/client_interceptor.h
- include/grpcpp/impl/codegen/client_unary_call.h
- include/grpcpp/impl/codegen/completion_queue.h
@ -1281,6 +1282,7 @@ filegroups:
- include/grpcpp/impl/codegen/serialization_traits.h
- include/grpcpp/impl/codegen/server_callback.h
- include/grpcpp/impl/codegen/server_context.h
- include/grpcpp/impl/codegen/server_context_impl.h
- include/grpcpp/impl/codegen/server_interceptor.h
- include/grpcpp/impl/codegen/server_interface.h
- include/grpcpp/impl/codegen/service_type.h

@ -39,7 +39,6 @@ some configuration as environment variables that can be set.
gRPC C core is processing requests via debug logs. Available tracers include:
- api - traces api calls to the C core
- bdp_estimator - traces behavior of bdp estimation logic
- call_combiner - traces call combiner state
- call_error - traces the possible errors contributing to final call status
- cares_resolver - traces operations of the c-ares based DNS resolver
- cares_address_sorting - traces operations of the c-ares based DNS
@ -52,9 +51,6 @@ some configuration as environment variables that can be set.
- connectivity_state - traces connectivity state changes to channels
- cronet - traces state in the cronet transport engine
- executor - traces grpc's internal thread pool ('the executor')
- fd_trace - traces fd create(), shutdown() and close() calls for channel fds.
Also traces epoll fd create()/close() calls in epollex polling engine
traces epoll-fd creation/close calls for epollex polling engine
- glb - traces the grpclb load balancer
- handshaker - traces handshaking state
- health_check_client - traces health checking client code
@ -74,6 +70,7 @@ some configuration as environment variables that can be set.
- queue_pluck
- server_channel - lightweight trace of significant server channel events
- secure_endpoint - traces bytes flowing through encrypted channels
- subchannel - traces the connectivity state of subchannel
- timer - timers (alarms) in the grpc internals
- timer_check - more detailed trace of timer logic in grpc internals
- transport_security - traces metadata about secure channel establishment
@ -85,10 +82,15 @@ some configuration as environment variables that can be set.
- alarm_refcount - refcounting traces for grpc_alarm structure
- metadata - tracks creation and mutation of metadata
- combiner - traces combiner lock state
- call_combiner - traces call combiner state
- closure - tracks closure creation, scheduling, and completion
- fd_trace - traces fd create(), shutdown() and close() calls for channel fds.
Also traces epoll fd create()/close() calls in epollex polling engine
traces epoll-fd creation/close calls for epollex polling engine
- pending_tags - traces still-in-progress tags on completion queues
- polling - traces the selected polling engine
- polling_api - traces the api calls to polling engine
- subchannel_refcount
- queue_refcount
- error_refcount
- stream_refcount

@ -161,6 +161,7 @@ Pod::Spec.new do |s|
'include/grpcpp/impl/codegen/channel_interface.h',
'include/grpcpp/impl/codegen/client_callback.h',
'include/grpcpp/impl/codegen/client_context.h',
'include/grpcpp/impl/codegen/client_context_impl.h',
'include/grpcpp/impl/codegen/client_interceptor.h',
'include/grpcpp/impl/codegen/client_unary_call.h',
'include/grpcpp/impl/codegen/completion_queue.h',
@ -182,6 +183,7 @@ Pod::Spec.new do |s|
'include/grpcpp/impl/codegen/serialization_traits.h',
'include/grpcpp/impl/codegen/server_callback.h',
'include/grpcpp/impl/codegen/server_context.h',
'include/grpcpp/impl/codegen/server_context_impl.h',
'include/grpcpp/impl/codegen/server_interceptor.h',
'include/grpcpp/impl/codegen/server_interface.h',
'include/grpcpp/impl/codegen/service_type.h',

@ -490,7 +490,7 @@ GRPCAPI grpc_server_credentials* grpc_ssl_server_credentials_create(
/** Deprecated in favor of grpc_ssl_server_credentials_create_with_options.
Same as grpc_ssl_server_credentials_create method except uses
grpc_ssl_client_certificate_request_type enum to support more ways to
authenticate client cerificates.*/
authenticate client certificates.*/
GRPCAPI grpc_server_credentials* grpc_ssl_server_credentials_create_ex(
const char* pem_root_certs, grpc_ssl_pem_key_cert_pair* pem_key_cert_pairs,
size_t num_key_cert_pairs,

@ -96,7 +96,7 @@ typedef enum {
/** Server requests client certificate and enforces that the client presents a
certificate.
The cerificate presented by the client is verified by the gRPC framework.
The certificate presented by the client is verified by the gRPC framework.
(For a successful connection the client needs to present a certificate that
can be verified against the root certificate configured by the server)

@ -48,7 +48,7 @@ typedef struct gpr_timespec {
int64_t tv_sec;
int32_t tv_nsec;
/** Against which clock was this time measured? (or GPR_TIMESPAN if
this is a relative time meaure) */
this is a relative time measure) */
gpr_clock_type clock_type;
} gpr_timespec;

@ -107,7 +107,7 @@ GPRAPI grpc_slice grpc_slice_sub_no_ref(grpc_slice s, size_t begin, size_t end);
/** Splits s into two: modifies s to be s[0:split], and returns a new slice,
sharing a refcount with s, that contains s[split:s.length].
Requires s intialized, split <= s.length */
Requires s initialized, split <= s.length */
GPRAPI grpc_slice grpc_slice_split_tail(grpc_slice* s, size_t split);
typedef enum {
@ -124,7 +124,7 @@ GPRAPI grpc_slice grpc_slice_split_tail_maybe_ref(grpc_slice* s, size_t split,
/** Splits s into two: modifies s to be s[split:s.length], and returns a new
slice, sharing a refcount with s, that contains s[0:split].
Requires s intialized, split <= s.length */
Requires s initialized, split <= s.length */
GPRAPI grpc_slice grpc_slice_split_head(grpc_slice* s, size_t split);
GPRAPI grpc_slice grpc_empty_slice(void);

@ -85,7 +85,7 @@ class Channel final : public ::grpc::ChannelInterface,
interceptor_creators);
::grpc::internal::Call CreateCall(const ::grpc::internal::RpcMethod& method,
::grpc::ClientContext* context,
::grpc_impl::ClientContext* context,
::grpc::CompletionQueue* cq) override;
void PerformOpsOnCall(::grpc::internal::CallOpSetInterface* ops,
::grpc::internal::Call* call) override;
@ -100,8 +100,9 @@ class Channel final : public ::grpc::ChannelInterface,
::grpc::CompletionQueue* CallbackCQ() override;
::grpc::internal::Call CreateCallInternal(
const ::grpc::internal::RpcMethod& method, ::grpc::ClientContext* context,
::grpc::CompletionQueue* cq, size_t interceptor_pos) override;
const ::grpc::internal::RpcMethod& method,
::grpc_impl::ClientContext* context, ::grpc::CompletionQueue* cq,
size_t interceptor_pos) override;
const grpc::string host_;
grpc_channel* const c_channel_; // owned

@ -25,12 +25,12 @@
#include <grpcpp/impl/codegen/time.h>
namespace grpc_impl {
class ClientContext;
class CompletionQueue;
}
} // namespace grpc_impl
namespace grpc {
class ChannelInterface;
class ClientContext;
template <class R>
class ClientReader;
@ -129,7 +129,7 @@ class ChannelInterface {
friend class ::grpc::internal::RpcMethod;
friend class ::grpc::internal::InterceptedChannel;
virtual internal::Call CreateCall(const internal::RpcMethod& method,
ClientContext* context,
::grpc_impl::ClientContext* context,
::grpc_impl::CompletionQueue* cq) = 0;
virtual void PerformOpsOnCall(internal::CallOpSetInterface* ops,
internal::Call* call) = 0;
@ -149,7 +149,7 @@ class ChannelInterface {
// method and adding a new pure method to an interface would be a breaking
// change (even though this is private and non-API)
virtual internal::Call CreateCallInternal(const internal::RpcMethod& method,
ClientContext* context,
::grpc_impl::ClientContext* context,
::grpc_impl::CompletionQueue* cq,
size_t interceptor_pos) {
return internal::Call();

@ -31,12 +31,11 @@
namespace grpc_impl {
class Channel;
}
class ClientContext;
} // namespace grpc_impl
namespace grpc {
class ClientContext;
namespace internal {
class RpcMethod;

@ -1,6 +1,6 @@
/*
*
* Copyright 2015 gRPC authors.
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,477 +16,15 @@
*
*/
/// A ClientContext allows the person implementing a service client to:
///
/// - Add custom metadata key-value pairs that will propagated to the server
/// side.
/// - Control call settings such as compression and authentication.
/// - Initial and trailing metadata coming from the server.
/// - Get performance metrics (ie, census).
///
/// Context settings are only relevant to the call they are invoked with, that
/// is to say, they aren't sticky. Some of these settings, such as the
/// compression options, can be made persistent at channel construction time
/// (see \a grpc::CreateCustomChannel).
///
/// \warning ClientContext instances should \em not be reused across rpcs.
#ifndef GRPCPP_IMPL_CODEGEN_CLIENT_CONTEXT_H
#define GRPCPP_IMPL_CODEGEN_CLIENT_CONTEXT_H
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <grpc/impl/codegen/compression_types.h>
#include <grpc/impl/codegen/propagation_bits.h>
#include <grpcpp/impl/codegen/client_interceptor.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/create_auth_context.h>
#include <grpcpp/impl/codegen/metadata_map.h>
#include <grpcpp/impl/codegen/rpc_method.h>
#include <grpcpp/impl/codegen/security/auth_context.h>
#include <grpcpp/impl/codegen/slice.h>
#include <grpcpp/impl/codegen/status.h>
#include <grpcpp/impl/codegen/string_ref.h>
#include <grpcpp/impl/codegen/sync.h>
#include <grpcpp/impl/codegen/time.h>
struct census_context;
struct grpc_call;
namespace grpc_impl {
#include <grpcpp/impl/codegen/client_context_impl.h>
class CallCredentials;
class Channel;
class CompletionQueue;
} // namespace grpc_impl
namespace grpc {
class ChannelInterface;
class ClientContext;
namespace internal {
class RpcMethod;
class CallOpClientRecvStatus;
class CallOpRecvInitialMetadata;
template <class InputMessage, class OutputMessage>
class BlockingUnaryCallImpl;
template <class InputMessage, class OutputMessage>
class CallbackUnaryCallImpl;
template <class Request, class Response>
class ClientCallbackReaderWriterImpl;
template <class Response>
class ClientCallbackReaderImpl;
template <class Request>
class ClientCallbackWriterImpl;
class ClientCallbackUnaryImpl;
} // namespace internal
template <class R>
class ClientReader;
template <class W>
class ClientWriter;
template <class W, class R>
class ClientReaderWriter;
template <class R>
class ClientAsyncReader;
template <class W>
class ClientAsyncWriter;
template <class W, class R>
class ClientAsyncReaderWriter;
template <class R>
class ClientAsyncResponseReader;
class ServerContext;
/// Options for \a ClientContext::FromServerContext specifying which traits from
/// the \a ServerContext to propagate (copy) from it into a new \a
/// ClientContext.
///
/// \see ClientContext::FromServerContext
class PropagationOptions {
public:
PropagationOptions() : propagate_(GRPC_PROPAGATE_DEFAULTS) {}
PropagationOptions& enable_deadline_propagation() {
propagate_ |= GRPC_PROPAGATE_DEADLINE;
return *this;
}
PropagationOptions& disable_deadline_propagation() {
propagate_ &= ~GRPC_PROPAGATE_DEADLINE;
return *this;
}
PropagationOptions& enable_census_stats_propagation() {
propagate_ |= GRPC_PROPAGATE_CENSUS_STATS_CONTEXT;
return *this;
}
PropagationOptions& disable_census_stats_propagation() {
propagate_ &= ~GRPC_PROPAGATE_CENSUS_STATS_CONTEXT;
return *this;
}
PropagationOptions& enable_census_tracing_propagation() {
propagate_ |= GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT;
return *this;
}
PropagationOptions& disable_census_tracing_propagation() {
propagate_ &= ~GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT;
return *this;
}
PropagationOptions& enable_cancellation_propagation() {
propagate_ |= GRPC_PROPAGATE_CANCELLATION;
return *this;
}
PropagationOptions& disable_cancellation_propagation() {
propagate_ &= ~GRPC_PROPAGATE_CANCELLATION;
return *this;
}
uint32_t c_bitmask() const { return propagate_; }
private:
uint32_t propagate_;
};
namespace testing {
class InteropClientContextInspector;
} // namespace testing
/// A ClientContext allows the person implementing a service client to:
///
/// - Add custom metadata key-value pairs that will propagated to the server
/// side.
/// - Control call settings such as compression and authentication.
/// - Initial and trailing metadata coming from the server.
/// - Get performance metrics (ie, census).
///
/// Context settings are only relevant to the call they are invoked with, that
/// is to say, they aren't sticky. Some of these settings, such as the
/// compression options, can be made persistent at channel construction time
/// (see \a grpc::CreateCustomChannel).
///
/// \warning ClientContext instances should \em not be reused across rpcs.
/// \warning The ClientContext instance used for creating an rpc must remain
/// alive and valid for the lifetime of the rpc.
class ClientContext {
public:
ClientContext();
~ClientContext();
/// Create a new \a ClientContext as a child of an incoming server call,
/// according to \a options (\see PropagationOptions).
///
/// \param server_context The source server context to use as the basis for
/// constructing the client context.
/// \param options The options controlling what to copy from the \a
/// server_context.
///
/// \return A newly constructed \a ClientContext instance based on \a
/// server_context, with traits propagated (copied) according to \a options.
static std::unique_ptr<ClientContext> FromServerContext(
const ServerContext& server_context,
PropagationOptions options = PropagationOptions());
/// Add the (\a meta_key, \a meta_value) pair to the metadata associated with
/// a client call. These are made available at the server side by the \a
/// grpc::ServerContext::client_metadata() method.
///
/// \warning This method should only be called before invoking the rpc.
///
/// \param meta_key The metadata key. If \a meta_value is binary data, it must
/// end in "-bin".
/// \param meta_value The metadata value. If its value is binary, the key name
/// must end in "-bin".
///
/// Metadata must conform to the following format:
/// Custom-Metadata -> Binary-Header / ASCII-Header
/// Binary-Header -> {Header-Name "-bin" } {binary value}
/// ASCII-Header -> Header-Name ASCII-Value
/// Header-Name -> 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - .
/// ASCII-Value -> 1*( %x20-%x7E ) ; space and printable ASCII
void AddMetadata(const grpc::string& meta_key,
const grpc::string& meta_value);
/// Return a collection of initial metadata key-value pairs. Note that keys
/// may happen more than once (ie, a \a std::multimap is returned).
///
/// \warning This method should only be called after initial metadata has been
/// received. For streaming calls, see \a
/// ClientReaderInterface::WaitForInitialMetadata().
///
/// \return A multimap of initial metadata key-value pairs from the server.
const std::multimap<grpc::string_ref, grpc::string_ref>&
GetServerInitialMetadata() const {
GPR_CODEGEN_ASSERT(initial_metadata_received_);
return *recv_initial_metadata_.map();
}
/// Return a collection of trailing metadata key-value pairs. Note that keys
/// may happen more than once (ie, a \a std::multimap is returned).
///
/// \warning This method is only callable once the stream has finished.
///
/// \return A multimap of metadata trailing key-value pairs from the server.
const std::multimap<grpc::string_ref, grpc::string_ref>&
GetServerTrailingMetadata() const {
// TODO(yangg) check finished
return *trailing_metadata_.map();
}
/// Set the deadline for the client call.
///
/// \warning This method should only be called before invoking the rpc.
///
/// \param deadline the deadline for the client call. Units are determined by
/// the type used. The deadline is an absolute (not relative) time.
template <typename T>
void set_deadline(const T& deadline) {
TimePoint<T> deadline_tp(deadline);
deadline_ = deadline_tp.raw_time();
}
/// EXPERIMENTAL: Indicate that this request is idempotent.
/// By default, RPCs are assumed to <i>not</i> be idempotent.
///
/// If true, the gRPC library assumes that it's safe to initiate
/// this RPC multiple times.
void set_idempotent(bool idempotent) { idempotent_ = idempotent; }
/// EXPERIMENTAL: Set this request to be cacheable.
/// If set, grpc is free to use the HTTP GET verb for sending the request,
/// with the possibility of receiving a cached response.
void set_cacheable(bool cacheable) { cacheable_ = cacheable; }
/// EXPERIMENTAL: Trigger wait-for-ready or not on this request.
/// See https://github.com/grpc/grpc/blob/master/doc/wait-for-ready.md.
/// If set, if an RPC is made when a channel's connectivity state is
/// TRANSIENT_FAILURE or CONNECTING, the call will not "fail fast",
/// and the channel will wait until the channel is READY before making the
/// call.
void set_wait_for_ready(bool wait_for_ready) {
wait_for_ready_ = wait_for_ready;
wait_for_ready_explicitly_set_ = true;
}
/// DEPRECATED: Use set_wait_for_ready() instead.
void set_fail_fast(bool fail_fast) { set_wait_for_ready(!fail_fast); }
/// Return the deadline for the client call.
std::chrono::system_clock::time_point deadline() const {
return Timespec2Timepoint(deadline_);
}
/// Return a \a gpr_timespec representation of the client call's deadline.
gpr_timespec raw_deadline() const { return deadline_; }
/// Set the per call authority header (see
/// https://tools.ietf.org/html/rfc7540#section-8.1.2.3).
void set_authority(const grpc::string& authority) { authority_ = authority; }
/// Return the authentication context for this client call.
///
/// \see grpc::AuthContext.
std::shared_ptr<const AuthContext> auth_context() const {
if (auth_context_.get() == nullptr) {
auth_context_ = CreateAuthContext(call_);
}
return auth_context_;
}
/// Set credentials for the client call.
///
/// A credentials object encapsulates all the state needed by a client to
/// authenticate with a server and make various assertions, e.g., about the
/// client’s identity, role, or whether it is authorized to make a particular
/// call.
///
/// \see https://grpc.io/docs/guides/auth.html
void set_credentials(
const std::shared_ptr<grpc_impl::CallCredentials>& creds) {
creds_ = creds;
}
/// Return the compression algorithm the client call will request be used.
/// Note that the gRPC runtime may decide to ignore this request, for example,
/// due to resource constraints.
grpc_compression_algorithm compression_algorithm() const {
return compression_algorithm_;
}
/// Set \a algorithm to be the compression algorithm used for the client call.
///
/// \param algorithm The compression algorithm used for the client call.
void set_compression_algorithm(grpc_compression_algorithm algorithm);
/// Flag whether the initial metadata should be \a corked
///
/// If \a corked is true, then the initial metadata will be coalesced with the
/// write of first message in the stream. As a result, any tag set for the
/// initial metadata operation (starting a client-streaming or bidi-streaming
/// RPC) will not actually be sent to the completion queue or delivered
/// via Next.
///
/// \param corked The flag indicating whether the initial metadata is to be
/// corked or not.
void set_initial_metadata_corked(bool corked) {
initial_metadata_corked_ = corked;
}
/// Return the peer uri in a string.
///
/// \warning This value is never authenticated or subject to any security
/// related code. It must not be used for any authentication related
/// functionality. Instead, use auth_context.
///
/// \return The call's peer URI.
grpc::string peer() const;
/// Get and set census context.
void set_census_context(struct census_context* ccp) { census_context_ = ccp; }
struct census_context* census_context() const {
return census_context_;
}
/// Send a best-effort out-of-band cancel on the call associated with
/// this client context. The call could be in any stage; e.g., if it is
/// already finished, it may still return success.
///
/// There is no guarantee the call will be cancelled.
///
/// Note that TryCancel() does not change any of the tags that are pending
/// on the completion queue. All pending tags will still be delivered
/// (though their ok result may reflect the effect of cancellation).
void TryCancel();
/// Global Callbacks
///
/// Can be set exactly once per application to install hooks whenever
/// a client context is constructed and destructed.
class GlobalCallbacks {
public:
virtual ~GlobalCallbacks() {}
virtual void DefaultConstructor(ClientContext* context) = 0;
virtual void Destructor(ClientContext* context) = 0;
};
static void SetGlobalCallbacks(GlobalCallbacks* callbacks);
/// Should be used for framework-level extensions only.
/// Applications never need to call this method.
grpc_call* c_call() { return call_; }
/// EXPERIMENTAL debugging API
///
/// if status is not ok() for an RPC, this will return a detailed string
/// of the gRPC Core error that led to the failure. It should not be relied
/// upon for anything other than gaining more debug data in failure cases.
grpc::string debug_error_string() const { return debug_error_string_; }
private:
// Disallow copy and assign.
ClientContext(const ClientContext&);
ClientContext& operator=(const ClientContext&);
friend class ::grpc::testing::InteropClientContextInspector;
friend class ::grpc::internal::CallOpClientRecvStatus;
friend class ::grpc::internal::CallOpRecvInitialMetadata;
friend class ::grpc_impl::Channel;
template <class R>
friend class ::grpc::ClientReader;
template <class W>
friend class ::grpc::ClientWriter;
template <class W, class R>
friend class ::grpc::ClientReaderWriter;
template <class R>
friend class ::grpc::ClientAsyncReader;
template <class W>
friend class ::grpc::ClientAsyncWriter;
template <class W, class R>
friend class ::grpc::ClientAsyncReaderWriter;
template <class R>
friend class ::grpc::ClientAsyncResponseReader;
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::BlockingUnaryCallImpl;
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::CallbackUnaryCallImpl;
template <class Request, class Response>
friend class ::grpc::internal::ClientCallbackReaderWriterImpl;
template <class Response>
friend class ::grpc::internal::ClientCallbackReaderImpl;
template <class Request>
friend class ::grpc::internal::ClientCallbackWriterImpl;
friend class ::grpc::internal::ClientCallbackUnaryImpl;
// Used by friend class CallOpClientRecvStatus
void set_debug_error_string(const grpc::string& debug_error_string) {
debug_error_string_ = debug_error_string;
}
grpc_call* call() const { return call_; }
void set_call(grpc_call* call,
const std::shared_ptr<::grpc_impl::Channel>& channel);
experimental::ClientRpcInfo* set_client_rpc_info(
const char* method, internal::RpcMethod::RpcType type,
grpc::ChannelInterface* channel,
const std::vector<
std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>&
creators,
size_t interceptor_pos) {
rpc_info_ = experimental::ClientRpcInfo(this, type, method, channel);
rpc_info_.RegisterInterceptors(creators, interceptor_pos);
return &rpc_info_;
}
uint32_t initial_metadata_flags() const {
return (idempotent_ ? GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST : 0) |
(wait_for_ready_ ? GRPC_INITIAL_METADATA_WAIT_FOR_READY : 0) |
(cacheable_ ? GRPC_INITIAL_METADATA_CACHEABLE_REQUEST : 0) |
(wait_for_ready_explicitly_set_
? GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET
: 0) |
(initial_metadata_corked_ ? GRPC_INITIAL_METADATA_CORKED : 0);
}
grpc::string authority() { return authority_; }
void SendCancelToInterceptors();
bool initial_metadata_received_;
bool wait_for_ready_;
bool wait_for_ready_explicitly_set_;
bool idempotent_;
bool cacheable_;
std::shared_ptr<::grpc_impl::Channel> channel_;
grpc::internal::Mutex mu_;
grpc_call* call_;
bool call_canceled_;
gpr_timespec deadline_;
grpc::string authority_;
std::shared_ptr<grpc_impl::CallCredentials> creds_;
mutable std::shared_ptr<const AuthContext> auth_context_;
struct census_context* census_context_;
std::multimap<grpc::string, grpc::string> send_initial_metadata_;
mutable internal::MetadataMap recv_initial_metadata_;
mutable internal::MetadataMap trailing_metadata_;
grpc_call* propagate_from_call_;
PropagationOptions propagation_options_;
grpc_compression_algorithm compression_algorithm_;
bool initial_metadata_corked_;
grpc::string debug_error_string_;
experimental::ClientRpcInfo rpc_info_;
};
typedef ::grpc_impl::ClientContext ClientContext;
typedef ::grpc_impl::PropagationOptions PropagationOptions;
} // namespace grpc

@ -0,0 +1,491 @@
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/// A ClientContext allows the person implementing a service client to:
///
/// - Add custom metadata key-value pairs that will propagated to the server
/// side.
/// - Control call settings such as compression and authentication.
/// - Initial and trailing metadata coming from the server.
/// - Get performance metrics (ie, census).
///
/// Context settings are only relevant to the call they are invoked with, that
/// is to say, they aren't sticky. Some of these settings, such as the
/// compression options, can be made persistent at channel construction time
/// (see \a grpc::CreateCustomChannel).
///
/// \warning ClientContext instances should \em not be reused across rpcs.
#ifndef GRPCPP_IMPL_CODEGEN_CLIENT_CONTEXT_IMPL_H
#define GRPCPP_IMPL_CODEGEN_CLIENT_CONTEXT_IMPL_H
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <grpc/impl/codegen/compression_types.h>
#include <grpc/impl/codegen/propagation_bits.h>
#include <grpcpp/impl/codegen/client_interceptor.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/create_auth_context.h>
#include <grpcpp/impl/codegen/metadata_map.h>
#include <grpcpp/impl/codegen/rpc_method.h>
#include <grpcpp/impl/codegen/security/auth_context.h>
#include <grpcpp/impl/codegen/slice.h>
#include <grpcpp/impl/codegen/status.h>
#include <grpcpp/impl/codegen/string_ref.h>
#include <grpcpp/impl/codegen/sync.h>
#include <grpcpp/impl/codegen/time.h>
struct census_context;
struct grpc_call;
namespace grpc {
class ChannelInterface;
namespace internal {
class RpcMethod;
class CallOpClientRecvStatus;
class CallOpRecvInitialMetadata;
template <class InputMessage, class OutputMessage>
class BlockingUnaryCallImpl;
template <class InputMessage, class OutputMessage>
class CallbackUnaryCallImpl;
template <class Request, class Response>
class ClientCallbackReaderWriterImpl;
template <class Response>
class ClientCallbackReaderImpl;
template <class Request>
class ClientCallbackWriterImpl;
class ClientCallbackUnaryImpl;
} // namespace internal
template <class R>
class ClientReader;
template <class W>
class ClientWriter;
template <class W, class R>
class ClientReaderWriter;
template <class R>
class ClientAsyncReader;
template <class W>
class ClientAsyncWriter;
template <class W, class R>
class ClientAsyncReaderWriter;
template <class R>
class ClientAsyncResponseReader;
namespace testing {
class InteropClientContextInspector;
} // namespace testing
} // namespace grpc
namespace grpc_impl {
class CallCredentials;
class Channel;
class CompletionQueue;
class ServerContext;
/// Options for \a ClientContext::FromServerContext specifying which traits from
/// the \a ServerContext to propagate (copy) from it into a new \a
/// ClientContext.
///
/// \see ClientContext::FromServerContext
class PropagationOptions {
public:
PropagationOptions() : propagate_(GRPC_PROPAGATE_DEFAULTS) {}
PropagationOptions& enable_deadline_propagation() {
propagate_ |= GRPC_PROPAGATE_DEADLINE;
return *this;
}
PropagationOptions& disable_deadline_propagation() {
propagate_ &= ~GRPC_PROPAGATE_DEADLINE;
return *this;
}
PropagationOptions& enable_census_stats_propagation() {
propagate_ |= GRPC_PROPAGATE_CENSUS_STATS_CONTEXT;
return *this;
}
PropagationOptions& disable_census_stats_propagation() {
propagate_ &= ~GRPC_PROPAGATE_CENSUS_STATS_CONTEXT;
return *this;
}
PropagationOptions& enable_census_tracing_propagation() {
propagate_ |= GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT;
return *this;
}
PropagationOptions& disable_census_tracing_propagation() {
propagate_ &= ~GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT;
return *this;
}
PropagationOptions& enable_cancellation_propagation() {
propagate_ |= GRPC_PROPAGATE_CANCELLATION;
return *this;
}
PropagationOptions& disable_cancellation_propagation() {
propagate_ &= ~GRPC_PROPAGATE_CANCELLATION;
return *this;
}
uint32_t c_bitmask() const { return propagate_; }
private:
uint32_t propagate_;
};
/// A ClientContext allows the person implementing a service client to:
///
/// - Add custom metadata key-value pairs that will propagated to the server
/// side.
/// - Control call settings such as compression and authentication.
/// - Initial and trailing metadata coming from the server.
/// - Get performance metrics (ie, census).
///
/// Context settings are only relevant to the call they are invoked with, that
/// is to say, they aren't sticky. Some of these settings, such as the
/// compression options, can be made persistent at channel construction time
/// (see \a grpc::CreateCustomChannel).
///
/// \warning ClientContext instances should \em not be reused across rpcs.
/// \warning The ClientContext instance used for creating an rpc must remain
/// alive and valid for the lifetime of the rpc.
class ClientContext {
public:
ClientContext();
~ClientContext();
/// Create a new \a ClientContext as a child of an incoming server call,
/// according to \a options (\see PropagationOptions).
///
/// \param server_context The source server context to use as the basis for
/// constructing the client context.
/// \param options The options controlling what to copy from the \a
/// server_context.
///
/// \return A newly constructed \a ClientContext instance based on \a
/// server_context, with traits propagated (copied) according to \a options.
static std::unique_ptr<ClientContext> FromServerContext(
const grpc_impl::ServerContext& server_context,
PropagationOptions options = PropagationOptions());
/// Add the (\a meta_key, \a meta_value) pair to the metadata associated with
/// a client call. These are made available at the server side by the \a
/// grpc::ServerContext::client_metadata() method.
///
/// \warning This method should only be called before invoking the rpc.
///
/// \param meta_key The metadata key. If \a meta_value is binary data, it must
/// end in "-bin".
/// \param meta_value The metadata value. If its value is binary, the key name
/// must end in "-bin".
///
/// Metadata must conform to the following format:
/// Custom-Metadata -> Binary-Header / ASCII-Header
/// Binary-Header -> {Header-Name "-bin" } {binary value}
/// ASCII-Header -> Header-Name ASCII-Value
/// Header-Name -> 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - .
/// ASCII-Value -> 1*( %x20-%x7E ) ; space and printable ASCII
void AddMetadata(const grpc::string& meta_key,
const grpc::string& meta_value);
/// Return a collection of initial metadata key-value pairs. Note that keys
/// may happen more than once (ie, a \a std::multimap is returned).
///
/// \warning This method should only be called after initial metadata has been
/// received. For streaming calls, see \a
/// ClientReaderInterface::WaitForInitialMetadata().
///
/// \return A multimap of initial metadata key-value pairs from the server.
const std::multimap<grpc::string_ref, grpc::string_ref>&
GetServerInitialMetadata() const {
GPR_CODEGEN_ASSERT(initial_metadata_received_);
return *recv_initial_metadata_.map();
}
/// Return a collection of trailing metadata key-value pairs. Note that keys
/// may happen more than once (ie, a \a std::multimap is returned).
///
/// \warning This method is only callable once the stream has finished.
///
/// \return A multimap of metadata trailing key-value pairs from the server.
const std::multimap<grpc::string_ref, grpc::string_ref>&
GetServerTrailingMetadata() const {
// TODO(yangg) check finished
return *trailing_metadata_.map();
}
/// Set the deadline for the client call.
///
/// \warning This method should only be called before invoking the rpc.
///
/// \param deadline the deadline for the client call. Units are determined by
/// the type used. The deadline is an absolute (not relative) time.
template <typename T>
void set_deadline(const T& deadline) {
grpc::TimePoint<T> deadline_tp(deadline);
deadline_ = deadline_tp.raw_time();
}
/// EXPERIMENTAL: Indicate that this request is idempotent.
/// By default, RPCs are assumed to <i>not</i> be idempotent.
///
/// If true, the gRPC library assumes that it's safe to initiate
/// this RPC multiple times.
void set_idempotent(bool idempotent) { idempotent_ = idempotent; }
/// EXPERIMENTAL: Set this request to be cacheable.
/// If set, grpc is free to use the HTTP GET verb for sending the request,
/// with the possibility of receiving a cached response.
void set_cacheable(bool cacheable) { cacheable_ = cacheable; }
/// EXPERIMENTAL: Trigger wait-for-ready or not on this request.
/// See https://github.com/grpc/grpc/blob/master/doc/wait-for-ready.md.
/// If set, if an RPC is made when a channel's connectivity state is
/// TRANSIENT_FAILURE or CONNECTING, the call will not "fail fast",
/// and the channel will wait until the channel is READY before making the
/// call.
void set_wait_for_ready(bool wait_for_ready) {
wait_for_ready_ = wait_for_ready;
wait_for_ready_explicitly_set_ = true;
}
/// DEPRECATED: Use set_wait_for_ready() instead.
void set_fail_fast(bool fail_fast) { set_wait_for_ready(!fail_fast); }
/// Return the deadline for the client call.
std::chrono::system_clock::time_point deadline() const {
return grpc::Timespec2Timepoint(deadline_);
}
/// Return a \a gpr_timespec representation of the client call's deadline.
gpr_timespec raw_deadline() const { return deadline_; }
/// Set the per call authority header (see
/// https://tools.ietf.org/html/rfc7540#section-8.1.2.3).
void set_authority(const grpc::string& authority) { authority_ = authority; }
/// Return the authentication context for this client call.
///
/// \see grpc::AuthContext.
std::shared_ptr<const grpc::AuthContext> auth_context() const {
if (auth_context_.get() == nullptr) {
auth_context_ = grpc::CreateAuthContext(call_);
}
return auth_context_;
}
/// Set credentials for the client call.
///
/// A credentials object encapsulates all the state needed by a client to
/// authenticate with a server and make various assertions, e.g., about the
/// client’s identity, role, or whether it is authorized to make a particular
/// call.
///
/// \see https://grpc.io/docs/guides/auth.html
void set_credentials(
const std::shared_ptr<grpc_impl::CallCredentials>& creds) {
creds_ = creds;
}
/// Return the compression algorithm the client call will request be used.
/// Note that the gRPC runtime may decide to ignore this request, for example,
/// due to resource constraints.
grpc_compression_algorithm compression_algorithm() const {
return compression_algorithm_;
}
/// Set \a algorithm to be the compression algorithm used for the client call.
///
/// \param algorithm The compression algorithm used for the client call.
void set_compression_algorithm(grpc_compression_algorithm algorithm);
/// Flag whether the initial metadata should be \a corked
///
/// If \a corked is true, then the initial metadata will be coalesced with the
/// write of first message in the stream. As a result, any tag set for the
/// initial metadata operation (starting a client-streaming or bidi-streaming
/// RPC) will not actually be sent to the completion queue or delivered
/// via Next.
///
/// \param corked The flag indicating whether the initial metadata is to be
/// corked or not.
void set_initial_metadata_corked(bool corked) {
initial_metadata_corked_ = corked;
}
/// Return the peer uri in a string.
///
/// \warning This value is never authenticated or subject to any security
/// related code. It must not be used for any authentication related
/// functionality. Instead, use auth_context.
///
/// \return The call's peer URI.
grpc::string peer() const;
/// Get and set census context.
void set_census_context(struct census_context* ccp) { census_context_ = ccp; }
struct census_context* census_context() const {
return census_context_;
}
/// Send a best-effort out-of-band cancel on the call associated with
/// this client context. The call could be in any stage; e.g., if it is
/// already finished, it may still return success.
///
/// There is no guarantee the call will be cancelled.
///
/// Note that TryCancel() does not change any of the tags that are pending
/// on the completion queue. All pending tags will still be delivered
/// (though their ok result may reflect the effect of cancellation).
void TryCancel();
/// Global Callbacks
///
/// Can be set exactly once per application to install hooks whenever
/// a client context is constructed and destructed.
class GlobalCallbacks {
public:
virtual ~GlobalCallbacks() {}
virtual void DefaultConstructor(ClientContext* context) = 0;
virtual void Destructor(ClientContext* context) = 0;
};
static void SetGlobalCallbacks(GlobalCallbacks* callbacks);
/// Should be used for framework-level extensions only.
/// Applications never need to call this method.
grpc_call* c_call() { return call_; }
/// EXPERIMENTAL debugging API
///
/// if status is not ok() for an RPC, this will return a detailed string
/// of the gRPC Core error that led to the failure. It should not be relied
/// upon for anything other than gaining more debug data in failure cases.
grpc::string debug_error_string() const { return debug_error_string_; }
private:
// Disallow copy and assign.
ClientContext(const ClientContext&);
ClientContext& operator=(const ClientContext&);
friend class ::grpc::testing::InteropClientContextInspector;
friend class ::grpc::internal::CallOpClientRecvStatus;
friend class ::grpc::internal::CallOpRecvInitialMetadata;
friend class ::grpc_impl::Channel;
template <class R>
friend class ::grpc::ClientReader;
template <class W>
friend class ::grpc::ClientWriter;
template <class W, class R>
friend class ::grpc::ClientReaderWriter;
template <class R>
friend class ::grpc::ClientAsyncReader;
template <class W>
friend class ::grpc::ClientAsyncWriter;
template <class W, class R>
friend class ::grpc::ClientAsyncReaderWriter;
template <class R>
friend class ::grpc::ClientAsyncResponseReader;
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::BlockingUnaryCallImpl;
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::CallbackUnaryCallImpl;
template <class Request, class Response>
friend class ::grpc::internal::ClientCallbackReaderWriterImpl;
template <class Response>
friend class ::grpc::internal::ClientCallbackReaderImpl;
template <class Request>
friend class ::grpc::internal::ClientCallbackWriterImpl;
friend class ::grpc::internal::ClientCallbackUnaryImpl;
// Used by friend class CallOpClientRecvStatus
void set_debug_error_string(const grpc::string& debug_error_string) {
debug_error_string_ = debug_error_string;
}
grpc_call* call() const { return call_; }
void set_call(grpc_call* call,
const std::shared_ptr<::grpc_impl::Channel>& channel);
grpc::experimental::ClientRpcInfo* set_client_rpc_info(
const char* method, grpc::internal::RpcMethod::RpcType type,
grpc::ChannelInterface* channel,
const std::vector<std::unique_ptr<
grpc::experimental::ClientInterceptorFactoryInterface>>& creators,
size_t interceptor_pos) {
rpc_info_ = grpc::experimental::ClientRpcInfo(this, type, method, channel);
rpc_info_.RegisterInterceptors(creators, interceptor_pos);
return &rpc_info_;
}
uint32_t initial_metadata_flags() const {
return (idempotent_ ? GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST : 0) |
(wait_for_ready_ ? GRPC_INITIAL_METADATA_WAIT_FOR_READY : 0) |
(cacheable_ ? GRPC_INITIAL_METADATA_CACHEABLE_REQUEST : 0) |
(wait_for_ready_explicitly_set_
? GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET
: 0) |
(initial_metadata_corked_ ? GRPC_INITIAL_METADATA_CORKED : 0);
}
grpc::string authority() { return authority_; }
void SendCancelToInterceptors();
bool initial_metadata_received_;
bool wait_for_ready_;
bool wait_for_ready_explicitly_set_;
bool idempotent_;
bool cacheable_;
std::shared_ptr<::grpc_impl::Channel> channel_;
grpc::internal::Mutex mu_;
grpc_call* call_;
bool call_canceled_;
gpr_timespec deadline_;
grpc::string authority_;
std::shared_ptr<grpc_impl::CallCredentials> creds_;
mutable std::shared_ptr<const grpc::AuthContext> auth_context_;
struct census_context* census_context_;
std::multimap<grpc::string, grpc::string> send_initial_metadata_;
mutable grpc::internal::MetadataMap recv_initial_metadata_;
mutable grpc::internal::MetadataMap trailing_metadata_;
grpc_call* propagate_from_call_;
PropagationOptions propagation_options_;
grpc_compression_algorithm compression_algorithm_;
bool initial_metadata_corked_;
grpc::string debug_error_string_;
grpc::experimental::ClientRpcInfo rpc_info_;
};
} // namespace grpc_impl
#endif // GRPCPP_IMPL_CODEGEN_CLIENT_CONTEXT_IMPL_H

@ -29,12 +29,11 @@
namespace grpc_impl {
class Channel;
}
class ClientContext;
} // namespace grpc_impl
namespace grpc {
class ClientContext;
namespace internal {
class InterceptorBatchMethodsImpl;
}
@ -96,7 +95,7 @@ class ClientRpcInfo {
/// Return a pointer to the underlying ClientContext structure associated
/// with the RPC to support features that apply to it
grpc::ClientContext* client_context() { return ctx_; }
grpc_impl::ClientContext* client_context() { return ctx_; }
/// Return the type of the RPC (unary or a streaming flavor)
Type type() const { return type_; }
@ -119,8 +118,9 @@ class ClientRpcInfo {
ClientRpcInfo() = default;
// Constructor will only be called from ClientContext
ClientRpcInfo(grpc::ClientContext* ctx, internal::RpcMethod::RpcType type,
const char* method, grpc::ChannelInterface* channel)
ClientRpcInfo(grpc_impl::ClientContext* ctx,
internal::RpcMethod::RpcType type, const char* method,
grpc::ChannelInterface* channel)
: ctx_(ctx),
type_(static_cast<Type>(type)),
method_(method),
@ -160,7 +160,7 @@ class ClientRpcInfo {
}
}
grpc::ClientContext* ctx_ = nullptr;
grpc_impl::ClientContext* ctx_ = nullptr;
// TODO(yashykt): make type_ const once move-assignment is deleted
Type type_{Type::UNKNOWN};
const char* method_ = nullptr;
@ -170,7 +170,7 @@ class ClientRpcInfo {
size_t hijacked_interceptor_ = 0;
friend class internal::InterceptorBatchMethodsImpl;
friend class grpc::ClientContext;
friend class grpc_impl::ClientContext;
};
// PLEASE DO NOT USE THIS. ALWAYS PREFER PER CHANNEL INTERCEPTORS OVER A GLOBAL

@ -25,17 +25,19 @@
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/status.h>
namespace grpc {
namespace grpc_impl {
class ClientContext;
} // namespace grpc_impl
namespace grpc {
namespace internal {
class RpcMethod;
/// Wrapper that performs a blocking unary call
template <class InputMessage, class OutputMessage>
Status BlockingUnaryCall(ChannelInterface* channel, const RpcMethod& method,
ClientContext* context, const InputMessage& request,
OutputMessage* result) {
grpc_impl::ClientContext* context,
const InputMessage& request, OutputMessage* result) {
return BlockingUnaryCallImpl<InputMessage, OutputMessage>(
channel, method, context, request, result)
.status();
@ -45,8 +47,8 @@ template <class InputMessage, class OutputMessage>
class BlockingUnaryCallImpl {
public:
BlockingUnaryCallImpl(ChannelInterface* channel, const RpcMethod& method,
ClientContext* context, const InputMessage& request,
OutputMessage* result) {
grpc_impl::ClientContext* context,
const InputMessage& request, OutputMessage* result) {
CompletionQueue cq(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_DEFAULT_POLLING,
nullptr}); // Pluckable completion queue

@ -46,6 +46,7 @@ namespace grpc_impl {
class Channel;
class Server;
class ServerBuilder;
class ServerContext;
} // namespace grpc_impl
namespace grpc {
@ -65,8 +66,6 @@ class ServerReaderWriterBody;
} // namespace internal
class ChannelInterface;
class ClientContext;
class ServerContext;
class ServerInterface;
namespace internal {
@ -278,7 +277,7 @@ class CompletionQueue : private ::grpc::GrpcLibraryCodegen {
template <::grpc::StatusCode code>
friend class ::grpc::internal::ErrorMethodHandler;
friend class ::grpc_impl::Server;
friend class ::grpc::ServerContext;
friend class ::grpc_impl::ServerContext;
friend class ::grpc::ServerInterface;
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::BlockingUnaryCallImpl;

@ -174,20 +174,22 @@ class InterceptorBatchMethods {
/// Returns a pointer to the modifiable received message. Note that the
/// message is already deserialized but the type is not set; the interceptor
/// should static_cast to the appropriate type before using it. This is valid
/// for POST_RECV_MESSAGE interceptions; nullptr for not valid
/// for PRE_RECV_MESSAGE and POST_RECV_MESSAGE interceptions; nullptr for not
/// valid
virtual void* GetRecvMessage() = 0;
/// Returns a modifiable multimap of the received initial metadata.
/// Valid for POST_RECV_INITIAL_METADATA interceptions; nullptr if not valid
/// Valid for PRE_RECV_INITIAL_METADATA and POST_RECV_INITIAL_METADATA
/// interceptions; nullptr if not valid
virtual std::multimap<grpc::string_ref, grpc::string_ref>*
GetRecvInitialMetadata() = 0;
/// Returns a modifiable view of the received status on POST_RECV_STATUS
/// interceptions; nullptr if not valid.
/// Returns a modifiable view of the received status on PRE_RECV_STATUS and
/// POST_RECV_STATUS interceptions; nullptr if not valid.
virtual Status* GetRecvStatus() = 0;
/// Returns a modifiable multimap of the received trailing metadata on
/// POST_RECV_STATUS interceptions; nullptr if not valid
/// PRE_RECV_STATUS and POST_RECV_STATUS interceptions; nullptr if not valid
virtual std::multimap<grpc::string_ref, grpc::string_ref>*
GetRecvTrailingMetadata() = 0;

@ -31,9 +31,11 @@
#include <grpcpp/impl/codegen/rpc_method.h>
#include <grpcpp/impl/codegen/status.h>
namespace grpc {
namespace grpc_impl {
class ServerContext;
}
namespace grpc {
namespace internal {
/// Base class for running an RPC handler.
class MethodHandler {
@ -50,7 +52,7 @@ class MethodHandler {
/// \param requester : used only by the callback API. It is a function
/// called by the RPC Controller to request another RPC (and also
/// to set up the state required to make that request possible)
HandlerParameter(Call* c, ServerContext* context, void* req,
HandlerParameter(Call* c, ::grpc_impl::ServerContext* context, void* req,
Status req_status, void* handler_data,
std::function<void()> requester)
: call(c),
@ -61,7 +63,7 @@ class MethodHandler {
call_requester(std::move(requester)) {}
~HandlerParameter() {}
Call* call;
ServerContext* server_context;
::grpc_impl::ServerContext* server_context;
void* request;
Status status;
void* internal_data;

@ -29,7 +29,7 @@
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/message_allocator.h>
#include <grpcpp/impl/codegen/server_context.h>
#include <grpcpp/impl/codegen/server_context_impl.h>
#include <grpcpp/impl/codegen/server_interface.h>
#include <grpcpp/impl/codegen/status.h>
@ -53,7 +53,7 @@ class ServerReactor {
virtual void OnCancel() = 0;
private:
friend class ::grpc::ServerContext;
friend class ::grpc_impl::ServerContext;
template <class Request, class Response>
friend class CallbackClientStreamingHandler;
template <class Request, class Response>
@ -313,7 +313,7 @@ class ServerBidiReactor : public internal::ServerReactor {
/// is a result of the client calling StartCall().
///
/// \param[in] context The context object now associated with this RPC
virtual void OnStarted(ServerContext* context) {}
virtual void OnStarted(::grpc_impl::ServerContext* context) {}
/// Notifies the application that an explicit StartSendInitialMetadata
/// operation completed. Not used when the sending of initial metadata
@ -372,7 +372,7 @@ class ServerReadReactor : public internal::ServerReactor {
///
/// \param[in] context The context object now associated with this RPC
/// \param[in] resp The response object to be used by this RPC
virtual void OnStarted(ServerContext* context, Response* resp) {}
virtual void OnStarted(::grpc_impl::ServerContext* context, Response* resp) {}
/// The following notifications are exactly like ServerBidiReactor.
virtual void OnSendInitialMetadataDone(bool ok) {}
@ -413,7 +413,8 @@ class ServerWriteReactor : public internal::ServerReactor {
///
/// \param[in] context The context object now associated with this RPC
/// \param[in] req The request object sent by the client
virtual void OnStarted(ServerContext* context, const Request* req) {}
virtual void OnStarted(::grpc_impl::ServerContext* context,
const Request* req) {}
/// The following notifications are exactly like ServerBidiReactor.
virtual void OnSendInitialMetadataDone(bool ok) {}
@ -437,7 +438,7 @@ class UnimplementedReadReactor
: public experimental::ServerReadReactor<Request, Response> {
public:
void OnDone() override { delete this; }
void OnStarted(ServerContext*, Response*) override {
void OnStarted(::grpc_impl::ServerContext*, Response*) override {
this->Finish(Status(StatusCode::UNIMPLEMENTED, ""));
}
};
@ -447,7 +448,7 @@ class UnimplementedWriteReactor
: public experimental::ServerWriteReactor<Request, Response> {
public:
void OnDone() override { delete this; }
void OnStarted(ServerContext*, const Request*) override {
void OnStarted(::grpc_impl::ServerContext*, const Request*) override {
this->Finish(Status(StatusCode::UNIMPLEMENTED, ""));
}
};
@ -457,7 +458,7 @@ class UnimplementedBidiReactor
: public experimental::ServerBidiReactor<Request, Response> {
public:
void OnDone() override { delete this; }
void OnStarted(ServerContext*) override {
void OnStarted(::grpc_impl::ServerContext*) override {
this->Finish(Status(StatusCode::UNIMPLEMENTED, ""));
}
};
@ -466,7 +467,8 @@ template <class RequestType, class ResponseType>
class CallbackUnaryHandler : public MethodHandler {
public:
CallbackUnaryHandler(
std::function<void(ServerContext*, const RequestType*, ResponseType*,
std::function<void(::grpc_impl::ServerContext*, const RequestType*,
ResponseType*,
experimental::ServerCallbackRpcController*)>
func)
: func_(func) {}
@ -525,8 +527,8 @@ class CallbackUnaryHandler : public MethodHandler {
}
private:
std::function<void(ServerContext*, const RequestType*, ResponseType*,
experimental::ServerCallbackRpcController*)>
std::function<void(::grpc_impl::ServerContext*, const RequestType*,
ResponseType*, experimental::ServerCallbackRpcController*)>
func_;
experimental::MessageAllocator<RequestType, ResponseType>* allocator_ =
nullptr;
@ -597,7 +599,7 @@ class CallbackUnaryHandler : public MethodHandler {
friend class CallbackUnaryHandler<RequestType, ResponseType>;
ServerCallbackRpcControllerImpl(
ServerContext* ctx, Call* call,
::grpc_impl::ServerContext* ctx, Call* call,
experimental::MessageHolder<RequestType, ResponseType>* allocator_state,
std::function<void()> call_requester)
: ctx_(ctx),
@ -628,7 +630,7 @@ class CallbackUnaryHandler : public MethodHandler {
finish_ops_;
CallbackWithSuccessTag finish_tag_;
ServerContext* ctx_;
::grpc_impl::ServerContext* ctx_;
Call call_;
experimental::MessageHolder<RequestType, ResponseType>* const
allocator_state_;
@ -732,7 +734,8 @@ class CallbackClientStreamingHandler : public MethodHandler {
friend class CallbackClientStreamingHandler<RequestType, ResponseType>;
ServerCallbackReaderImpl(
ServerContext* ctx, Call* call, std::function<void()> call_requester,
::grpc_impl::ServerContext* ctx, Call* call,
std::function<void()> call_requester,
experimental::ServerReadReactor<RequestType, ResponseType>* reactor)
: ctx_(ctx),
call_(*call),
@ -772,7 +775,7 @@ class CallbackClientStreamingHandler : public MethodHandler {
CallOpSet<CallOpRecvMessage<RequestType>> read_ops_;
CallbackWithSuccessTag read_tag_;
ServerContext* ctx_;
::grpc_impl::ServerContext* ctx_;
Call call_;
ResponseType resp_;
std::function<void()> call_requester_;
@ -909,7 +912,7 @@ class CallbackServerStreamingHandler : public MethodHandler {
friend class CallbackServerStreamingHandler<RequestType, ResponseType>;
ServerCallbackWriterImpl(
ServerContext* ctx, Call* call, const RequestType* req,
::grpc_impl::ServerContext* ctx, Call* call, const RequestType* req,
std::function<void()> call_requester,
experimental::ServerWriteReactor<RequestType, ResponseType>* reactor)
: ctx_(ctx),
@ -950,7 +953,7 @@ class CallbackServerStreamingHandler : public MethodHandler {
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> write_ops_;
CallbackWithSuccessTag write_tag_;
ServerContext* ctx_;
::grpc_impl::ServerContext* ctx_;
Call call_;
const RequestType* req_;
std::function<void()> call_requester_;
@ -1078,7 +1081,8 @@ class CallbackBidiHandler : public MethodHandler {
friend class CallbackBidiHandler<RequestType, ResponseType>;
ServerCallbackReaderWriterImpl(
ServerContext* ctx, Call* call, std::function<void()> call_requester,
::grpc_impl::ServerContext* ctx, Call* call,
std::function<void()> call_requester,
experimental::ServerBidiReactor<RequestType, ResponseType>* reactor)
: ctx_(ctx),
call_(*call),
@ -1124,7 +1128,7 @@ class CallbackBidiHandler : public MethodHandler {
CallOpSet<CallOpRecvMessage<RequestType>> read_ops_;
CallbackWithSuccessTag read_tag_;
ServerContext* ctx_;
::grpc_impl::ServerContext* ctx_;
Call call_;
std::function<void()> call_requester_;
experimental::ServerBidiReactor<RequestType, ResponseType>* reactor_;

@ -19,361 +19,10 @@
#ifndef GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_H
#define GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_H
#include <map>
#include <memory>
#include <vector>
#include <grpcpp/impl/codegen/server_context_impl.h>
#include <grpc/impl/codegen/compression_types.h>
#include <grpcpp/impl/codegen/call.h>
#include <grpcpp/impl/codegen/call_op_set.h>
#include <grpcpp/impl/codegen/callback_common.h>
#include <grpcpp/impl/codegen/completion_queue_tag.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/create_auth_context.h>
#include <grpcpp/impl/codegen/metadata_map.h>
#include <grpcpp/impl/codegen/security/auth_context.h>
#include <grpcpp/impl/codegen/server_interceptor.h>
#include <grpcpp/impl/codegen/string_ref.h>
#include <grpcpp/impl/codegen/time.h>
struct grpc_metadata;
struct grpc_call;
struct census_context;
namespace grpc_impl {
class CompletionQueue;
class Server;
} // namespace grpc_impl
namespace grpc {
class ClientContext;
class GenericServerContext;
class ServerInterface;
template <class W, class R>
class ServerAsyncReader;
template <class W>
class ServerAsyncWriter;
template <class W>
class ServerAsyncResponseWriter;
template <class W, class R>
class ServerAsyncReaderWriter;
template <class R>
class ServerReader;
template <class W>
class ServerWriter;
namespace internal {
template <class W, class R>
class ServerReaderWriterBody;
template <class ServiceType, class RequestType, class ResponseType>
class RpcMethodHandler;
template <class ServiceType, class RequestType, class ResponseType>
class ClientStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
class ServerStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
class BidiStreamingHandler;
template <class RequestType, class ResponseType>
class CallbackUnaryHandler;
template <class RequestType, class ResponseType>
class CallbackClientStreamingHandler;
template <class RequestType, class ResponseType>
class CallbackServerStreamingHandler;
template <class RequestType, class ResponseType>
class CallbackBidiHandler;
template <class Streamer, bool WriteNeeded>
class TemplatedBidiStreamingHandler;
template <StatusCode code>
class ErrorMethodHandler;
class Call;
class ServerReactor;
} // namespace internal
class ServerInterface;
namespace testing {
class InteropServerContextInspector;
class ServerContextTestSpouse;
} // namespace testing
/// A ServerContext allows the person implementing a service handler to:
///
/// - Add custom initial and trailing metadata key-value pairs that will
/// propagated to the client side.
/// - Control call settings such as compression and authentication.
/// - Access metadata coming from the client.
/// - Get performance metrics (ie, census).
///
/// Context settings are only relevant to the call handler they are supplied to,
/// that is to say, they aren't sticky across multiple calls. Some of these
/// settings, such as the compression options, can be made persistent at server
/// construction time by specifying the appropriate \a ChannelArguments
/// to a \a grpc::ServerBuilder, via \a ServerBuilder::AddChannelArgument.
///
/// \warning ServerContext instances should \em not be reused across rpcs.
class ServerContext {
public:
ServerContext(); // for async calls
~ServerContext();
/// Return the deadline for the server call.
std::chrono::system_clock::time_point deadline() const {
return Timespec2Timepoint(deadline_);
}
/// Return a \a gpr_timespec representation of the server call's deadline.
gpr_timespec raw_deadline() const { return deadline_; }
/// Add the (\a key, \a value) pair to the initial metadata
/// associated with a server call. These are made available at the client side
/// by the \a grpc::ClientContext::GetServerInitialMetadata() method.
///
/// \warning This method should only be called before sending initial metadata
/// to the client (which can happen explicitly, or implicitly when sending a
/// a response message or status to the client).
///
/// \param key The metadata key. If \a value is binary data, it must
/// end in "-bin".
/// \param value The metadata value. If its value is binary, the key name
/// must end in "-bin".
///
/// Metadata must conform to the following format:
/// Custom-Metadata -> Binary-Header / ASCII-Header
/// Binary-Header -> {Header-Name "-bin" } {binary value}
/// ASCII-Header -> Header-Name ASCII-Value
/// Header-Name -> 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - .
/// ASCII-Value -> 1*( %x20-%x7E ) ; space and printable ASCII
void AddInitialMetadata(const grpc::string& key, const grpc::string& value);
/// Add the (\a key, \a value) pair to the initial metadata
/// associated with a server call. These are made available at the client
/// side by the \a grpc::ClientContext::GetServerTrailingMetadata() method.
///
/// \warning This method should only be called before sending trailing
/// metadata to the client (which happens when the call is finished and a
/// status is sent to the client).
///
/// \param key The metadata key. If \a value is binary data,
/// it must end in "-bin".
/// \param value The metadata value. If its value is binary, the key name
/// must end in "-bin".
///
/// Metadata must conform to the following format:
/// Custom-Metadata -> Binary-Header / ASCII-Header
/// Binary-Header -> {Header-Name "-bin" } {binary value}
/// ASCII-Header -> Header-Name ASCII-Value
/// Header-Name -> 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - .
/// ASCII-Value -> 1*( %x20-%x7E ) ; space and printable ASCII
void AddTrailingMetadata(const grpc::string& key, const grpc::string& value);
/// IsCancelled is always safe to call when using sync or callback API.
/// When using async API, it is only safe to call IsCancelled after
/// the AsyncNotifyWhenDone tag has been delivered.
bool IsCancelled() const;
/// Cancel the Call from the server. This is a best-effort API and
/// depending on when it is called, the RPC may still appear successful to
/// the client.
/// For example, if TryCancel() is called on a separate thread, it might race
/// with the server handler which might return success to the client before
/// TryCancel() was even started by the thread.
///
/// It is the caller's responsibility to prevent such races and ensure that if
/// TryCancel() is called, the serverhandler must return Status::CANCELLED.
/// The only exception is that if the serverhandler is already returning an
/// error status code, it is ok to not return Status::CANCELLED even if
/// TryCancel() was called.
///
/// Note that TryCancel() does not change any of the tags that are pending
/// on the completion queue. All pending tags will still be delivered
/// (though their ok result may reflect the effect of cancellation).
void TryCancel() const;
/// Return a collection of initial metadata key-value pairs sent from the
/// client. Note that keys may happen more than
/// once (ie, a \a std::multimap is returned).
///
/// It is safe to use this method after initial metadata has been received,
/// Calls always begin with the client sending initial metadata, so this is
/// safe to access as soon as the call has begun on the server side.
///
/// \return A multimap of initial metadata key-value pairs from the server.
const std::multimap<grpc::string_ref, grpc::string_ref>& client_metadata()
const {
return *client_metadata_.map();
}
/// Return the compression algorithm to be used by the server call.
grpc_compression_level compression_level() const {
return compression_level_;
}
/// Set \a level to be the compression level used for the server call.
///
/// \param level The compression level used for the server call.
void set_compression_level(grpc_compression_level level) {
compression_level_set_ = true;
compression_level_ = level;
}
/// Return a bool indicating whether the compression level for this call
/// has been set (either implicitly or through a previous call to
/// \a set_compression_level.
bool compression_level_set() const { return compression_level_set_; }
/// Return the compression algorithm the server call will request be used.
/// Note that the gRPC runtime may decide to ignore this request, for example,
/// due to resource constraints, or if the server is aware the client doesn't
/// support the requested algorithm.
grpc_compression_algorithm compression_algorithm() const {
return compression_algorithm_;
}
/// Set \a algorithm to be the compression algorithm used for the server call.
///
/// \param algorithm The compression algorithm used for the server call.
void set_compression_algorithm(grpc_compression_algorithm algorithm);
/// Set the serialized load reporting costs in \a cost_data for the call.
void SetLoadReportingCosts(const std::vector<grpc::string>& cost_data);
/// Return the authentication context for this server call.
///
/// \see grpc::AuthContext.
std::shared_ptr<const AuthContext> auth_context() const {
if (auth_context_.get() == nullptr) {
auth_context_ = CreateAuthContext(call_);
}
return auth_context_;
}
/// Return the peer uri in a string.
/// WARNING: this value is never authenticated or subject to any security
/// related code. It must not be used for any authentication related
/// functionality. Instead, use auth_context.
grpc::string peer() const;
/// Get the census context associated with this server call.
const struct census_context* census_context() const;
/// Async only. Has to be called before the rpc starts.
/// Returns the tag in completion queue when the rpc finishes.
/// IsCancelled() can then be called to check whether the rpc was cancelled.
/// TODO(vjpai): Fix this so that the tag is returned even if the call never
/// starts (https://github.com/grpc/grpc/issues/10136).
void AsyncNotifyWhenDone(void* tag) {
has_notify_when_done_tag_ = true;
async_notify_when_done_tag_ = tag;
}
/// Should be used for framework-level extensions only.
/// Applications never need to call this method.
grpc_call* c_call() { return call_; }
private:
friend class ::grpc::testing::InteropServerContextInspector;
friend class ::grpc::testing::ServerContextTestSpouse;
friend class ::grpc::ServerInterface;
friend class ::grpc_impl::Server;
template <class W, class R>
friend class ::grpc::ServerAsyncReader;
template <class W>
friend class ::grpc::ServerAsyncWriter;
template <class W>
friend class ::grpc::ServerAsyncResponseWriter;
template <class W, class R>
friend class ::grpc::ServerAsyncReaderWriter;
template <class R>
friend class ::grpc::ServerReader;
template <class W>
friend class ::grpc::ServerWriter;
template <class W, class R>
friend class ::grpc::internal::ServerReaderWriterBody;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc::internal::RpcMethodHandler;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc::internal::ClientStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc::internal::ServerStreamingHandler;
template <class Streamer, bool WriteNeeded>
friend class ::grpc::internal::TemplatedBidiStreamingHandler;
template <class RequestType, class ResponseType>
friend class ::grpc::internal::CallbackUnaryHandler;
template <class RequestType, class ResponseType>
friend class ::grpc::internal::CallbackClientStreamingHandler;
template <class RequestType, class ResponseType>
friend class ::grpc::internal::CallbackServerStreamingHandler;
template <class RequestType, class ResponseType>
friend class ::grpc::internal::CallbackBidiHandler;
template <StatusCode code>
friend class internal::ErrorMethodHandler;
friend class ::grpc::ClientContext;
friend class ::grpc::GenericServerContext;
/// Prevent copying.
ServerContext(const ServerContext&);
ServerContext& operator=(const ServerContext&);
class CompletionOp;
void BeginCompletionOp(internal::Call* call,
std::function<void(bool)> callback,
internal::ServerReactor* reactor);
/// Return the tag queued by BeginCompletionOp()
internal::CompletionQueueTag* GetCompletionOpTag();
ServerContext(gpr_timespec deadline, grpc_metadata_array* arr);
void set_call(grpc_call* call) { call_ = call; }
void BindDeadlineAndMetadata(gpr_timespec deadline, grpc_metadata_array* arr);
void Clear();
void Setup(gpr_timespec deadline);
uint32_t initial_metadata_flags() const { return 0; }
void SetCancelCallback(std::function<void()> callback);
void ClearCancelCallback();
experimental::ServerRpcInfo* set_server_rpc_info(
const char* method, internal::RpcMethod::RpcType type,
const std::vector<
std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>&
creators) {
if (creators.size() != 0) {
rpc_info_ = new experimental::ServerRpcInfo(this, method, type);
rpc_info_->RegisterInterceptors(creators);
}
return rpc_info_;
}
CompletionOp* completion_op_;
bool has_notify_when_done_tag_;
void* async_notify_when_done_tag_;
internal::CallbackWithSuccessTag completion_tag_;
gpr_timespec deadline_;
grpc_call* call_;
::grpc_impl::CompletionQueue* cq_;
bool sent_initial_metadata_;
mutable std::shared_ptr<const AuthContext> auth_context_;
mutable internal::MetadataMap client_metadata_;
std::multimap<grpc::string, grpc::string> initial_metadata_;
std::multimap<grpc::string, grpc::string> trailing_metadata_;
bool compression_level_set_;
grpc_compression_level compression_level_;
grpc_compression_algorithm compression_algorithm_;
internal::CallOpSet<internal::CallOpSendInitialMetadata,
internal::CallOpSendMessage>
pending_ops_;
bool has_pending_ops_;
experimental::ServerRpcInfo* rpc_info_;
};
typedef ::grpc_impl::ServerContext ServerContext;
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_H

@ -0,0 +1,376 @@
/*
*
* Copyright 2019 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 GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_IMPL_H
#define GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_IMPL_H
#include <map>
#include <memory>
#include <vector>
#include <grpc/impl/codegen/compression_types.h>
#include <grpcpp/impl/codegen/call.h>
#include <grpcpp/impl/codegen/call_op_set.h>
#include <grpcpp/impl/codegen/callback_common.h>
#include <grpcpp/impl/codegen/completion_queue_tag.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/create_auth_context.h>
#include <grpcpp/impl/codegen/metadata_map.h>
#include <grpcpp/impl/codegen/security/auth_context.h>
#include <grpcpp/impl/codegen/server_interceptor.h>
#include <grpcpp/impl/codegen/string_ref.h>
#include <grpcpp/impl/codegen/time.h>
struct grpc_metadata;
struct grpc_call;
struct census_context;
namespace grpc_impl {
class ClientContext;
class CompletionQueue;
class Server;
} // namespace grpc_impl
namespace grpc {
class GenericServerContext;
class ServerInterface;
template <class W, class R>
class ServerAsyncReader;
template <class W>
class ServerAsyncWriter;
template <class W>
class ServerAsyncResponseWriter;
template <class W, class R>
class ServerAsyncReaderWriter;
template <class R>
class ServerReader;
template <class W>
class ServerWriter;
namespace internal {
template <class W, class R>
class ServerReaderWriterBody;
template <class ServiceType, class RequestType, class ResponseType>
class RpcMethodHandler;
template <class ServiceType, class RequestType, class ResponseType>
class ClientStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
class ServerStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
class BidiStreamingHandler;
template <class RequestType, class ResponseType>
class CallbackUnaryHandler;
template <class RequestType, class ResponseType>
class CallbackClientStreamingHandler;
template <class RequestType, class ResponseType>
class CallbackServerStreamingHandler;
template <class RequestType, class ResponseType>
class CallbackBidiHandler;
template <class Streamer, bool WriteNeeded>
class TemplatedBidiStreamingHandler;
template <StatusCode code>
class ErrorMethodHandler;
class Call;
class ServerReactor;
} // namespace internal
class ServerInterface;
namespace testing {
class InteropServerContextInspector;
class ServerContextTestSpouse;
} // namespace testing
} // namespace grpc
namespace grpc_impl {
/// A ServerContext allows the person implementing a service handler to:
///
/// - Add custom initial and trailing metadata key-value pairs that will
/// propagated to the client side.
/// - Control call settings such as compression and authentication.
/// - Access metadata coming from the client.
/// - Get performance metrics (ie, census).
///
/// Context settings are only relevant to the call handler they are supplied to,
/// that is to say, they aren't sticky across multiple calls. Some of these
/// settings, such as the compression options, can be made persistent at server
/// construction time by specifying the appropriate \a ChannelArguments
/// to a \a grpc::ServerBuilder, via \a ServerBuilder::AddChannelArgument.
///
/// \warning ServerContext instances should \em not be reused across rpcs.
class ServerContext {
public:
ServerContext(); // for async calls
~ServerContext();
/// Return the deadline for the server call.
std::chrono::system_clock::time_point deadline() const {
return ::grpc::Timespec2Timepoint(deadline_);
}
/// Return a \a gpr_timespec representation of the server call's deadline.
gpr_timespec raw_deadline() const { return deadline_; }
/// Add the (\a key, \a value) pair to the initial metadata
/// associated with a server call. These are made available at the client side
/// by the \a grpc::ClientContext::GetServerInitialMetadata() method.
///
/// \warning This method should only be called before sending initial metadata
/// to the client (which can happen explicitly, or implicitly when sending a
/// a response message or status to the client).
///
/// \param key The metadata key. If \a value is binary data, it must
/// end in "-bin".
/// \param value The metadata value. If its value is binary, the key name
/// must end in "-bin".
///
/// Metadata must conform to the following format:
/// Custom-Metadata -> Binary-Header / ASCII-Header
/// Binary-Header -> {Header-Name "-bin" } {binary value}
/// ASCII-Header -> Header-Name ASCII-Value
/// Header-Name -> 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - .
/// ASCII-Value -> 1*( %x20-%x7E ) ; space and printable ASCII
void AddInitialMetadata(const grpc::string& key, const grpc::string& value);
/// Add the (\a key, \a value) pair to the initial metadata
/// associated with a server call. These are made available at the client
/// side by the \a grpc::ClientContext::GetServerTrailingMetadata() method.
///
/// \warning This method should only be called before sending trailing
/// metadata to the client (which happens when the call is finished and a
/// status is sent to the client).
///
/// \param key The metadata key. If \a value is binary data,
/// it must end in "-bin".
/// \param value The metadata value. If its value is binary, the key name
/// must end in "-bin".
///
/// Metadata must conform to the following format:
/// Custom-Metadata -> Binary-Header / ASCII-Header
/// Binary-Header -> {Header-Name "-bin" } {binary value}
/// ASCII-Header -> Header-Name ASCII-Value
/// Header-Name -> 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - .
/// ASCII-Value -> 1*( %x20-%x7E ) ; space and printable ASCII
void AddTrailingMetadata(const grpc::string& key, const grpc::string& value);
/// IsCancelled is always safe to call when using sync or callback API.
/// When using async API, it is only safe to call IsCancelled after
/// the AsyncNotifyWhenDone tag has been delivered.
bool IsCancelled() const;
/// Cancel the Call from the server. This is a best-effort API and
/// depending on when it is called, the RPC may still appear successful to
/// the client.
/// For example, if TryCancel() is called on a separate thread, it might race
/// with the server handler which might return success to the client before
/// TryCancel() was even started by the thread.
///
/// It is the caller's responsibility to prevent such races and ensure that if
/// TryCancel() is called, the serverhandler must return Status::CANCELLED.
/// The only exception is that if the serverhandler is already returning an
/// error status code, it is ok to not return Status::CANCELLED even if
/// TryCancel() was called.
///
/// Note that TryCancel() does not change any of the tags that are pending
/// on the completion queue. All pending tags will still be delivered
/// (though their ok result may reflect the effect of cancellation).
void TryCancel() const;
/// Return a collection of initial metadata key-value pairs sent from the
/// client. Note that keys may happen more than
/// once (ie, a \a std::multimap is returned).
///
/// It is safe to use this method after initial metadata has been received,
/// Calls always begin with the client sending initial metadata, so this is
/// safe to access as soon as the call has begun on the server side.
///
/// \return A multimap of initial metadata key-value pairs from the server.
const std::multimap<grpc::string_ref, grpc::string_ref>& client_metadata()
const {
return *client_metadata_.map();
}
/// Return the compression algorithm to be used by the server call.
grpc_compression_level compression_level() const {
return compression_level_;
}
/// Set \a level to be the compression level used for the server call.
///
/// \param level The compression level used for the server call.
void set_compression_level(grpc_compression_level level) {
compression_level_set_ = true;
compression_level_ = level;
}
/// Return a bool indicating whether the compression level for this call
/// has been set (either implicitly or through a previous call to
/// \a set_compression_level.
bool compression_level_set() const { return compression_level_set_; }
/// Return the compression algorithm the server call will request be used.
/// Note that the gRPC runtime may decide to ignore this request, for example,
/// due to resource constraints, or if the server is aware the client doesn't
/// support the requested algorithm.
grpc_compression_algorithm compression_algorithm() const {
return compression_algorithm_;
}
/// Set \a algorithm to be the compression algorithm used for the server call.
///
/// \param algorithm The compression algorithm used for the server call.
void set_compression_algorithm(grpc_compression_algorithm algorithm);
/// Set the serialized load reporting costs in \a cost_data for the call.
void SetLoadReportingCosts(const std::vector<grpc::string>& cost_data);
/// Return the authentication context for this server call.
///
/// \see grpc::AuthContext.
std::shared_ptr<const ::grpc::AuthContext> auth_context() const {
if (auth_context_.get() == nullptr) {
auth_context_ = ::grpc::CreateAuthContext(call_);
}
return auth_context_;
}
/// Return the peer uri in a string.
/// WARNING: this value is never authenticated or subject to any security
/// related code. It must not be used for any authentication related
/// functionality. Instead, use auth_context.
grpc::string peer() const;
/// Get the census context associated with this server call.
const struct census_context* census_context() const;
/// Async only. Has to be called before the rpc starts.
/// Returns the tag in completion queue when the rpc finishes.
/// IsCancelled() can then be called to check whether the rpc was cancelled.
/// TODO(vjpai): Fix this so that the tag is returned even if the call never
/// starts (https://github.com/grpc/grpc/issues/10136).
void AsyncNotifyWhenDone(void* tag) {
has_notify_when_done_tag_ = true;
async_notify_when_done_tag_ = tag;
}
/// Should be used for framework-level extensions only.
/// Applications never need to call this method.
grpc_call* c_call() { return call_; }
private:
friend class ::grpc::testing::InteropServerContextInspector;
friend class ::grpc::testing::ServerContextTestSpouse;
friend class ::grpc::ServerInterface;
friend class ::grpc_impl::Server;
template <class W, class R>
friend class ::grpc::ServerAsyncReader;
template <class W>
friend class ::grpc::ServerAsyncWriter;
template <class W>
friend class ::grpc::ServerAsyncResponseWriter;
template <class W, class R>
friend class ::grpc::ServerAsyncReaderWriter;
template <class R>
friend class ::grpc::ServerReader;
template <class W>
friend class ::grpc::ServerWriter;
template <class W, class R>
friend class ::grpc::internal::ServerReaderWriterBody;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc::internal::RpcMethodHandler;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc::internal::ClientStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
friend class ::grpc::internal::ServerStreamingHandler;
template <class Streamer, bool WriteNeeded>
friend class ::grpc::internal::TemplatedBidiStreamingHandler;
template <class RequestType, class ResponseType>
friend class ::grpc::internal::CallbackUnaryHandler;
template <class RequestType, class ResponseType>
friend class ::grpc::internal::CallbackClientStreamingHandler;
template <class RequestType, class ResponseType>
friend class ::grpc::internal::CallbackServerStreamingHandler;
template <class RequestType, class ResponseType>
friend class ::grpc::internal::CallbackBidiHandler;
template <::grpc::StatusCode code>
friend class ::grpc::internal::ErrorMethodHandler;
friend class ::grpc_impl::ClientContext;
friend class ::grpc::GenericServerContext;
/// Prevent copying.
ServerContext(const ServerContext&);
ServerContext& operator=(const ServerContext&);
class CompletionOp;
void BeginCompletionOp(::grpc::internal::Call* call,
std::function<void(bool)> callback,
::grpc::internal::ServerReactor* reactor);
/// Return the tag queued by BeginCompletionOp()
::grpc::internal::CompletionQueueTag* GetCompletionOpTag();
ServerContext(gpr_timespec deadline, grpc_metadata_array* arr);
void set_call(grpc_call* call) { call_ = call; }
void BindDeadlineAndMetadata(gpr_timespec deadline, grpc_metadata_array* arr);
void Clear();
void Setup(gpr_timespec deadline);
uint32_t initial_metadata_flags() const { return 0; }
void SetCancelCallback(std::function<void()> callback);
void ClearCancelCallback();
::grpc::experimental::ServerRpcInfo* set_server_rpc_info(
const char* method, ::grpc::internal::RpcMethod::RpcType type,
const std::vector<std::unique_ptr<
::grpc::experimental::ServerInterceptorFactoryInterface>>& creators) {
if (creators.size() != 0) {
rpc_info_ = new ::grpc::experimental::ServerRpcInfo(this, method, type);
rpc_info_->RegisterInterceptors(creators);
}
return rpc_info_;
}
CompletionOp* completion_op_;
bool has_notify_when_done_tag_;
void* async_notify_when_done_tag_;
::grpc::internal::CallbackWithSuccessTag completion_tag_;
gpr_timespec deadline_;
grpc_call* call_;
::grpc_impl::CompletionQueue* cq_;
bool sent_initial_metadata_;
mutable std::shared_ptr<const ::grpc::AuthContext> auth_context_;
mutable ::grpc::internal::MetadataMap client_metadata_;
std::multimap<grpc::string, grpc::string> initial_metadata_;
std::multimap<grpc::string, grpc::string> trailing_metadata_;
bool compression_level_set_;
grpc_compression_level compression_level_;
grpc_compression_algorithm compression_algorithm_;
::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata,
::grpc::internal::CallOpSendMessage>
pending_ops_;
bool has_pending_ops_;
::grpc::experimental::ServerRpcInfo* rpc_info_;
};
} // namespace grpc_impl
#endif // GRPCPP_IMPL_CODEGEN_SERVER_CONTEXT_IMPL_H

@ -26,9 +26,11 @@
#include <grpcpp/impl/codegen/rpc_method.h>
#include <grpcpp/impl/codegen/string_ref.h>
namespace grpc {
namespace grpc_impl {
class ServerContext;
}
namespace grpc {
namespace internal {
class InterceptorBatchMethodsImpl;
@ -78,7 +80,7 @@ class ServerRpcInfo {
/// Return a pointer to the underlying ServerContext structure associated
/// with the RPC to support features that apply to it
grpc::ServerContext* server_context() { return ctx_; }
grpc_impl::ServerContext* server_context() { return ctx_; }
private:
static_assert(Type::UNARY ==
@ -94,7 +96,7 @@ class ServerRpcInfo {
static_cast<Type>(internal::RpcMethod::BIDI_STREAMING),
"violated expectation about Type enum");
ServerRpcInfo(grpc::ServerContext* ctx, const char* method,
ServerRpcInfo(grpc_impl::ServerContext* ctx, const char* method,
internal::RpcMethod::RpcType type)
: ctx_(ctx), method_(method), type_(static_cast<Type>(type)) {
ref_.store(1);
@ -127,14 +129,14 @@ class ServerRpcInfo {
}
}
grpc::ServerContext* ctx_ = nullptr;
grpc_impl::ServerContext* ctx_ = nullptr;
const char* method_ = nullptr;
const Type type_;
std::atomic_int ref_;
std::vector<std::unique_ptr<experimental::Interceptor>> interceptors_;
friend class internal::InterceptorBatchMethodsImpl;
friend class grpc::ServerContext;
friend class grpc_impl::ServerContext;
};
} // namespace experimental

@ -34,12 +34,12 @@ class Channel;
class CompletionQueue;
class ServerCompletionQueue;
class ServerCredentials;
class ServerContext;
} // namespace grpc_impl
namespace grpc {
class AsyncGenericService;
class GenericServerContext;
class ServerContext;
class Service;
extern CoreCodegenInterface* g_core_codegen_interface;
@ -176,7 +176,8 @@ class ServerInterface : public internal::CallHook {
class BaseAsyncRequest : public internal::CompletionQueueTag {
public:
BaseAsyncRequest(ServerInterface* server, ServerContext* context,
BaseAsyncRequest(ServerInterface* server,
::grpc_impl::ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq,
@ -190,7 +191,7 @@ class ServerInterface : public internal::CallHook {
protected:
ServerInterface* const server_;
ServerContext* const context_;
::grpc_impl::ServerContext* const context_;
internal::ServerAsyncStreamingInterface* const stream_;
::grpc_impl::CompletionQueue* const call_cq_;
::grpc_impl::ServerCompletionQueue* const notification_cq_;
@ -205,7 +206,8 @@ class ServerInterface : public internal::CallHook {
/// RegisteredAsyncRequest is not part of the C++ API
class RegisteredAsyncRequest : public BaseAsyncRequest {
public:
RegisteredAsyncRequest(ServerInterface* server, ServerContext* context,
RegisteredAsyncRequest(ServerInterface* server,
::grpc_impl::ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq,
@ -234,7 +236,8 @@ class ServerInterface : public internal::CallHook {
class NoPayloadAsyncRequest final : public RegisteredAsyncRequest {
public:
NoPayloadAsyncRequest(internal::RpcServiceMethod* registered_method,
ServerInterface* server, ServerContext* context,
ServerInterface* server,
::grpc_impl::ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq,
@ -252,7 +255,8 @@ class ServerInterface : public internal::CallHook {
class PayloadAsyncRequest final : public RegisteredAsyncRequest {
public:
PayloadAsyncRequest(internal::RpcServiceMethod* registered_method,
ServerInterface* server, ServerContext* context,
ServerInterface* server,
::grpc_impl::ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq,
@ -309,7 +313,7 @@ class ServerInterface : public internal::CallHook {
private:
internal::RpcServiceMethod* const registered_method_;
ServerInterface* const server_;
ServerContext* const context_;
::grpc_impl::ServerContext* const context_;
internal::ServerAsyncStreamingInterface* const stream_;
::grpc_impl::CompletionQueue* const call_cq_;
@ -335,7 +339,7 @@ class ServerInterface : public internal::CallHook {
template <class Message>
void RequestAsyncCall(internal::RpcServiceMethod* method,
ServerContext* context,
::grpc_impl::ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq,
@ -346,7 +350,7 @@ class ServerInterface : public internal::CallHook {
}
void RequestAsyncCall(internal::RpcServiceMethod* method,
ServerContext* context,
::grpc_impl::ServerContext* context,
internal::ServerAsyncStreamingInterface* stream,
::grpc_impl::CompletionQueue* call_cq,
::grpc_impl::ServerCompletionQueue* notification_cq,

@ -30,11 +30,11 @@ namespace grpc_impl {
class Server;
class CompletionQueue;
class ServerContext;
} // namespace grpc_impl
namespace grpc {
class ServerInterface;
class ServerContext;
namespace internal {
class Call;
@ -146,7 +146,8 @@ class Service {
experimental_type experimental() { return experimental_type(this); }
template <class Message>
void RequestAsyncUnary(int index, ServerContext* context, Message* request,
void RequestAsyncUnary(int index, ::grpc_impl::ServerContext* context,
Message* request,
internal::ServerAsyncStreamingInterface* stream,
CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq, void* tag) {
@ -158,7 +159,7 @@ class Service {
notification_cq, tag, request);
}
void RequestAsyncClientStreaming(
int index, ServerContext* context,
int index, ::grpc_impl::ServerContext* context,
internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq, void* tag) {
size_t idx = static_cast<size_t>(index);
@ -167,7 +168,7 @@ class Service {
}
template <class Message>
void RequestAsyncServerStreaming(
int index, ServerContext* context, Message* request,
int index, ::grpc_impl::ServerContext* context, Message* request,
internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq, void* tag) {
size_t idx = static_cast<size_t>(index);
@ -175,7 +176,7 @@ class Service {
notification_cq, tag, request);
}
void RequestAsyncBidiStreaming(
int index, ServerContext* context,
int index, ::grpc_impl::ServerContext* context,
internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
ServerCompletionQueue* notification_cq, void* tag) {
size_t idx = static_cast<size_t>(index);

@ -30,7 +30,7 @@ static inline void RegisterOpenCensusViewsForExport() {
::grpc_impl::RegisterOpenCensusViewsForExport();
}
static inline ::opencensus::trace::Span GetSpanFromServerContext(
ServerContext* context) {
::grpc_impl::ServerContext* context) {
return ::grpc_impl::GetSpanFromServerContext(context);
}

@ -21,11 +21,8 @@
#include "opencensus/trace/span.h"
namespace grpc {
class ServerContext;
}
namespace grpc_impl {
class ServerContext;
// These symbols in this file will not be included in the binary unless
// grpc_opencensus_plugin build target was added as a dependency. At the moment
// it is only setup to be built with Bazel.
@ -43,8 +40,7 @@ void RegisterOpenCensusPlugin();
void RegisterOpenCensusViewsForExport();
// Returns the tracing Span for the current RPC.
::opencensus::trace::Span GetSpanFromServerContext(
grpc::ServerContext* context);
::opencensus::trace::Span GetSpanFromServerContext(ServerContext* context);
} // namespace grpc_impl

@ -44,7 +44,6 @@ struct grpc_server;
namespace grpc {
class AsyncGenericService;
class ServerContext;
namespace internal {
class ExternalConnectionAcceptorImpl;
@ -54,6 +53,7 @@ class ExternalConnectionAcceptorImpl;
namespace grpc_impl {
class HealthCheckServiceInterface;
class ServerContext;
class ServerInitializer;
/// Represents a gRPC server.
@ -82,9 +82,9 @@ class Server : public grpc::ServerInterface, private grpc::GrpcLibraryCodegen {
/// Called before server is created.
virtual void UpdateArguments(grpc::ChannelArguments* args) {}
/// Called before application callback for each synchronous server request
virtual void PreSynchronousRequest(grpc::ServerContext* context) = 0;
virtual void PreSynchronousRequest(grpc_impl::ServerContext* context) = 0;
/// Called after application callback for each synchronous server request
virtual void PostSynchronousRequest(grpc::ServerContext* context) = 0;
virtual void PostSynchronousRequest(grpc_impl::ServerContext* context) = 0;
/// Called before server is started.
virtual void PreServerStart(Server* server) {}
/// Called after a server port is added.

@ -1,6 +1,6 @@
# GRPC Python setup requirements
coverage>=4.0
cython==0.28.3
cython>=0.29.8
enum34>=1.0.4
protobuf>=3.5.0.post1
six>=1.10

@ -1,6 +1,6 @@
# GRPC Python setup requirements
coverage>=4.0
cython==0.28.3
cython>=0.29.8
enum34>=1.0.4
protobuf>=3.5.0.post1
six>=1.10

@ -157,13 +157,13 @@ grpc::string GetHeaderIncludes(grpc_generator::File* file,
printer->Print(vars, "namespace grpc_impl {\n");
printer->Print(vars, "class CompletionQueue;\n");
printer->Print(vars, "class ServerCompletionQueue;\n");
printer->Print(vars, "class ServerContext;\n");
printer->Print(vars, "} // namespace grpc_impl\n\n");
printer->Print(vars, "namespace grpc {\n");
printer->Print(vars, "namespace experimental {\n");
printer->Print(vars, "template <typename RequestT, typename ResponseT>\n");
printer->Print(vars, "class MessageAllocator;\n");
printer->Print(vars, "} // namespace experimental\n");
printer->Print(vars, "class ServerContext;\n");
printer->Print(vars, "} // namespace grpc\n\n");
vars["message_header_ext"] = params.message_header_extension.empty()

@ -118,18 +118,6 @@ class ChannelData {
static void GetChannelInfo(grpc_channel_element* elem,
const grpc_channel_info* info);
void set_channelz_node(channelz::ClientChannelNode* node) {
channelz_node_ = node;
resolving_lb_policy_->set_channelz_node(node->Ref());
}
void FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels,
channelz::ChildRefsList* child_channels) {
if (resolving_lb_policy_ != nullptr) {
resolving_lb_policy_->FillChildRefsForChannelz(child_subchannels,
child_channels);
}
}
bool deadline_checking_enabled() const { return deadline_checking_enabled_; }
bool enable_retries() const { return enable_retries_; }
size_t per_rpc_retry_buffer_size() const {
@ -159,6 +147,9 @@ class ChannelData {
return service_config_;
}
RefCountedPtr<ConnectedSubchannel> GetConnectedSubchannelInDataPlane(
SubchannelInterface* subchannel) const;
grpc_connectivity_state CheckConnectivityState(bool try_to_connect);
void AddExternalConnectivityWatcher(grpc_polling_entity pollent,
grpc_connectivity_state* state,
@ -173,9 +164,9 @@ class ChannelData {
}
private:
class SubchannelWrapper;
class ConnectivityStateAndPickerSetter;
class ServiceConfigSetter;
class GrpcSubchannel;
class ClientChannelControlHelper;
class ExternalConnectivityWatcher {
@ -249,8 +240,7 @@ class ChannelData {
ClientChannelFactory* client_channel_factory_;
UniquePtr<char> server_name_;
RefCountedPtr<ServiceConfig> default_service_config_;
// Initialized shortly after construction.
channelz::ClientChannelNode* channelz_node_ = nullptr;
channelz::ChannelNode* channelz_node_;
//
// Fields used in the data plane. Guarded by data_plane_combiner.
@ -269,12 +259,20 @@ class ChannelData {
grpc_combiner* combiner_;
grpc_pollset_set* interested_parties_;
RefCountedPtr<SubchannelPoolInterface> subchannel_pool_;
OrphanablePtr<LoadBalancingPolicy> resolving_lb_policy_;
OrphanablePtr<ResolvingLoadBalancingPolicy> resolving_lb_policy_;
grpc_connectivity_state_tracker state_tracker_;
ExternalConnectivityWatcher::WatcherList external_connectivity_watcher_list_;
UniquePtr<char> health_check_service_name_;
RefCountedPtr<ServiceConfig> saved_service_config_;
bool received_first_resolver_result_ = false;
// The number of SubchannelWrapper instances referencing a given Subchannel.
Map<Subchannel*, int> subchannel_refcount_map_;
// Pending ConnectedSubchannel updates for each SubchannelWrapper.
// Updates are queued here in the control plane combiner and then applied
// in the data plane combiner when the picker is updated.
Map<RefCountedPtr<SubchannelWrapper>, RefCountedPtr<ConnectedSubchannel>,
RefCountedPtrLess<SubchannelWrapper>>
pending_subchannel_updates_;
//
// Fields accessed from both data plane and control plane combiners.
@ -718,6 +716,247 @@ class CallData {
grpc_metadata_batch send_trailing_metadata_;
};
//
// ChannelData::SubchannelWrapper
//
// This class is a wrapper for Subchannel that hides details of the
// channel's implementation (such as the health check service name and
// connected subchannel) from the LB policy API.
//
// Note that no synchronization is needed here, because even if the
// underlying subchannel is shared between channels, this wrapper will only
// be used within one channel, so it will always be synchronized by the
// control plane combiner.
class ChannelData::SubchannelWrapper : public SubchannelInterface {
public:
SubchannelWrapper(ChannelData* chand, Subchannel* subchannel,
UniquePtr<char> health_check_service_name)
: SubchannelInterface(&grpc_client_channel_routing_trace),
chand_(chand),
subchannel_(subchannel),
health_check_service_name_(std::move(health_check_service_name)) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
gpr_log(GPR_INFO,
"chand=%p: creating subchannel wrapper %p for subchannel %p",
chand, this, subchannel_);
}
GRPC_CHANNEL_STACK_REF(chand_->owning_stack_, "SubchannelWrapper");
auto* subchannel_node = subchannel_->channelz_node();
if (subchannel_node != nullptr) {
intptr_t subchannel_uuid = subchannel_node->uuid();
auto it = chand_->subchannel_refcount_map_.find(subchannel_);
if (it == chand_->subchannel_refcount_map_.end()) {
chand_->channelz_node_->AddChildSubchannel(subchannel_uuid);
it = chand_->subchannel_refcount_map_.emplace(subchannel_, 0).first;
}
++it->second;
}
}
~SubchannelWrapper() {
if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
gpr_log(GPR_INFO,
"chand=%p: destroying subchannel wrapper %p for subchannel %p",
chand_, this, subchannel_);
}
auto* subchannel_node = subchannel_->channelz_node();
if (subchannel_node != nullptr) {
intptr_t subchannel_uuid = subchannel_node->uuid();
auto it = chand_->subchannel_refcount_map_.find(subchannel_);
GPR_ASSERT(it != chand_->subchannel_refcount_map_.end());
--it->second;
if (it->second == 0) {
chand_->channelz_node_->RemoveChildSubchannel(subchannel_uuid);
chand_->subchannel_refcount_map_.erase(it);
}
}
GRPC_SUBCHANNEL_UNREF(subchannel_, "unref from LB");
GRPC_CHANNEL_STACK_UNREF(chand_->owning_stack_, "SubchannelWrapper");
}
grpc_connectivity_state CheckConnectivityState() override {
RefCountedPtr<ConnectedSubchannel> connected_subchannel;
grpc_connectivity_state connectivity_state =
subchannel_->CheckConnectivityState(health_check_service_name_.get(),
&connected_subchannel);
MaybeUpdateConnectedSubchannel(std::move(connected_subchannel));
return connectivity_state;
}
void WatchConnectivityState(
grpc_connectivity_state initial_state,
UniquePtr<ConnectivityStateWatcherInterface> watcher) override {
auto& watcher_wrapper = watcher_map_[watcher.get()];
GPR_ASSERT(watcher_wrapper == nullptr);
watcher_wrapper = New<WatcherWrapper>(
std::move(watcher), Ref(DEBUG_LOCATION, "WatcherWrapper"));
subchannel_->WatchConnectivityState(
initial_state,
UniquePtr<char>(gpr_strdup(health_check_service_name_.get())),
OrphanablePtr<Subchannel::ConnectivityStateWatcherInterface>(
watcher_wrapper));
}
void CancelConnectivityStateWatch(
ConnectivityStateWatcherInterface* watcher) override {
auto it = watcher_map_.find(watcher);
GPR_ASSERT(it != watcher_map_.end());
subchannel_->CancelConnectivityStateWatch(health_check_service_name_.get(),
it->second);
watcher_map_.erase(it);
}
void AttemptToConnect() override { subchannel_->AttemptToConnect(); }
void ResetBackoff() override { subchannel_->ResetBackoff(); }
const grpc_channel_args* channel_args() override {
return subchannel_->channel_args();
}
// Caller must be holding the control-plane combiner.
ConnectedSubchannel* connected_subchannel() const {
return connected_subchannel_.get();
}
// Caller must be holding the data-plane combiner.
ConnectedSubchannel* connected_subchannel_in_data_plane() const {
return connected_subchannel_in_data_plane_.get();
}
void set_connected_subchannel_in_data_plane(
RefCountedPtr<ConnectedSubchannel> connected_subchannel) {
connected_subchannel_in_data_plane_ = std::move(connected_subchannel);
}
private:
// Subchannel and SubchannelInterface have different interfaces for
// their respective ConnectivityStateWatcherInterface classes.
// The one in Subchannel updates the ConnectedSubchannel along with
// the state, whereas the one in SubchannelInterface does not expose
// the ConnectedSubchannel.
//
// This wrapper provides a bridge between the two. It implements
// Subchannel::ConnectivityStateWatcherInterface and wraps
// the instance of SubchannelInterface::ConnectivityStateWatcherInterface
// that was passed in by the LB policy. We pass an instance of this
// class to the underlying Subchannel, and when we get updates from
// the subchannel, we pass those on to the wrapped watcher to return
// the update to the LB policy. This allows us to set the connected
// subchannel before passing the result back to the LB policy.
class WatcherWrapper : public Subchannel::ConnectivityStateWatcherInterface {
public:
WatcherWrapper(
UniquePtr<SubchannelInterface::ConnectivityStateWatcherInterface>
watcher,
RefCountedPtr<SubchannelWrapper> parent)
: watcher_(std::move(watcher)), parent_(std::move(parent)) {}
~WatcherWrapper() { parent_.reset(DEBUG_LOCATION, "WatcherWrapper"); }
void Orphan() override { Unref(); }
void OnConnectivityStateChange(
grpc_connectivity_state new_state,
RefCountedPtr<ConnectedSubchannel> connected_subchannel) override {
if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
gpr_log(GPR_INFO,
"chand=%p: connectivity change for subchannel wrapper %p "
"subchannel %p (connected_subchannel=%p state=%s); "
"hopping into combiner",
parent_->chand_, parent_.get(), parent_->subchannel_,
connected_subchannel.get(),
grpc_connectivity_state_name(new_state));
}
// Will delete itself.
New<Updater>(Ref(), new_state, std::move(connected_subchannel));
}
grpc_pollset_set* interested_parties() override {
return watcher_->interested_parties();
}
private:
class Updater {
public:
Updater(RefCountedPtr<WatcherWrapper> parent,
grpc_connectivity_state new_state,
RefCountedPtr<ConnectedSubchannel> connected_subchannel)
: parent_(std::move(parent)),
state_(new_state),
connected_subchannel_(std::move(connected_subchannel)) {
GRPC_CLOSURE_INIT(
&closure_, ApplyUpdateInControlPlaneCombiner, this,
grpc_combiner_scheduler(parent_->parent_->chand_->combiner_));
GRPC_CLOSURE_SCHED(&closure_, GRPC_ERROR_NONE);
}
private:
static void ApplyUpdateInControlPlaneCombiner(void* arg,
grpc_error* error) {
Updater* self = static_cast<Updater*>(arg);
if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
gpr_log(GPR_INFO,
"chand=%p: processing connectivity change in combiner "
"for subchannel wrapper %p subchannel %p "
"(connected_subchannel=%p state=%s)",
self->parent_->parent_->chand_, self->parent_->parent_.get(),
self->parent_->parent_->subchannel_,
self->connected_subchannel_.get(),
grpc_connectivity_state_name(self->state_));
}
self->parent_->parent_->MaybeUpdateConnectedSubchannel(
std::move(self->connected_subchannel_));
self->parent_->watcher_->OnConnectivityStateChange(self->state_);
Delete(self);
}
RefCountedPtr<WatcherWrapper> parent_;
grpc_connectivity_state state_;
RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
grpc_closure closure_;
};
UniquePtr<SubchannelInterface::ConnectivityStateWatcherInterface> watcher_;
RefCountedPtr<SubchannelWrapper> parent_;
};
void MaybeUpdateConnectedSubchannel(
RefCountedPtr<ConnectedSubchannel> connected_subchannel) {
// Update the connected subchannel only if the channel is not shutting
// down. This is because once the channel is shutting down, we
// ignore picker updates from the LB policy, which means that
// ConnectivityStateAndPickerSetter will never process the entries
// in chand_->pending_subchannel_updates_. So we don't want to add
// entries there that will never be processed, since that would
// leave dangling refs to the channel and prevent its destruction.
grpc_error* disconnect_error = chand_->disconnect_error();
if (disconnect_error != GRPC_ERROR_NONE) return;
// Not shutting down, so do the update.
if (connected_subchannel_ != connected_subchannel) {
connected_subchannel_ = std::move(connected_subchannel);
// Record the new connected subchannel so that it can be updated
// in the data plane combiner the next time the picker is updated.
chand_->pending_subchannel_updates_[Ref(
DEBUG_LOCATION, "ConnectedSubchannelUpdate")] = connected_subchannel_;
}
}
ChannelData* chand_;
Subchannel* subchannel_;
UniquePtr<char> health_check_service_name_;
// Maps from the address of the watcher passed to us by the LB policy
// to the address of the WrapperWatcher that we passed to the underlying
// subchannel. This is needed so that when the LB policy calls
// CancelConnectivityStateWatch() with its watcher, we know the
// corresponding WrapperWatcher to cancel on the underlying subchannel.
Map<ConnectivityStateWatcherInterface*, WatcherWrapper*> watcher_map_;
// To be accessed only in the control plane combiner.
RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
// To be accessed only in the data plane combiner.
RefCountedPtr<ConnectedSubchannel> connected_subchannel_in_data_plane_;
};
//
// ChannelData::ConnectivityStateAndPickerSetter
//
@ -735,15 +974,19 @@ class ChannelData::ConnectivityStateAndPickerSetter {
// Update connectivity state here, while holding control plane combiner.
grpc_connectivity_state_set(&chand->state_tracker_, state, reason);
if (chand->channelz_node_ != nullptr) {
chand->channelz_node_->SetConnectivityState(state);
chand->channelz_node_->AddTraceEvent(
channelz::ChannelTrace::Severity::Info,
grpc_slice_from_static_string(
GetChannelConnectivityStateChangeString(state)));
}
// Grab any pending subchannel updates.
pending_subchannel_updates_ =
std::move(chand_->pending_subchannel_updates_);
// Bounce into the data plane combiner to reset the picker.
GRPC_CHANNEL_STACK_REF(chand->owning_stack_,
"ConnectivityStateAndPickerSetter");
GRPC_CLOSURE_INIT(&closure_, SetPicker, this,
GRPC_CLOSURE_INIT(&closure_, SetPickerInDataPlane, this,
grpc_combiner_scheduler(chand->data_plane_combiner_));
GRPC_CLOSURE_SCHED(&closure_, GRPC_ERROR_NONE);
}
@ -766,16 +1009,38 @@ class ChannelData::ConnectivityStateAndPickerSetter {
GPR_UNREACHABLE_CODE(return "UNKNOWN");
}
static void SetPicker(void* arg, grpc_error* ignored) {
static void SetPickerInDataPlane(void* arg, grpc_error* ignored) {
auto* self = static_cast<ConnectivityStateAndPickerSetter*>(arg);
// Update picker.
self->chand_->picker_ = std::move(self->picker_);
// Handle subchannel updates.
for (auto& p : self->pending_subchannel_updates_) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
gpr_log(GPR_INFO,
"chand=%p: updating subchannel wrapper %p data plane "
"connected_subchannel to %p",
self->chand_, p.first.get(), p.second.get());
}
p.first->set_connected_subchannel_in_data_plane(std::move(p.second));
}
// Swap out the picker. We hang on to the old picker so that it can
// be deleted in the control-plane combiner, since that's where we need
// to unref the subchannel wrappers that are reffed by the picker.
self->picker_.swap(self->chand_->picker_);
// Re-process queued picks.
for (QueuedPick* pick = self->chand_->queued_picks_; pick != nullptr;
pick = pick->next) {
CallData::StartPickLocked(pick->elem, GRPC_ERROR_NONE);
}
// Clean up.
// Pop back into the control plane combiner to delete ourself, so
// that we make sure to unref subchannel wrappers there. This
// includes both the ones reffed by the old picker (now stored in
// self->picker_) and the ones in self->pending_subchannel_updates_.
GRPC_CLOSURE_INIT(&self->closure_, CleanUpInControlPlane, self,
grpc_combiner_scheduler(self->chand_->combiner_));
GRPC_CLOSURE_SCHED(&self->closure_, GRPC_ERROR_NONE);
}
static void CleanUpInControlPlane(void* arg, grpc_error* ignored) {
auto* self = static_cast<ConnectivityStateAndPickerSetter*>(arg);
GRPC_CHANNEL_STACK_UNREF(self->chand_->owning_stack_,
"ConnectivityStateAndPickerSetter");
Delete(self);
@ -783,6 +1048,9 @@ class ChannelData::ConnectivityStateAndPickerSetter {
ChannelData* chand_;
UniquePtr<LoadBalancingPolicy::SubchannelPicker> picker_;
Map<RefCountedPtr<SubchannelWrapper>, RefCountedPtr<ConnectedSubchannel>,
RefCountedPtrLess<SubchannelWrapper>>
pending_subchannel_updates_;
grpc_closure closure_;
};
@ -957,65 +1225,6 @@ void ChannelData::ExternalConnectivityWatcher::WatchConnectivityStateLocked(
&self->chand_->state_tracker_, self->state_, &self->my_closure_);
}
//
// ChannelData::GrpcSubchannel
//
// This class is a wrapper for Subchannel that hides details of the
// channel's implementation (such as the health check service name) from
// the LB policy API.
//
// Note that no synchronization is needed here, because even if the
// underlying subchannel is shared between channels, this wrapper will only
// be used within one channel, so it will always be synchronized by the
// control plane combiner.
class ChannelData::GrpcSubchannel : public SubchannelInterface {
public:
GrpcSubchannel(Subchannel* subchannel,
UniquePtr<char> health_check_service_name)
: subchannel_(subchannel),
health_check_service_name_(std::move(health_check_service_name)) {}
~GrpcSubchannel() { GRPC_SUBCHANNEL_UNREF(subchannel_, "unref from LB"); }
grpc_connectivity_state CheckConnectivityState(
RefCountedPtr<ConnectedSubchannelInterface>* connected_subchannel)
override {
RefCountedPtr<ConnectedSubchannel> tmp;
auto retval = subchannel_->CheckConnectivityState(
health_check_service_name_.get(), &tmp);
*connected_subchannel = std::move(tmp);
return retval;
}
void WatchConnectivityState(
grpc_connectivity_state initial_state,
UniquePtr<ConnectivityStateWatcher> watcher) override {
subchannel_->WatchConnectivityState(
initial_state,
UniquePtr<char>(gpr_strdup(health_check_service_name_.get())),
std::move(watcher));
}
void CancelConnectivityStateWatch(
ConnectivityStateWatcher* watcher) override {
subchannel_->CancelConnectivityStateWatch(health_check_service_name_.get(),
watcher);
}
void AttemptToConnect() override { subchannel_->AttemptToConnect(); }
channelz::SubchannelNode* channelz_node() override {
return subchannel_->channelz_node();
}
void ResetBackoff() override { subchannel_->ResetBackoff(); }
private:
Subchannel* subchannel_;
UniquePtr<char> health_check_service_name_;
};
//
// ChannelData::ClientChannelControlHelper
//
@ -1041,7 +1250,10 @@ class ChannelData::ClientChannelControlHelper
health_check_service_name.reset(
gpr_strdup(chand_->health_check_service_name_.get()));
}
static const char* args_to_remove[] = {GRPC_ARG_INHIBIT_HEALTH_CHECKING};
static const char* args_to_remove[] = {
GRPC_ARG_INHIBIT_HEALTH_CHECKING,
GRPC_ARG_CHANNELZ_CHANNEL_NODE,
};
grpc_arg arg = SubchannelPoolInterface::CreateChannelArg(
chand_->subchannel_pool_.get());
grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove(
@ -1050,8 +1262,8 @@ class ChannelData::ClientChannelControlHelper
chand_->client_channel_factory_->CreateSubchannel(new_args);
grpc_channel_args_destroy(new_args);
if (subchannel == nullptr) return nullptr;
return MakeRefCounted<GrpcSubchannel>(subchannel,
std::move(health_check_service_name));
return MakeRefCounted<SubchannelWrapper>(
chand_, subchannel, std::move(health_check_service_name));
}
grpc_channel* CreateChannel(const char* target,
@ -1062,8 +1274,7 @@ class ChannelData::ClientChannelControlHelper
void UpdateState(
grpc_connectivity_state state,
UniquePtr<LoadBalancingPolicy::SubchannelPicker> picker) override {
grpc_error* disconnect_error =
chand_->disconnect_error_.Load(MemoryOrder::ACQUIRE);
grpc_error* disconnect_error = chand_->disconnect_error();
if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
const char* extra = disconnect_error == GRPC_ERROR_NONE
? ""
@ -1082,7 +1293,22 @@ class ChannelData::ClientChannelControlHelper
// No-op -- we should never get this from ResolvingLoadBalancingPolicy.
void RequestReresolution() override {}
void AddTraceEvent(TraceSeverity severity, const char* message) override {
if (chand_->channelz_node_ != nullptr) {
chand_->channelz_node_->AddTraceEvent(
ConvertSeverityEnum(severity),
grpc_slice_from_copied_string(message));
}
}
private:
static channelz::ChannelTrace::Severity ConvertSeverityEnum(
TraceSeverity severity) {
if (severity == TRACE_INFO) return channelz::ChannelTrace::Info;
if (severity == TRACE_WARNING) return channelz::ChannelTrace::Warning;
return channelz::ChannelTrace::Error;
}
ChannelData* chand_;
};
@ -1125,6 +1351,15 @@ RefCountedPtr<SubchannelPoolInterface> GetSubchannelPool(
return GlobalSubchannelPool::instance();
}
channelz::ChannelNode* GetChannelzNode(const grpc_channel_args* args) {
const grpc_arg* arg =
grpc_channel_args_find(args, GRPC_ARG_CHANNELZ_CHANNEL_NODE);
if (arg != nullptr && arg->type == GRPC_ARG_POINTER) {
return static_cast<channelz::ChannelNode*>(arg->value.pointer.p);
}
return nullptr;
}
ChannelData::ChannelData(grpc_channel_element_args* args, grpc_error** error)
: deadline_checking_enabled_(
grpc_deadline_checking_enabled(args->channel_args)),
@ -1134,11 +1369,16 @@ ChannelData::ChannelData(grpc_channel_element_args* args, grpc_error** error)
owning_stack_(args->channel_stack),
client_channel_factory_(
ClientChannelFactory::GetFromChannelArgs(args->channel_args)),
channelz_node_(GetChannelzNode(args->channel_args)),
data_plane_combiner_(grpc_combiner_create()),
combiner_(grpc_combiner_create()),
interested_parties_(grpc_pollset_set_create()),
subchannel_pool_(GetSubchannelPool(args->channel_args)),
disconnect_error_(GRPC_ERROR_NONE) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
gpr_log(GPR_INFO, "chand=%p: creating client_channel for channel stack %p",
this, owning_stack_);
}
// Initialize data members.
grpc_connectivity_state_init(&state_tracker_, GRPC_CHANNEL_IDLE,
"client_channel");
@ -1195,10 +1435,8 @@ ChannelData::ChannelData(grpc_channel_element_args* args, grpc_error** error)
std::move(target_uri), ProcessResolverResultLocked, this, error));
grpc_channel_args_destroy(new_args);
if (*error != GRPC_ERROR_NONE) {
// Orphan the resolving LB policy and flush the exec_ctx to ensure
// that it finishes shutting down. This ensures that if we are
// failing, we destroy the ClientChannelControlHelper (and thus
// unref the channel stack) before we return.
// Before we return, shut down the resolving LB policy, which destroys
// the ClientChannelControlHelper and therefore unrefs the channel stack.
// TODO(roth): This is not a complete solution, because it only
// catches the case where channel stack initialization fails in this
// particular filter. If there is a failure in a different filter, we
@ -1206,7 +1444,6 @@ ChannelData::ChannelData(grpc_channel_element_args* args, grpc_error** error)
// in practice, there are no other filters that can cause failures in
// channel stack initialization, so this works for now.
resolving_lb_policy_.reset();
ExecCtx::Get()->Flush();
} else {
grpc_pollset_set_add_pollset_set(resolving_lb_policy_->interested_parties(),
interested_parties_);
@ -1218,6 +1455,9 @@ ChannelData::ChannelData(grpc_channel_element_args* args, grpc_error** error)
}
ChannelData::~ChannelData() {
if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
gpr_log(GPR_INFO, "chand=%p: destroying channel", this);
}
if (resolving_lb_policy_ != nullptr) {
grpc_pollset_set_del_pollset_set(resolving_lb_policy_->interested_parties(),
interested_parties_);
@ -1403,9 +1643,13 @@ grpc_error* ChannelData::DoPingLocked(grpc_transport_op* op) {
}
LoadBalancingPolicy::PickResult result =
picker_->Pick(LoadBalancingPolicy::PickArgs());
if (result.connected_subchannel != nullptr) {
ConnectedSubchannel* connected_subchannel =
static_cast<ConnectedSubchannel*>(result.connected_subchannel.get());
ConnectedSubchannel* connected_subchannel = nullptr;
if (result.subchannel != nullptr) {
SubchannelWrapper* subchannel =
static_cast<SubchannelWrapper*>(result.subchannel.get());
connected_subchannel = subchannel->connected_subchannel();
}
if (connected_subchannel != nullptr) {
connected_subchannel->Ping(op->send_ping.on_initiate, op->send_ping.on_ack);
} else {
if (result.error == GRPC_ERROR_NONE) {
@ -1448,6 +1692,10 @@ void ChannelData::StartTransportOpLocked(void* arg, grpc_error* ignored) {
}
// Disconnect.
if (op->disconnect_with_error != GRPC_ERROR_NONE) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) {
gpr_log(GPR_INFO, "chand=%p: channel shut down from API: %s", chand,
grpc_error_string(op->disconnect_with_error));
}
grpc_error* error = GRPC_ERROR_NONE;
GPR_ASSERT(chand->disconnect_error_.CompareExchangeStrong(
&error, op->disconnect_with_error, MemoryOrder::ACQ_REL,
@ -1522,6 +1770,17 @@ void ChannelData::RemoveQueuedPick(QueuedPick* to_remove,
}
}
RefCountedPtr<ConnectedSubchannel>
ChannelData::GetConnectedSubchannelInDataPlane(
SubchannelInterface* subchannel) const {
SubchannelWrapper* subchannel_wrapper =
static_cast<SubchannelWrapper*>(subchannel);
ConnectedSubchannel* connected_subchannel =
subchannel_wrapper->connected_subchannel_in_data_plane();
if (connected_subchannel == nullptr) return nullptr;
return connected_subchannel->Ref();
}
void ChannelData::TryToConnectLocked(void* arg, grpc_error* error_ignored) {
auto* chand = static_cast<ChannelData*>(arg);
if (chand->resolving_lb_policy_ != nullptr) {
@ -3449,10 +3708,9 @@ void CallData::StartPickLocked(void* arg, grpc_error* error) {
auto result = chand->picker()->Pick(pick_args);
if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
gpr_log(GPR_INFO,
"chand=%p calld=%p: LB pick returned %s (connected_subchannel=%p, "
"error=%s)",
"chand=%p calld=%p: LB pick returned %s (subchannel=%p, error=%s)",
chand, calld, PickResultTypeName(result.type),
result.connected_subchannel.get(), grpc_error_string(result.error));
result.subchannel.get(), grpc_error_string(result.error));
}
switch (result.type) {
case LoadBalancingPolicy::PickResult::PICK_TRANSIENT_FAILURE: {
@ -3494,11 +3752,16 @@ void CallData::StartPickLocked(void* arg, grpc_error* error) {
break;
default: // PICK_COMPLETE
// Handle drops.
if (GPR_UNLIKELY(result.connected_subchannel == nullptr)) {
if (GPR_UNLIKELY(result.subchannel == nullptr)) {
result.error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Call dropped by load balancing policy");
} else {
// Grab a ref to the connected subchannel while we're still
// holding the data plane combiner.
calld->connected_subchannel_ =
chand->GetConnectedSubchannelInDataPlane(result.subchannel.get());
GPR_ASSERT(calld->connected_subchannel_ != nullptr);
}
calld->connected_subchannel_ = std::move(result.connected_subchannel);
calld->lb_recv_trailing_metadata_ready_ =
result.recv_trailing_metadata_ready;
calld->lb_recv_trailing_metadata_ready_user_data_ =
@ -3532,20 +3795,6 @@ const grpc_channel_filter grpc_client_channel_filter = {
"client-channel",
};
void grpc_client_channel_set_channelz_node(
grpc_channel_element* elem, grpc_core::channelz::ClientChannelNode* node) {
auto* chand = static_cast<ChannelData*>(elem->channel_data);
chand->set_channelz_node(node);
}
void grpc_client_channel_populate_child_refs(
grpc_channel_element* elem,
grpc_core::channelz::ChildRefsList* child_subchannels,
grpc_core::channelz::ChildRefsList* child_channels) {
auto* chand = static_cast<ChannelData*>(elem->channel_data);
chand->FillChildRefsForChannelz(child_subchannels, child_channels);
}
grpc_connectivity_state grpc_client_channel_check_connectivity_state(
grpc_channel_element* elem, int try_to_connect) {
auto* chand = static_cast<ChannelData*>(elem->channel_data);

@ -40,14 +40,6 @@ extern grpc_core::TraceFlag grpc_client_channel_trace;
extern const grpc_channel_filter grpc_client_channel_filter;
void grpc_client_channel_set_channelz_node(
grpc_channel_element* elem, grpc_core::channelz::ClientChannelNode* node);
void grpc_client_channel_populate_child_refs(
grpc_channel_element* elem,
grpc_core::channelz::ChildRefsList* child_subchannels,
grpc_core::channelz::ChildRefsList* child_channels);
grpc_connectivity_state grpc_client_channel_check_connectivity_state(
grpc_channel_element* elem, int try_to_connect);

@ -29,89 +29,6 @@
namespace grpc_core {
namespace channelz {
namespace {
void* client_channel_channelz_copy(void* p) { return p; }
void client_channel_channelz_destroy(void* p) {}
int client_channel_channelz_cmp(void* a, void* b) { return GPR_ICMP(a, b); }
} // namespace
static const grpc_arg_pointer_vtable client_channel_channelz_vtable = {
client_channel_channelz_copy, client_channel_channelz_destroy,
client_channel_channelz_cmp};
ClientChannelNode::ClientChannelNode(grpc_channel* channel,
size_t channel_tracer_max_nodes,
bool is_top_level_channel)
: ChannelNode(channel, channel_tracer_max_nodes, is_top_level_channel) {
client_channel_ =
grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel));
GPR_ASSERT(client_channel_->filter == &grpc_client_channel_filter);
grpc_client_channel_set_channelz_node(client_channel_, this);
}
void ClientChannelNode::PopulateConnectivityState(grpc_json* json) {
grpc_connectivity_state state;
if (ChannelIsDestroyed()) {
state = GRPC_CHANNEL_SHUTDOWN;
} else {
state =
grpc_client_channel_check_connectivity_state(client_channel_, false);
}
json = grpc_json_create_child(nullptr, json, "state", nullptr,
GRPC_JSON_OBJECT, false);
grpc_json_create_child(nullptr, json, "state",
grpc_connectivity_state_name(state), GRPC_JSON_STRING,
false);
}
void ClientChannelNode::PopulateChildRefs(grpc_json* json) {
ChildRefsList child_subchannels;
ChildRefsList child_channels;
grpc_json* json_iterator = nullptr;
grpc_client_channel_populate_child_refs(client_channel_, &child_subchannels,
&child_channels);
if (!child_subchannels.empty()) {
grpc_json* array_parent = grpc_json_create_child(
nullptr, json, "subchannelRef", nullptr, GRPC_JSON_ARRAY, false);
for (size_t i = 0; i < child_subchannels.size(); ++i) {
json_iterator =
grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr,
GRPC_JSON_OBJECT, false);
grpc_json_add_number_string_child(json_iterator, nullptr, "subchannelId",
child_subchannels[i]);
}
}
if (!child_channels.empty()) {
grpc_json* array_parent = grpc_json_create_child(
nullptr, json, "channelRef", nullptr, GRPC_JSON_ARRAY, false);
json_iterator = nullptr;
for (size_t i = 0; i < child_channels.size(); ++i) {
json_iterator =
grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr,
GRPC_JSON_OBJECT, false);
grpc_json_add_number_string_child(json_iterator, nullptr, "channelId",
child_channels[i]);
}
}
}
grpc_arg ClientChannelNode::CreateChannelArg() {
return grpc_channel_arg_pointer_create(
const_cast<char*>(GRPC_ARG_CHANNELZ_CHANNEL_NODE_CREATION_FUNC),
reinterpret_cast<void*>(MakeClientChannelNode),
&client_channel_channelz_vtable);
}
RefCountedPtr<ChannelNode> ClientChannelNode::MakeClientChannelNode(
grpc_channel* channel, size_t channel_tracer_max_nodes,
bool is_top_level_channel) {
return MakeRefCounted<ClientChannelNode>(channel, channel_tracer_max_nodes,
is_top_level_channel);
}
SubchannelNode::SubchannelNode(Subchannel* subchannel,
size_t channel_tracer_max_nodes)

@ -32,32 +32,6 @@ class Subchannel;
namespace channelz {
// Subtype of ChannelNode that overrides and provides client_channel specific
// functionality like querying for connectivity_state and subchannel data.
class ClientChannelNode : public ChannelNode {
public:
static RefCountedPtr<ChannelNode> MakeClientChannelNode(
grpc_channel* channel, size_t channel_tracer_max_nodes,
bool is_top_level_channel);
ClientChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes,
bool is_top_level_channel);
virtual ~ClientChannelNode() {}
// Overriding template methods from ChannelNode to render information that
// only ClientChannelNode knows about.
void PopulateConnectivityState(grpc_json* json) override;
void PopulateChildRefs(grpc_json* json) override;
// Helper to create a channel arg to ensure this type of ChannelNode is
// created.
static grpc_arg CreateChannelArg();
private:
grpc_channel_element* client_channel_;
};
// Handles channelz bookkeeping for sockets
class SubchannelNode : public BaseNode {
public:
SubchannelNode(Subchannel* subchannel, size_t channel_tracer_max_nodes);
@ -85,12 +59,12 @@ class SubchannelNode : public BaseNode {
void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); }
private:
void PopulateConnectivityState(grpc_json* json);
Subchannel* subchannel_;
UniquePtr<char> target_;
CallCountingHelper call_counter_;
ChannelTrace trace_;
void PopulateConnectivityState(grpc_json* json);
};
} // namespace channelz

@ -38,14 +38,6 @@
#include "src/core/lib/surface/channel_init.h"
static bool append_filter(grpc_channel_stack_builder* builder, void* arg) {
const grpc_channel_args* args =
grpc_channel_stack_builder_get_channel_arguments(builder);
grpc_arg args_to_add[] = {
grpc_core::channelz::ClientChannelNode::CreateChannelArg()};
grpc_channel_args* new_args = grpc_channel_args_copy_and_add(
args, args_to_add, GPR_ARRAY_SIZE(args_to_add));
grpc_channel_stack_builder_set_channel_arguments(builder, new_args);
grpc_channel_args_destroy(new_args);
return grpc_channel_stack_builder_append_filter(
builder, static_cast<const grpc_channel_filter*>(arg), nullptr, nullptr);
}

@ -43,23 +43,8 @@ LoadBalancingPolicy::~LoadBalancingPolicy() {
}
void LoadBalancingPolicy::Orphan() {
// Invoke ShutdownAndUnrefLocked() inside of the combiner.
// TODO(roth): Is this actually needed? We should already be in the
// combiner here. Note that if we directly call ShutdownLocked(),
// then we can probably remove the hack whereby the helper is
// destroyed at shutdown instead of at destruction.
GRPC_CLOSURE_SCHED(
GRPC_CLOSURE_CREATE(&LoadBalancingPolicy::ShutdownAndUnrefLocked, this,
grpc_combiner_scheduler(combiner_)),
GRPC_ERROR_NONE);
}
void LoadBalancingPolicy::ShutdownAndUnrefLocked(void* arg,
grpc_error* ignored) {
LoadBalancingPolicy* policy = static_cast<LoadBalancingPolicy*>(arg);
policy->ShutdownLocked();
policy->channel_control_helper_.reset();
policy->Unref();
ShutdownLocked();
Unref();
}
//

@ -21,7 +21,6 @@
#include <grpc/support/port_platform.h>
#include "src/core/ext/filters/client_channel/client_channel_channelz.h"
#include "src/core/ext/filters/client_channel/server_address.h"
#include "src/core/ext/filters/client_channel/service_config.h"
#include "src/core/ext/filters/client_channel/subchannel_interface.h"
@ -31,6 +30,7 @@
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/metadata_batch.h"
namespace grpc_core {
@ -128,7 +128,7 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
/// Used only if type is PICK_COMPLETE. Will be set to the selected
/// subchannel, or nullptr if the LB policy decides to drop the call.
RefCountedPtr<ConnectedSubchannelInterface> connected_subchannel;
RefCountedPtr<SubchannelInterface> subchannel;
/// Used only if type is PICK_TRANSIENT_FAILURE.
/// Error to be set when returning a transient failure.
@ -201,6 +201,12 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
/// Requests that the resolver re-resolve.
virtual void RequestReresolution() GRPC_ABSTRACT;
/// Adds a trace message associated with the channel.
/// Does NOT take ownership of \a message.
enum TraceSeverity { TRACE_INFO, TRACE_WARNING, TRACE_ERROR };
virtual void AddTraceEvent(TraceSeverity severity,
const char* message) GRPC_ABSTRACT;
GRPC_ABSTRACT_BASE_CLASS
};
@ -274,22 +280,9 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
/// Resets connection backoff.
virtual void ResetBackoffLocked() GRPC_ABSTRACT;
/// Populates child_subchannels and child_channels with the uuids of this
/// LB policy's referenced children.
///
/// This is not invoked from the client_channel's combiner. The
/// implementation is responsible for providing its own synchronization.
virtual void FillChildRefsForChannelz(
channelz::ChildRefsList* child_subchannels,
channelz::ChildRefsList* child_channels) GRPC_ABSTRACT;
void set_channelz_node(
RefCountedPtr<channelz::ClientChannelNode> channelz_node) {
channelz_node_ = std::move(channelz_node);
}
grpc_pollset_set* interested_parties() const { return interested_parties_; }
// Note: This must be invoked while holding the combiner.
void Orphan() override;
// A picker that returns PICK_QUEUE for all picks.
@ -300,6 +293,8 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
explicit QueuePicker(RefCountedPtr<LoadBalancingPolicy> parent)
: parent_(std::move(parent)) {}
~QueuePicker() { parent_.reset(DEBUG_LOCATION, "QueuePicker"); }
PickResult Pick(PickArgs args) override;
private:
@ -328,29 +323,20 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
// Note: LB policies MUST NOT call any method on the helper from their
// constructor.
// Note: This will return null after ShutdownLocked() has been called.
ChannelControlHelper* channel_control_helper() const {
return channel_control_helper_.get();
}
channelz::ClientChannelNode* channelz_node() const {
return channelz_node_.get();
}
/// Shuts down the policy.
virtual void ShutdownLocked() GRPC_ABSTRACT;
private:
static void ShutdownAndUnrefLocked(void* arg, grpc_error* ignored);
/// Combiner under which LB policy actions take place.
grpc_combiner* combiner_;
/// Owned pointer to interested parties in load balancing decisions.
grpc_pollset_set* interested_parties_;
/// Channel control helper.
UniquePtr<ChannelControlHelper> channel_control_helper_;
/// Channelz node.
RefCountedPtr<channelz::ClientChannelNode> channelz_node_;
};
} // namespace grpc_core

@ -141,9 +141,6 @@ class GrpcLb : public LoadBalancingPolicy {
void UpdateLocked(UpdateArgs args) override;
void ResetBackoffLocked() override;
void FillChildRefsForChannelz(
channelz::ChildRefsList* child_subchannels,
channelz::ChildRefsList* child_channels) override;
private:
/// Contains a call to the LB server and all the data related to the call.
@ -300,6 +297,7 @@ class GrpcLb : public LoadBalancingPolicy {
void UpdateState(grpc_connectivity_state state,
UniquePtr<SubchannelPicker> picker) override;
void RequestReresolution() override;
void AddTraceEvent(TraceSeverity severity, const char* message) override;
void set_child(LoadBalancingPolicy* child) { child_ = child; }
@ -349,8 +347,6 @@ class GrpcLb : public LoadBalancingPolicy {
// The channel for communicating with the LB server.
grpc_channel* lb_channel_ = nullptr;
// Uuid of the lb channel. Used for channelz.
gpr_atm lb_channel_uuid_ = 0;
// Response generator to inject address updates into lb_channel_.
RefCountedPtr<FakeResolverResponseGenerator> response_generator_;
@ -386,9 +382,6 @@ class GrpcLb : public LoadBalancingPolicy {
grpc_connectivity_state lb_channel_connectivity_ = GRPC_CHANNEL_IDLE;
grpc_closure lb_channel_on_connectivity_changed_;
// Lock held when modifying the value of child_policy_ or
// pending_child_policy_.
gpr_mu child_policy_mu_;
// The child policy to use for the backends.
OrphanablePtr<LoadBalancingPolicy> child_policy_;
// When switching child policies, the new policy will be stored here
@ -582,13 +575,12 @@ GrpcLb::PickResult GrpcLb::Picker::Pick(PickArgs args) {
result = child_picker_->Pick(args);
// If pick succeeded, add LB token to initial metadata.
if (result.type == PickResult::PICK_COMPLETE &&
result.connected_subchannel != nullptr) {
result.subchannel != nullptr) {
const grpc_arg* arg = grpc_channel_args_find(
result.connected_subchannel->args(), GRPC_ARG_GRPCLB_ADDRESS_LB_TOKEN);
result.subchannel->channel_args(), GRPC_ARG_GRPCLB_ADDRESS_LB_TOKEN);
if (arg == nullptr) {
gpr_log(GPR_ERROR,
"[grpclb %p picker %p] No LB token for connected subchannel %p",
parent_, this, result.connected_subchannel.get());
gpr_log(GPR_ERROR, "[grpclb %p picker %p] No LB token for subchannel %p",
parent_, this, result.subchannel.get());
abort();
}
grpc_mdelem lb_token = {reinterpret_cast<uintptr_t>(arg->value.pointer.p)};
@ -655,7 +647,6 @@ void GrpcLb::Helper::UpdateState(grpc_connectivity_state state,
grpc_pollset_set_del_pollset_set(
parent_->child_policy_->interested_parties(),
parent_->interested_parties());
MutexLock lock(&parent_->child_policy_mu_);
parent_->child_policy_ = std::move(parent_->pending_child_policy_);
} else if (!CalledByCurrentChild()) {
// This request is from an outdated child, so ignore it.
@ -735,6 +726,15 @@ void GrpcLb::Helper::RequestReresolution() {
}
}
void GrpcLb::Helper::AddTraceEvent(TraceSeverity severity,
const char* message) {
if (parent_->shutting_down_ ||
(!CalledByPendingChild() && !CalledByCurrentChild())) {
return;
}
parent_->channel_control_helper()->AddTraceEvent(severity, message);
}
//
// GrpcLb::BalancerCallState
//
@ -1244,25 +1244,34 @@ grpc_channel_args* BuildBalancerChannelArgs(
// treated as a stand-alone channel and not inherit this argument from the
// args of the parent channel.
GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
// Don't want to pass down channelz node from parent; the balancer
// channel will get its own.
GRPC_ARG_CHANNELZ_CHANNEL_NODE,
};
// Channel args to add.
const grpc_arg args_to_add[] = {
// The fake resolver response generator, which we use to inject
// address updates into the LB channel.
InlinedVector<grpc_arg, 3> args_to_add;
// The fake resolver response generator, which we use to inject
// address updates into the LB channel.
args_to_add.emplace_back(
grpc_core::FakeResolverResponseGenerator::MakeChannelArg(
response_generator),
// A channel arg indicating the target is a grpclb load balancer.
grpc_channel_arg_integer_create(
const_cast<char*>(GRPC_ARG_ADDRESS_IS_GRPCLB_LOAD_BALANCER), 1),
// A channel arg indicating this is an internal channels, aka it is
// owned by components in Core, not by the user application.
grpc_channel_arg_integer_create(
const_cast<char*>(GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL), 1),
};
response_generator));
// A channel arg indicating the target is a grpclb load balancer.
args_to_add.emplace_back(grpc_channel_arg_integer_create(
const_cast<char*>(GRPC_ARG_ADDRESS_IS_GRPCLB_LOAD_BALANCER), 1));
// The parent channel's channelz uuid.
channelz::ChannelNode* channelz_node = nullptr;
const grpc_arg* arg =
grpc_channel_args_find(args, GRPC_ARG_CHANNELZ_CHANNEL_NODE);
if (arg != nullptr && arg->type == GRPC_ARG_POINTER &&
arg->value.pointer.p != nullptr) {
channelz_node = static_cast<channelz::ChannelNode*>(arg->value.pointer.p);
args_to_add.emplace_back(
channelz::MakeParentUuidArg(channelz_node->uuid()));
}
// Construct channel args.
grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove(
args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), args_to_add,
GPR_ARRAY_SIZE(args_to_add));
args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), args_to_add.data(),
args_to_add.size());
// Make any necessary modifications for security.
return grpc_lb_policy_grpclb_modify_lb_channel_args(addresses, new_args);
}
@ -1288,7 +1297,6 @@ GrpcLb::GrpcLb(Args args)
GRPC_CLOSURE_INIT(&lb_channel_on_connectivity_changed_,
&GrpcLb::OnBalancerChannelConnectivityChangedLocked, this,
grpc_combiner_scheduler(args.combiner));
gpr_mu_init(&child_policy_mu_);
// Record server name.
const grpc_arg* arg = grpc_channel_args_find(args.args, GRPC_ARG_SERVER_URI);
const char* server_uri = grpc_channel_arg_get_string(arg);
@ -1314,7 +1322,6 @@ GrpcLb::GrpcLb(Args args)
GrpcLb::~GrpcLb() {
gpr_free((void*)server_name_);
grpc_channel_args_destroy(args_);
gpr_mu_destroy(&child_policy_mu_);
}
void GrpcLb::ShutdownLocked() {
@ -1335,11 +1342,8 @@ void GrpcLb::ShutdownLocked() {
grpc_pollset_set_del_pollset_set(
pending_child_policy_->interested_parties(), interested_parties());
}
{
MutexLock lock(&child_policy_mu_);
child_policy_.reset();
pending_child_policy_.reset();
}
child_policy_.reset();
pending_child_policy_.reset();
// We destroy the LB channel here instead of in our destructor because
// destroying the channel triggers a last callback to
// OnBalancerChannelConnectivityChangedLocked(), and we need to be
@ -1347,7 +1351,6 @@ void GrpcLb::ShutdownLocked() {
if (lb_channel_ != nullptr) {
grpc_channel_destroy(lb_channel_);
lb_channel_ = nullptr;
gpr_atm_no_barrier_store(&lb_channel_uuid_, 0);
}
}
@ -1367,29 +1370,6 @@ void GrpcLb::ResetBackoffLocked() {
}
}
void GrpcLb::FillChildRefsForChannelz(
channelz::ChildRefsList* child_subchannels,
channelz::ChildRefsList* child_channels) {
{
// Delegate to the child policy to fill the children subchannels.
// This must be done holding child_policy_mu_, since this method
// does not run in the combiner.
MutexLock lock(&child_policy_mu_);
if (child_policy_ != nullptr) {
child_policy_->FillChildRefsForChannelz(child_subchannels,
child_channels);
}
if (pending_child_policy_ != nullptr) {
pending_child_policy_->FillChildRefsForChannelz(child_subchannels,
child_channels);
}
}
gpr_atm uuid = gpr_atm_no_barrier_load(&lb_channel_uuid_);
if (uuid != 0) {
child_channels->push_back(uuid);
}
}
void GrpcLb::UpdateLocked(UpdateArgs args) {
const bool is_initial_update = lb_channel_ == nullptr;
auto* grpclb_config =
@ -1472,11 +1452,6 @@ void GrpcLb::ProcessAddressesAndChannelArgsLocked(
lb_channel_ =
channel_control_helper()->CreateChannel(uri_str, *lb_channel_args);
GPR_ASSERT(lb_channel_ != nullptr);
grpc_core::channelz::ChannelNode* channel_node =
grpc_channel_get_channelz_node(lb_channel_);
if (channel_node != nullptr) {
gpr_atm_no_barrier_store(&lb_channel_uuid_, channel_node->uuid());
}
gpr_free(uri_str);
}
// Propagate updates to the LB channel (pick_first) through the fake
@ -1764,15 +1739,10 @@ void GrpcLb::CreateOrUpdateChildPolicyLocked() {
gpr_log(GPR_INFO, "[grpclb %p] Creating new %schild policy %s", this,
child_policy_ == nullptr ? "" : "pending ", child_policy_name);
}
auto new_policy =
CreateChildPolicyLocked(child_policy_name, update_args.args);
// Swap the policy into place.
auto& lb_policy =
child_policy_ == nullptr ? child_policy_ : pending_child_policy_;
{
MutexLock lock(&child_policy_mu_);
lb_policy = std::move(new_policy);
}
lb_policy = CreateChildPolicyLocked(child_policy_name, update_args.args);
policy_to_update = lb_policy.get();
} else {
// Cases 2a and 3a: update an existing policy.

@ -28,7 +28,6 @@
#include "src/core/ext/filters/client_channel/subchannel.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gprpp/sync.h"
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/transport/connectivity_state.h"
@ -53,8 +52,6 @@ class PickFirst : public LoadBalancingPolicy {
void UpdateLocked(UpdateArgs args) override;
void ExitIdleLocked() override;
void ResetBackoffLocked() override;
void FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels,
channelz::ChildRefsList* ignored) override;
private:
~PickFirst();
@ -87,9 +84,8 @@ class PickFirst : public LoadBalancingPolicy {
public:
PickFirstSubchannelList(PickFirst* policy, TraceFlag* tracer,
const ServerAddressList& addresses,
grpc_combiner* combiner,
const grpc_channel_args& args)
: SubchannelList(policy, tracer, addresses, combiner,
: SubchannelList(policy, tracer, addresses,
policy->channel_control_helper(), args) {
// Need to maintain a ref to the LB policy as long as we maintain
// any references to subchannels, since the subchannels'
@ -113,37 +109,22 @@ class PickFirst : public LoadBalancingPolicy {
class Picker : public SubchannelPicker {
public:
explicit Picker(
RefCountedPtr<ConnectedSubchannelInterface> connected_subchannel)
: connected_subchannel_(std::move(connected_subchannel)) {}
explicit Picker(RefCountedPtr<SubchannelInterface> subchannel)
: subchannel_(std::move(subchannel)) {}
PickResult Pick(PickArgs args) override {
PickResult result;
result.type = PickResult::PICK_COMPLETE;
result.connected_subchannel = connected_subchannel_;
result.subchannel = subchannel_;
return result;
}
private:
RefCountedPtr<ConnectedSubchannelInterface> connected_subchannel_;
};
// Helper class to ensure that any function that modifies the child refs
// data structures will update the channelz snapshot data structures before
// returning.
class AutoChildRefsUpdater {
public:
explicit AutoChildRefsUpdater(PickFirst* pf) : pf_(pf) {}
~AutoChildRefsUpdater() { pf_->UpdateChildRefsLocked(); }
private:
PickFirst* pf_;
RefCountedPtr<SubchannelInterface> subchannel_;
};
void ShutdownLocked() override;
void UpdateChildRefsLocked();
// All our subchannels.
OrphanablePtr<PickFirstSubchannelList> subchannel_list_;
// Latest pending subchannel list.
@ -154,12 +135,6 @@ class PickFirst : public LoadBalancingPolicy {
bool idle_ = false;
// Are we shut down?
bool shutdown_ = false;
/// Lock and data used to capture snapshots of this channels child
/// channels and subchannels. This data is consumed by channelz.
Mutex child_refs_mu_;
channelz::ChildRefsList child_subchannels_;
channelz::ChildRefsList child_channels_;
};
PickFirst::PickFirst(Args args) : LoadBalancingPolicy(std::move(args)) {
@ -177,7 +152,6 @@ PickFirst::~PickFirst() {
}
void PickFirst::ShutdownLocked() {
AutoChildRefsUpdater guard(this);
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) {
gpr_log(GPR_INFO, "Pick First %p Shutting down", this);
}
@ -189,6 +163,9 @@ void PickFirst::ShutdownLocked() {
void PickFirst::ExitIdleLocked() {
if (shutdown_) return;
if (idle_) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) {
gpr_log(GPR_INFO, "Pick First %p exiting idle", this);
}
idle_ = false;
if (subchannel_list_ == nullptr ||
subchannel_list_->num_subchannels() == 0) {
@ -212,42 +189,7 @@ void PickFirst::ResetBackoffLocked() {
}
}
void PickFirst::FillChildRefsForChannelz(
channelz::ChildRefsList* child_subchannels_to_fill,
channelz::ChildRefsList* ignored) {
MutexLock lock(&child_refs_mu_);
for (size_t i = 0; i < child_subchannels_.size(); ++i) {
// TODO(ncteisen): implement a de dup loop that is not O(n^2). Might
// have to implement lightweight set. For now, we don't care about
// performance when channelz requests are made.
bool found = false;
for (size_t j = 0; j < child_subchannels_to_fill->size(); ++j) {
if ((*child_subchannels_to_fill)[j] == child_subchannels_[i]) {
found = true;
break;
}
}
if (!found) {
child_subchannels_to_fill->push_back(child_subchannels_[i]);
}
}
}
void PickFirst::UpdateChildRefsLocked() {
channelz::ChildRefsList cs;
if (subchannel_list_ != nullptr) {
subchannel_list_->PopulateChildRefsList(&cs);
}
if (latest_pending_subchannel_list_ != nullptr) {
latest_pending_subchannel_list_->PopulateChildRefsList(&cs);
}
// atomically update the data that channelz will actually be looking at.
MutexLock lock(&child_refs_mu_);
child_subchannels_ = std::move(cs);
}
void PickFirst::UpdateLocked(UpdateArgs args) {
AutoChildRefsUpdater guard(this);
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) {
gpr_log(GPR_INFO,
"Pick First %p received update with %" PRIuPTR " addresses", this,
@ -258,7 +200,7 @@ void PickFirst::UpdateLocked(UpdateArgs args) {
grpc_channel_args* new_args =
grpc_channel_args_copy_and_add(args.args, &new_arg, 1);
auto subchannel_list = MakeOrphanable<PickFirstSubchannelList>(
this, &grpc_lb_pick_first_trace, args.addresses, combiner(), *new_args);
this, &grpc_lb_pick_first_trace, args.addresses, *new_args);
grpc_channel_args_destroy(new_args);
if (subchannel_list->num_subchannels() == 0) {
// Empty update or no valid subchannels. Unsubscribe from all current
@ -348,7 +290,6 @@ void PickFirst::UpdateLocked(UpdateArgs args) {
void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
grpc_connectivity_state connectivity_state) {
PickFirst* p = static_cast<PickFirst*>(subchannel_list()->policy());
AutoChildRefsUpdater guard(p);
// The notification must be for a subchannel in either the current or
// latest pending subchannel lists.
GPR_ASSERT(subchannel_list() == p->subchannel_list_.get() ||
@ -388,7 +329,8 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
} else {
p->channel_control_helper()->UpdateState(
GRPC_CHANNEL_CONNECTING,
UniquePtr<SubchannelPicker>(New<QueuePicker>(p->Ref())));
UniquePtr<SubchannelPicker>(
New<QueuePicker>(p->Ref(DEBUG_LOCATION, "QueuePicker"))));
}
} else {
if (connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
@ -401,20 +343,20 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
p->selected_ = nullptr;
CancelConnectivityWatchLocked("selected subchannel failed; going IDLE");
p->channel_control_helper()->UpdateState(
GRPC_CHANNEL_IDLE,
UniquePtr<SubchannelPicker>(New<QueuePicker>(p->Ref())));
GRPC_CHANNEL_IDLE, UniquePtr<SubchannelPicker>(New<QueuePicker>(
p->Ref(DEBUG_LOCATION, "QueuePicker"))));
} else {
// This is unlikely but can happen when a subchannel has been asked
// to reconnect by a different channel and this channel has dropped
// some connectivity state notifications.
if (connectivity_state == GRPC_CHANNEL_READY) {
p->channel_control_helper()->UpdateState(
GRPC_CHANNEL_READY, UniquePtr<SubchannelPicker>(New<Picker>(
connected_subchannel()->Ref())));
GRPC_CHANNEL_READY,
UniquePtr<SubchannelPicker>(New<Picker>(subchannel()->Ref())));
} else { // CONNECTING
p->channel_control_helper()->UpdateState(
connectivity_state,
UniquePtr<SubchannelPicker>(New<QueuePicker>(p->Ref())));
connectivity_state, UniquePtr<SubchannelPicker>(New<QueuePicker>(
p->Ref(DEBUG_LOCATION, "QueuePicker"))));
}
}
}
@ -470,7 +412,8 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
if (subchannel_list() == p->subchannel_list_.get()) {
p->channel_control_helper()->UpdateState(
GRPC_CHANNEL_CONNECTING,
UniquePtr<SubchannelPicker>(New<QueuePicker>(p->Ref())));
UniquePtr<SubchannelPicker>(
New<QueuePicker>(p->Ref(DEBUG_LOCATION, "QueuePicker"))));
}
break;
}
@ -504,13 +447,13 @@ void PickFirst::PickFirstSubchannelData::ProcessUnselectedReadyLocked() {
p->subchannel_list_ = std::move(p->latest_pending_subchannel_list_);
}
// Cases 1 and 2.
p->selected_ = this;
p->channel_control_helper()->UpdateState(
GRPC_CHANNEL_READY,
UniquePtr<SubchannelPicker>(New<Picker>(connected_subchannel()->Ref())));
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) {
gpr_log(GPR_INFO, "Pick First %p selected subchannel %p", p, subchannel());
}
p->selected_ = this;
p->channel_control_helper()->UpdateState(
GRPC_CHANNEL_READY,
UniquePtr<SubchannelPicker>(New<Picker>(subchannel()->Ref())));
}
void PickFirst::PickFirstSubchannelData::

@ -38,7 +38,6 @@
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/gprpp/sync.h"
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/static_metadata.h"
@ -63,8 +62,6 @@ class RoundRobin : public LoadBalancingPolicy {
void UpdateLocked(UpdateArgs args) override;
void ResetBackoffLocked() override;
void FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels,
channelz::ChildRefsList* ignored) override;
private:
~RoundRobin();
@ -108,9 +105,8 @@ class RoundRobin : public LoadBalancingPolicy {
public:
RoundRobinSubchannelList(RoundRobin* policy, TraceFlag* tracer,
const ServerAddressList& addresses,
grpc_combiner* combiner,
const grpc_channel_args& args)
: SubchannelList(policy, tracer, addresses, combiner,
: SubchannelList(policy, tracer, addresses,
policy->channel_control_helper(), args) {
// Need to maintain a ref to the LB policy as long as we maintain
// any references to subchannels, since the subchannels'
@ -157,25 +153,11 @@ class RoundRobin : public LoadBalancingPolicy {
RoundRobin* parent_;
size_t last_picked_index_;
InlinedVector<RefCountedPtr<ConnectedSubchannelInterface>, 10> subchannels_;
};
// Helper class to ensure that any function that modifies the child refs
// data structures will update the channelz snapshot data structures before
// returning.
class AutoChildRefsUpdater {
public:
explicit AutoChildRefsUpdater(RoundRobin* rr) : rr_(rr) {}
~AutoChildRefsUpdater() { rr_->UpdateChildRefsLocked(); }
private:
RoundRobin* rr_;
InlinedVector<RefCountedPtr<SubchannelInterface>, 10> subchannels_;
};
void ShutdownLocked() override;
void UpdateChildRefsLocked();
/** list of subchannels */
OrphanablePtr<RoundRobinSubchannelList> subchannel_list_;
/** Latest version of the subchannel list.
@ -186,11 +168,6 @@ class RoundRobin : public LoadBalancingPolicy {
OrphanablePtr<RoundRobinSubchannelList> latest_pending_subchannel_list_;
/** are we shutting down? */
bool shutdown_ = false;
/// Lock and data used to capture snapshots of this channel's child
/// channels and subchannels. This data is consumed by channelz.
Mutex child_refs_mu_;
channelz::ChildRefsList child_subchannels_;
channelz::ChildRefsList child_channels_;
};
//
@ -201,10 +178,9 @@ RoundRobin::Picker::Picker(RoundRobin* parent,
RoundRobinSubchannelList* subchannel_list)
: parent_(parent) {
for (size_t i = 0; i < subchannel_list->num_subchannels(); ++i) {
auto* connected_subchannel =
subchannel_list->subchannel(i)->connected_subchannel();
if (connected_subchannel != nullptr) {
subchannels_.push_back(connected_subchannel->Ref());
RoundRobinSubchannelData* sd = subchannel_list->subchannel(i);
if (sd->connectivity_state() == GRPC_CHANNEL_READY) {
subchannels_.push_back(sd->subchannel()->Ref());
}
}
// For discussion on why we generate a random starting index for
@ -225,14 +201,13 @@ RoundRobin::PickResult RoundRobin::Picker::Pick(PickArgs args) {
last_picked_index_ = (last_picked_index_ + 1) % subchannels_.size();
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) {
gpr_log(GPR_INFO,
"[RR %p picker %p] returning index %" PRIuPTR
", connected_subchannel=%p",
"[RR %p picker %p] returning index %" PRIuPTR ", subchannel=%p",
parent_, this, last_picked_index_,
subchannels_[last_picked_index_].get());
}
PickResult result;
result.type = PickResult::PICK_COMPLETE;
result.connected_subchannel = subchannels_[last_picked_index_];
result.subchannel = subchannels_[last_picked_index_];
return result;
}
@ -255,7 +230,6 @@ RoundRobin::~RoundRobin() {
}
void RoundRobin::ShutdownLocked() {
AutoChildRefsUpdater guard(this);
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) {
gpr_log(GPR_INFO, "[RR %p] Shutting down", this);
}
@ -271,40 +245,6 @@ void RoundRobin::ResetBackoffLocked() {
}
}
void RoundRobin::FillChildRefsForChannelz(
channelz::ChildRefsList* child_subchannels_to_fill,
channelz::ChildRefsList* ignored) {
MutexLock lock(&child_refs_mu_);
for (size_t i = 0; i < child_subchannels_.size(); ++i) {
// TODO(ncteisen): implement a de dup loop that is not O(n^2). Might
// have to implement lightweight set. For now, we don't care about
// performance when channelz requests are made.
bool found = false;
for (size_t j = 0; j < child_subchannels_to_fill->size(); ++j) {
if ((*child_subchannels_to_fill)[j] == child_subchannels_[i]) {
found = true;
break;
}
}
if (!found) {
child_subchannels_to_fill->push_back(child_subchannels_[i]);
}
}
}
void RoundRobin::UpdateChildRefsLocked() {
channelz::ChildRefsList cs;
if (subchannel_list_ != nullptr) {
subchannel_list_->PopulateChildRefsList(&cs);
}
if (latest_pending_subchannel_list_ != nullptr) {
latest_pending_subchannel_list_->PopulateChildRefsList(&cs);
}
// atomically update the data that channelz will actually be looking at.
MutexLock lock(&child_refs_mu_);
child_subchannels_ = std::move(cs);
}
void RoundRobin::RoundRobinSubchannelList::StartWatchingLocked() {
if (num_subchannels() == 0) return;
// Check current state of each subchannel synchronously, since any
@ -379,8 +319,8 @@ void RoundRobin::RoundRobinSubchannelList::
} else if (num_connecting_ > 0) {
/* 2) CONNECTING */
p->channel_control_helper()->UpdateState(
GRPC_CHANNEL_CONNECTING,
UniquePtr<SubchannelPicker>(New<QueuePicker>(p->Ref())));
GRPC_CHANNEL_CONNECTING, UniquePtr<SubchannelPicker>(New<QueuePicker>(
p->Ref(DEBUG_LOCATION, "QueuePicker"))));
} else if (num_transient_failure_ == num_subchannels()) {
/* 3) TRANSIENT_FAILURE */
grpc_error* error =
@ -396,7 +336,6 @@ void RoundRobin::RoundRobinSubchannelList::
void RoundRobin::RoundRobinSubchannelList::
UpdateRoundRobinStateFromSubchannelStateCountsLocked() {
RoundRobin* p = static_cast<RoundRobin*>(policy());
AutoChildRefsUpdater guard(p);
if (num_ready_ > 0) {
if (p->subchannel_list_.get() != this) {
// Promote this list to p->subchannel_list_.
@ -468,7 +407,6 @@ void RoundRobin::RoundRobinSubchannelData::ProcessConnectivityChangeLocked(
}
void RoundRobin::UpdateLocked(UpdateArgs args) {
AutoChildRefsUpdater guard(this);
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) {
gpr_log(GPR_INFO, "[RR %p] received update with %" PRIuPTR " addresses",
this, args.addresses.size());
@ -482,7 +420,7 @@ void RoundRobin::UpdateLocked(UpdateArgs args) {
}
}
latest_pending_subchannel_list_ = MakeOrphanable<RoundRobinSubchannelList>(
this, &grpc_lb_round_robin_trace, args.addresses, combiner(), *args.args);
this, &grpc_lb_round_robin_trace, args.addresses, *args.args);
if (latest_pending_subchannel_list_->num_subchannels() == 0) {
// If the new list is empty, immediately promote the new list to the
// current list and transition to TRANSIENT_FAILURE.

@ -39,7 +39,6 @@
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/closure.h"
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/transport/connectivity_state.h"
@ -64,8 +63,7 @@ class MySubchannelList
};
*/
// All methods with a Locked() suffix must be called from within the
// client_channel combiner.
// All methods will be called from within the client_channel combiner.
namespace grpc_core {
@ -93,20 +91,13 @@ class SubchannelData {
// Returns a pointer to the subchannel.
SubchannelInterface* subchannel() const { return subchannel_.get(); }
// Returns the connected subchannel. Will be null if the subchannel
// is not connected.
ConnectedSubchannelInterface* connected_subchannel() const {
return connected_subchannel_.get();
}
// Synchronously checks the subchannel's connectivity state.
// Must not be called while there is a connectivity notification
// pending (i.e., between calling StartConnectivityWatchLocked() and
// calling CancelConnectivityWatchLocked()).
grpc_connectivity_state CheckConnectivityStateLocked() {
GPR_ASSERT(pending_watcher_ == nullptr);
connectivity_state_ =
subchannel()->CheckConnectivityState(&connected_subchannel_);
connectivity_state_ = subchannel_->CheckConnectivityState();
return connectivity_state_;
}
@ -144,7 +135,8 @@ class SubchannelData {
private:
// Watcher for subchannel connectivity state.
class Watcher : public SubchannelInterface::ConnectivityStateWatcher {
class Watcher
: public SubchannelInterface::ConnectivityStateWatcherInterface {
public:
Watcher(
SubchannelData<SubchannelListType, SubchannelDataType>* subchannel_data,
@ -154,42 +146,13 @@ class SubchannelData {
~Watcher() { subchannel_list_.reset(DEBUG_LOCATION, "Watcher dtor"); }
void OnConnectivityStateChange(grpc_connectivity_state new_state,
RefCountedPtr<ConnectedSubchannelInterface>
connected_subchannel) override;
void OnConnectivityStateChange(grpc_connectivity_state new_state) override;
grpc_pollset_set* interested_parties() override {
return subchannel_list_->policy()->interested_parties();
}
private:
// A fire-and-forget class that bounces into the combiner to process
// a connectivity state update.
class Updater {
public:
Updater(
SubchannelData<SubchannelListType, SubchannelDataType>*
subchannel_data,
RefCountedPtr<SubchannelList<SubchannelListType, SubchannelDataType>>
subchannel_list,
grpc_connectivity_state state,
RefCountedPtr<ConnectedSubchannelInterface> connected_subchannel);
~Updater() {
subchannel_list_.reset(DEBUG_LOCATION, "Watcher::Updater dtor");
}
private:
static void OnUpdateLocked(void* arg, grpc_error* error);
SubchannelData<SubchannelListType, SubchannelDataType>* subchannel_data_;
RefCountedPtr<SubchannelList<SubchannelListType, SubchannelDataType>>
subchannel_list_;
const grpc_connectivity_state state_;
RefCountedPtr<ConnectedSubchannelInterface> connected_subchannel_;
grpc_closure closure_;
};
SubchannelData<SubchannelListType, SubchannelDataType>* subchannel_data_;
RefCountedPtr<SubchannelListType> subchannel_list_;
};
@ -202,10 +165,10 @@ class SubchannelData {
// The subchannel.
RefCountedPtr<SubchannelInterface> subchannel_;
// Will be non-null when the subchannel's state is being watched.
SubchannelInterface::ConnectivityStateWatcher* pending_watcher_ = nullptr;
SubchannelInterface::ConnectivityStateWatcherInterface* pending_watcher_ =
nullptr;
// Data updated by the watcher.
grpc_connectivity_state connectivity_state_;
RefCountedPtr<ConnectedSubchannelInterface> connected_subchannel_;
};
// A list of subchannels.
@ -223,19 +186,6 @@ class SubchannelList : public InternallyRefCounted<SubchannelListType> {
// Returns true if the subchannel list is shutting down.
bool shutting_down() const { return shutting_down_; }
// Populates refs_list with the uuids of this SubchannelLists's subchannels.
void PopulateChildRefsList(channelz::ChildRefsList* refs_list) {
for (size_t i = 0; i < subchannels_.size(); ++i) {
if (subchannels_[i].subchannel() != nullptr) {
grpc_core::channelz::SubchannelNode* subchannel_node =
subchannels_[i].subchannel()->channelz_node();
if (subchannel_node != nullptr) {
refs_list->push_back(subchannel_node->uuid());
}
}
}
}
// Accessors.
LoadBalancingPolicy* policy() const { return policy_; }
TraceFlag* tracer() const { return tracer_; }
@ -245,7 +195,6 @@ class SubchannelList : public InternallyRefCounted<SubchannelListType> {
// the backoff code out of subchannels and into LB policies.
void ResetBackoffLocked();
// Note: Caller must ensure that this is invoked inside of the combiner.
void Orphan() override {
ShutdownLocked();
InternallyRefCounted<SubchannelListType>::Unref(DEBUG_LOCATION, "shutdown");
@ -255,7 +204,7 @@ class SubchannelList : public InternallyRefCounted<SubchannelListType> {
protected:
SubchannelList(LoadBalancingPolicy* policy, TraceFlag* tracer,
const ServerAddressList& addresses, grpc_combiner* combiner,
const ServerAddressList& addresses,
LoadBalancingPolicy::ChannelControlHelper* helper,
const grpc_channel_args& args);
@ -276,8 +225,6 @@ class SubchannelList : public InternallyRefCounted<SubchannelListType> {
TraceFlag* tracer_;
grpc_combiner* combiner_;
// The list of subchannels.
SubchannelVector subchannels_;
@ -297,59 +244,26 @@ class SubchannelList : public InternallyRefCounted<SubchannelListType> {
template <typename SubchannelListType, typename SubchannelDataType>
void SubchannelData<SubchannelListType, SubchannelDataType>::Watcher::
OnConnectivityStateChange(
grpc_connectivity_state new_state,
RefCountedPtr<ConnectedSubchannelInterface> connected_subchannel) {
// Will delete itself.
New<Updater>(subchannel_data_,
subchannel_list_->Ref(DEBUG_LOCATION, "Watcher::Updater"),
new_state, std::move(connected_subchannel));
}
template <typename SubchannelListType, typename SubchannelDataType>
SubchannelData<SubchannelListType, SubchannelDataType>::Watcher::Updater::
Updater(
SubchannelData<SubchannelListType, SubchannelDataType>* subchannel_data,
RefCountedPtr<SubchannelList<SubchannelListType, SubchannelDataType>>
subchannel_list,
grpc_connectivity_state state,
RefCountedPtr<ConnectedSubchannelInterface> connected_subchannel)
: subchannel_data_(subchannel_data),
subchannel_list_(std::move(subchannel_list)),
state_(state),
connected_subchannel_(std::move(connected_subchannel)) {
GRPC_CLOSURE_INIT(&closure_, &OnUpdateLocked, this,
grpc_combiner_scheduler(subchannel_list_->combiner_));
GRPC_CLOSURE_SCHED(&closure_, GRPC_ERROR_NONE);
}
template <typename SubchannelListType, typename SubchannelDataType>
void SubchannelData<SubchannelListType, SubchannelDataType>::Watcher::Updater::
OnUpdateLocked(void* arg, grpc_error* error) {
Updater* self = static_cast<Updater*>(arg);
SubchannelData* sd = self->subchannel_data_;
if (GRPC_TRACE_FLAG_ENABLED(*sd->subchannel_list_->tracer())) {
OnConnectivityStateChange(grpc_connectivity_state new_state) {
if (GRPC_TRACE_FLAG_ENABLED(*subchannel_list_->tracer())) {
gpr_log(GPR_INFO,
"[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR
" (subchannel %p): connectivity changed: state=%s, "
"connected_subchannel=%p, shutting_down=%d, pending_watcher=%p",
sd->subchannel_list_->tracer()->name(),
sd->subchannel_list_->policy(), sd->subchannel_list_, sd->Index(),
sd->subchannel_list_->num_subchannels(), sd->subchannel_.get(),
grpc_connectivity_state_name(self->state_),
self->connected_subchannel_.get(),
sd->subchannel_list_->shutting_down(), sd->pending_watcher_);
"shutting_down=%d, pending_watcher=%p",
subchannel_list_->tracer()->name(), subchannel_list_->policy(),
subchannel_list_.get(), subchannel_data_->Index(),
subchannel_list_->num_subchannels(),
subchannel_data_->subchannel_.get(),
grpc_connectivity_state_name(new_state),
subchannel_list_->shutting_down(),
subchannel_data_->pending_watcher_);
}
if (!sd->subchannel_list_->shutting_down() &&
sd->pending_watcher_ != nullptr) {
sd->connectivity_state_ = self->state_;
// Get or release ref to connected subchannel.
sd->connected_subchannel_ = std::move(self->connected_subchannel_);
if (!subchannel_list_->shutting_down() &&
subchannel_data_->pending_watcher_ != nullptr) {
subchannel_data_->connectivity_state_ = new_state;
// Call the subclass's ProcessConnectivityChangeLocked() method.
sd->ProcessConnectivityChangeLocked(sd->connectivity_state_);
subchannel_data_->ProcessConnectivityChangeLocked(new_state);
}
// Clean up.
Delete(self);
}
//
@ -384,7 +298,6 @@ void SubchannelData<SubchannelListType, SubchannelDataType>::
subchannel_.get());
}
subchannel_.reset();
connected_subchannel_.reset();
}
}
@ -413,7 +326,7 @@ void SubchannelData<SubchannelListType,
New<Watcher>(this, subchannel_list()->Ref(DEBUG_LOCATION, "Watcher"));
subchannel_->WatchConnectivityState(
connectivity_state_,
UniquePtr<SubchannelInterface::ConnectivityStateWatcher>(
UniquePtr<SubchannelInterface::ConnectivityStateWatcherInterface>(
pending_watcher_));
}
@ -447,13 +360,12 @@ void SubchannelData<SubchannelListType, SubchannelDataType>::ShutdownLocked() {
template <typename SubchannelListType, typename SubchannelDataType>
SubchannelList<SubchannelListType, SubchannelDataType>::SubchannelList(
LoadBalancingPolicy* policy, TraceFlag* tracer,
const ServerAddressList& addresses, grpc_combiner* combiner,
const ServerAddressList& addresses,
LoadBalancingPolicy::ChannelControlHelper* helper,
const grpc_channel_args& args)
: InternallyRefCounted<SubchannelListType>(tracer),
policy_(policy),
tracer_(tracer),
combiner_(GRPC_COMBINER_REF(combiner, "subchannel_list")) {
tracer_(tracer) {
if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) {
gpr_log(GPR_INFO,
"[%s %p] Creating subchannel list %p for %" PRIuPTR " subchannels",
@ -522,7 +434,6 @@ SubchannelList<SubchannelListType, SubchannelDataType>::~SubchannelList() {
gpr_log(GPR_INFO, "[%s %p] Destroying subchannel_list %p", tracer_->name(),
policy_, this);
}
GRPC_COMBINER_UNREF(combiner_, "subchannel_list");
}
template <typename SubchannelListType, typename SubchannelDataType>

@ -117,7 +117,9 @@ TraceFlag grpc_lb_xds_trace(false, "xds");
namespace {
constexpr char kXds[] = "xds_experimental";
constexpr char kDefaultLocalityName[] = "xds_default_locality";
constexpr char kDefaultLocalityRegion[] = "xds_default_locality_region";
constexpr char kDefaultLocalityZone[] = "xds_default_locality_zone";
constexpr char kDefaultLocalitySubzone[] = "xds_default_locality_subzone";
constexpr uint32_t kDefaultLocalityWeight = 3;
class ParsedXdsConfig : public LoadBalancingPolicy::Config {
@ -155,9 +157,6 @@ class XdsLb : public LoadBalancingPolicy {
void UpdateLocked(UpdateArgs args) override;
void ResetBackoffLocked() override;
void FillChildRefsForChannelz(
channelz::ChildRefsList* child_subchannels,
channelz::ChildRefsList* child_channels) override;
private:
struct LocalityServerlistEntry;
@ -334,6 +333,8 @@ class XdsLb : public LoadBalancingPolicy {
explicit FallbackHelper(RefCountedPtr<XdsLb> parent)
: parent_(std::move(parent)) {}
~FallbackHelper() { parent_.reset(DEBUG_LOCATION, "FallbackHelper"); }
RefCountedPtr<SubchannelInterface> CreateSubchannel(
const grpc_channel_args& args) override;
grpc_channel* CreateChannel(const char* target,
@ -341,6 +342,7 @@ class XdsLb : public LoadBalancingPolicy {
void UpdateState(grpc_connectivity_state state,
UniquePtr<SubchannelPicker> picker) override;
void RequestReresolution() override;
void AddTraceEvent(TraceSeverity severity, const char* message) override;
void set_child(LoadBalancingPolicy* child) { child_ = child; }
@ -352,21 +354,61 @@ class XdsLb : public LoadBalancingPolicy {
LoadBalancingPolicy* child_ = nullptr;
};
class LocalityName : public RefCounted<LocalityName> {
public:
struct Less {
bool operator()(const RefCountedPtr<LocalityName>& lhs,
const RefCountedPtr<LocalityName>& rhs) {
int cmp_result = strcmp(lhs->region_.get(), rhs->region_.get());
if (cmp_result != 0) return cmp_result < 0;
cmp_result = strcmp(lhs->zone_.get(), rhs->zone_.get());
if (cmp_result != 0) return cmp_result < 0;
return strcmp(lhs->subzone_.get(), rhs->subzone_.get()) < 0;
}
};
LocalityName(UniquePtr<char> region, UniquePtr<char> zone,
UniquePtr<char> subzone)
: region_(std::move(region)),
zone_(std::move(zone)),
subzone_(std::move(subzone)) {}
bool operator==(const LocalityName& other) const {
return strcmp(region_.get(), other.region_.get()) == 0 &&
strcmp(zone_.get(), other.zone_.get()) == 0 &&
strcmp(subzone_.get(), other.subzone_.get()) == 0;
}
const char* AsHumanReadableString() {
if (human_readable_string_ == nullptr) {
char* tmp;
gpr_asprintf(&tmp, "{region=\"%s\", zone=\"%s\", subzone=\"%s\"}",
region_.get(), zone_.get(), subzone_.get());
human_readable_string_.reset(tmp);
}
return human_readable_string_.get();
}
private:
UniquePtr<char> region_;
UniquePtr<char> zone_;
UniquePtr<char> subzone_;
UniquePtr<char> human_readable_string_;
};
class LocalityMap {
public:
class LocalityEntry : public InternallyRefCounted<LocalityEntry> {
public:
LocalityEntry(RefCountedPtr<XdsLb> parent, uint32_t locality_weight)
: parent_(std::move(parent)), locality_weight_(locality_weight) {}
~LocalityEntry() = default;
LocalityEntry(RefCountedPtr<XdsLb> parent,
RefCountedPtr<LocalityName> name, uint32_t locality_weight);
~LocalityEntry();
void UpdateLocked(xds_grpclb_serverlist* serverlist,
LoadBalancingPolicy::Config* child_policy_config,
const grpc_channel_args* args);
void ShutdownLocked();
void ResetBackoffLocked();
void FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels,
channelz::ChildRefsList* child_channels);
void Orphan() override;
private:
@ -375,6 +417,8 @@ class XdsLb : public LoadBalancingPolicy {
explicit Helper(RefCountedPtr<LocalityEntry> entry)
: entry_(std::move(entry)) {}
~Helper() { entry_.reset(DEBUG_LOCATION, "Helper"); }
RefCountedPtr<SubchannelInterface> CreateSubchannel(
const grpc_channel_args& args) override;
grpc_channel* CreateChannel(const char* target,
@ -382,6 +426,8 @@ class XdsLb : public LoadBalancingPolicy {
void UpdateState(grpc_connectivity_state state,
UniquePtr<SubchannelPicker> picker) override;
void RequestReresolution() override;
void AddTraceEvent(TraceSeverity severity,
const char* message) override;
void set_child(LoadBalancingPolicy* child) { child_ = child; }
private:
@ -397,12 +443,10 @@ class XdsLb : public LoadBalancingPolicy {
grpc_channel_args* CreateChildPolicyArgsLocked(
const grpc_channel_args* args);
RefCountedPtr<XdsLb> parent_;
RefCountedPtr<LocalityName> name_;
OrphanablePtr<LoadBalancingPolicy> child_policy_;
OrphanablePtr<LoadBalancingPolicy> pending_child_policy_;
// Lock held when modifying the value of child_policy_ or
// pending_child_policy_.
Mutex child_policy_mu_;
RefCountedPtr<XdsLb> parent_;
RefCountedPtr<PickerRef> picker_ref_;
grpc_connectivity_state connectivity_state_;
uint32_t locality_weight_;
@ -413,24 +457,18 @@ class XdsLb : public LoadBalancingPolicy {
const grpc_channel_args* args, XdsLb* parent);
void ShutdownLocked();
void ResetBackoffLocked();
void FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels,
channelz::ChildRefsList* child_channels);
private:
void PruneLocalities(const LocalityList& locality_list);
Map<UniquePtr<char>, OrphanablePtr<LocalityEntry>, StringLess> map_;
// Lock held while filling child refs for all localities
// inside the map
Mutex child_refs_mu_;
Map<RefCountedPtr<LocalityName>, OrphanablePtr<LocalityEntry>,
LocalityName::Less>
map_;
};
struct LocalityServerlistEntry {
~LocalityServerlistEntry() {
gpr_free(locality_name);
xds_grpclb_destroy_serverlist(serverlist);
}
~LocalityServerlistEntry() { xds_grpclb_destroy_serverlist(serverlist); }
char* locality_name;
RefCountedPtr<LocalityName> locality_name;
uint32_t locality_weight;
// The deserialized response from the balancer. May be nullptr until one
// such response has arrived.
@ -479,10 +517,6 @@ class XdsLb : public LoadBalancingPolicy {
// The channel for communicating with the LB server.
OrphanablePtr<BalancerChannelState> lb_chand_;
OrphanablePtr<BalancerChannelState> pending_lb_chand_;
// Mutex to protect the channel to the LB server. This is used when
// processing a channelz request.
// TODO(juanlishen): Replace this with atomic.
Mutex lb_chand_mu_;
// Timeout in milliseconds for the LB call. 0 means no deadline.
int lb_call_timeout_ms_ = 0;
@ -506,9 +540,6 @@ class XdsLb : public LoadBalancingPolicy {
// The policy to use for the fallback backends.
RefCountedPtr<LoadBalancingPolicy::Config> fallback_policy_config_;
// Lock held when modifying the value of fallback_policy_ or
// pending_fallback_policy_.
Mutex fallback_policy_mu_;
// Non-null iff we are in fallback mode.
OrphanablePtr<LoadBalancingPolicy> fallback_policy_;
OrphanablePtr<LoadBalancingPolicy> pending_fallback_policy_;
@ -539,7 +570,7 @@ XdsLb::PickResult XdsLb::Picker::Pick(PickArgs args) {
PickResult result = PickFromLocality(key, args);
// If pick succeeded, add client stats.
if (result.type == PickResult::PICK_COMPLETE &&
result.connected_subchannel != nullptr && client_stats_ != nullptr) {
result.subchannel != nullptr && client_stats_ != nullptr) {
// TODO(roth): Add support for client stats.
}
return result;
@ -616,7 +647,6 @@ void XdsLb::FallbackHelper::UpdateState(grpc_connectivity_state state,
grpc_pollset_set_del_pollset_set(
parent_->fallback_policy_->interested_parties(),
parent_->interested_parties());
MutexLock lock(&parent_->fallback_policy_mu_);
parent_->fallback_policy_ = std::move(parent_->pending_fallback_policy_);
} else if (!CalledByCurrentFallback()) {
// This request is from an outdated fallback policy, so ignore it.
@ -641,6 +671,15 @@ void XdsLb::FallbackHelper::RequestReresolution() {
parent_->channel_control_helper()->RequestReresolution();
}
void XdsLb::FallbackHelper::AddTraceEvent(TraceSeverity severity,
const char* message) {
if (parent_->shutting_down_ ||
(!CalledByPendingFallback() && !CalledByCurrentFallback())) {
return;
}
parent_->channel_control_helper()->AddTraceEvent(severity, message);
}
//
// serverlist parsing code
//
@ -720,7 +759,7 @@ ServerAddressList ProcessServerlist(const xds_grpclb_serverlist* serverlist) {
XdsLb::BalancerChannelState::BalancerChannelState(
const char* balancer_name, const grpc_channel_args& args,
grpc_core::RefCountedPtr<grpc_core::XdsLb> parent_xdslb_policy)
RefCountedPtr<XdsLb> parent_xdslb_policy)
: InternallyRefCounted<BalancerChannelState>(&grpc_lb_xds_trace),
xdslb_policy_(std::move(parent_xdslb_policy)),
lb_call_backoff_(
@ -740,6 +779,7 @@ XdsLb::BalancerChannelState::BalancerChannelState(
}
XdsLb::BalancerChannelState::~BalancerChannelState() {
xdslb_policy_.reset(DEBUG_LOCATION, "BalancerChannelState");
grpc_channel_destroy(channel_);
}
@ -1199,7 +1239,10 @@ void XdsLb::BalancerChannelState::BalancerCallState::
xdslb_policy->locality_serverlist_.emplace_back(
MakeUnique<LocalityServerlistEntry>());
xdslb_policy->locality_serverlist_[0]->locality_name =
static_cast<char*>(gpr_strdup(kDefaultLocalityName));
MakeRefCounted<LocalityName>(
UniquePtr<char>(gpr_strdup(kDefaultLocalityRegion)),
UniquePtr<char>(gpr_strdup(kDefaultLocalityZone)),
UniquePtr<char>(gpr_strdup(kDefaultLocalitySubzone)));
xdslb_policy->locality_serverlist_[0]->locality_weight =
kDefaultLocalityWeight;
}
@ -1330,21 +1373,29 @@ grpc_channel_args* BuildBalancerChannelArgs(const grpc_channel_args* args) {
// treated as a stand-alone channel and not inherit this argument from the
// args of the parent channel.
GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
// Don't want to pass down channelz node from parent; the balancer
// channel will get its own.
GRPC_ARG_CHANNELZ_CHANNEL_NODE,
};
// Channel args to add.
const grpc_arg args_to_add[] = {
// A channel arg indicating the target is a xds load balancer.
grpc_channel_arg_integer_create(
const_cast<char*>(GRPC_ARG_ADDRESS_IS_XDS_LOAD_BALANCER), 1),
// A channel arg indicating this is an internal channels, aka it is
// owned by components in Core, not by the user application.
grpc_channel_arg_integer_create(
const_cast<char*>(GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL), 1),
};
InlinedVector<grpc_arg, 2> args_to_add;
// A channel arg indicating the target is a xds load balancer.
args_to_add.emplace_back(grpc_channel_arg_integer_create(
const_cast<char*>(GRPC_ARG_ADDRESS_IS_XDS_LOAD_BALANCER), 1));
// The parent channel's channelz uuid.
channelz::ChannelNode* channelz_node = nullptr;
const grpc_arg* arg =
grpc_channel_args_find(args, GRPC_ARG_CHANNELZ_CHANNEL_NODE);
if (arg != nullptr && arg->type == GRPC_ARG_POINTER &&
arg->value.pointer.p != nullptr) {
channelz_node = static_cast<channelz::ChannelNode*>(arg->value.pointer.p);
args_to_add.emplace_back(
channelz::MakeParentUuidArg(channelz_node->uuid()));
}
// Construct channel args.
grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove(
args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), args_to_add,
GPR_ARRAY_SIZE(args_to_add));
args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), args_to_add.data(),
args_to_add.size());
// Make any necessary modifications for security.
return grpc_lb_policy_xds_modify_lb_channel_args(new_args);
}
@ -1380,12 +1431,18 @@ XdsLb::XdsLb(Args args)
}
XdsLb::~XdsLb() {
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
gpr_log(GPR_INFO, "[xdslb %p] destroying xds LB policy", this);
}
gpr_free((void*)server_name_);
grpc_channel_args_destroy(args_);
locality_serverlist_.clear();
}
void XdsLb::ShutdownLocked() {
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
gpr_log(GPR_INFO, "[xdslb %p] shutting down", this);
}
shutting_down_ = true;
if (fallback_at_startup_checks_pending_) {
grpc_timer_cancel(&lb_fallback_timer_);
@ -1399,18 +1456,12 @@ void XdsLb::ShutdownLocked() {
grpc_pollset_set_del_pollset_set(
pending_fallback_policy_->interested_parties(), interested_parties());
}
{
MutexLock lock(&fallback_policy_mu_);
fallback_policy_.reset();
pending_fallback_policy_.reset();
}
fallback_policy_.reset();
pending_fallback_policy_.reset();
// We reset the LB channels here instead of in our destructor because they
// hold refs to XdsLb.
{
MutexLock lock(&lb_chand_mu_);
lb_chand_.reset();
pending_lb_chand_.reset();
}
lb_chand_.reset();
pending_lb_chand_.reset();
}
//
@ -1433,40 +1484,6 @@ void XdsLb::ResetBackoffLocked() {
}
}
void XdsLb::FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels,
channelz::ChildRefsList* child_channels) {
// Delegate to the locality_map_ to fill the children subchannels.
locality_map_.FillChildRefsForChannelz(child_subchannels, child_channels);
{
// This must be done holding fallback_policy_mu_, since this method does not
// run in the combiner.
MutexLock lock(&fallback_policy_mu_);
if (fallback_policy_ != nullptr) {
fallback_policy_->FillChildRefsForChannelz(child_subchannels,
child_channels);
}
if (pending_fallback_policy_ != nullptr) {
pending_fallback_policy_->FillChildRefsForChannelz(child_subchannels,
child_channels);
}
}
MutexLock lock(&lb_chand_mu_);
if (lb_chand_ != nullptr) {
grpc_core::channelz::ChannelNode* channel_node =
grpc_channel_get_channelz_node(lb_chand_->channel());
if (channel_node != nullptr) {
child_channels->push_back(channel_node->uuid());
}
}
if (pending_lb_chand_ != nullptr) {
grpc_core::channelz::ChannelNode* channel_node =
grpc_channel_get_channelz_node(pending_lb_chand_->channel());
if (channel_node != nullptr) {
child_channels->push_back(channel_node->uuid());
}
}
}
void XdsLb::ProcessAddressesAndChannelArgsLocked(
const ServerAddressList& addresses, const grpc_channel_args& args) {
// Update fallback address list.
@ -1492,8 +1509,9 @@ void XdsLb::ProcessAddressesAndChannelArgsLocked(
}
if (create_lb_channel) {
OrphanablePtr<BalancerChannelState> lb_chand =
MakeOrphanable<BalancerChannelState>(balancer_name_.get(),
*lb_channel_args, Ref());
MakeOrphanable<BalancerChannelState>(
balancer_name_.get(), *lb_channel_args,
Ref(DEBUG_LOCATION, "BalancerChannelState"));
if (lb_chand_ == nullptr || !lb_chand_->HasActiveCall()) {
GPR_ASSERT(pending_lb_chand_ == nullptr);
// If we do not have a working LB channel yet, use the newly created one.
@ -1656,14 +1674,10 @@ void XdsLb::UpdateFallbackPolicyLocked() {
fallback_policy_ == nullptr ? "" : "pending ",
fallback_policy_name);
}
auto new_policy =
CreateFallbackPolicyLocked(fallback_policy_name, update_args.args);
auto& lb_policy = fallback_policy_ == nullptr ? fallback_policy_
: pending_fallback_policy_;
{
MutexLock lock(&fallback_policy_mu_);
lb_policy = std::move(new_policy);
}
lb_policy =
CreateFallbackPolicyLocked(fallback_policy_name, update_args.args);
policy_to_update = lb_policy.get();
} else {
// Cases 2a and 3a: update an existing policy.
@ -1686,7 +1700,8 @@ void XdsLb::UpdateFallbackPolicyLocked() {
OrphanablePtr<LoadBalancingPolicy> XdsLb::CreateFallbackPolicyLocked(
const char* name, const grpc_channel_args* args) {
FallbackHelper* helper = New<FallbackHelper>(Ref());
FallbackHelper* helper =
New<FallbackHelper>(Ref(DEBUG_LOCATION, "FallbackHelper"));
LoadBalancingPolicy::Args lb_policy_args;
lb_policy_args.combiner = combiner();
lb_policy_args.args = args;
@ -1728,12 +1743,12 @@ void XdsLb::LocalityMap::PruneLocalities(const LocalityList& locality_list) {
for (auto iter = map_.begin(); iter != map_.end();) {
bool found = false;
for (size_t i = 0; i < locality_list.size(); i++) {
if (!gpr_stricmp(locality_list[i]->locality_name, iter->first.get())) {
if (*locality_list[i]->locality_name == *iter->first) {
found = true;
break;
}
}
if (!found) { // Remove entries not present in the locality list
MutexLock lock(&child_refs_mu_);
iter = map_.erase(iter);
} else
iter++;
@ -1746,14 +1761,15 @@ void XdsLb::LocalityMap::UpdateLocked(
const grpc_channel_args* args, XdsLb* parent) {
if (parent->shutting_down_) return;
for (size_t i = 0; i < locality_serverlist.size(); i++) {
UniquePtr<char> locality_name(
gpr_strdup(locality_serverlist[i]->locality_name));
auto iter = map_.find(locality_name);
auto iter = map_.find(locality_serverlist[i]->locality_name);
if (iter == map_.end()) {
OrphanablePtr<LocalityEntry> new_entry = MakeOrphanable<LocalityEntry>(
parent->Ref(), locality_serverlist[i]->locality_weight);
MutexLock lock(&child_refs_mu_);
iter = map_.emplace(std::move(locality_name), std::move(new_entry)).first;
parent->Ref(DEBUG_LOCATION, "LocalityEntry"),
locality_serverlist[i]->locality_name,
locality_serverlist[i]->locality_weight);
iter = map_.emplace(locality_serverlist[i]->locality_name,
std::move(new_entry))
.first;
}
// Don't create new child policies if not directed to
xds_grpclb_serverlist* serverlist =
@ -1763,10 +1779,7 @@ void XdsLb::LocalityMap::UpdateLocked(
PruneLocalities(locality_serverlist);
}
void XdsLb::LocalityMap::ShutdownLocked() {
MutexLock lock(&child_refs_mu_);
map_.clear();
}
void XdsLb::LocalityMap::ShutdownLocked() { map_.clear(); }
void XdsLb::LocalityMap::ResetBackoffLocked() {
for (auto& p : map_) {
@ -1774,19 +1787,31 @@ void XdsLb::LocalityMap::ResetBackoffLocked() {
}
}
void XdsLb::LocalityMap::FillChildRefsForChannelz(
channelz::ChildRefsList* child_subchannels,
channelz::ChildRefsList* child_channels) {
MutexLock lock(&child_refs_mu_);
for (auto& p : map_) {
p.second->FillChildRefsForChannelz(child_subchannels, child_channels);
}
}
//
// XdsLb::LocalityMap::LocalityEntry
//
XdsLb::LocalityMap::LocalityEntry::LocalityEntry(
RefCountedPtr<XdsLb> parent, RefCountedPtr<LocalityName> name,
uint32_t locality_weight)
: parent_(std::move(parent)),
name_(std::move(name)),
locality_weight_(locality_weight) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
gpr_log(GPR_INFO, "[xdslb %p] created LocalityEntry %p for %s",
parent_.get(), this, name_->AsHumanReadableString());
}
}
XdsLb::LocalityMap::LocalityEntry::~LocalityEntry() {
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
gpr_log(GPR_INFO,
"[xdslb %p] LocalityEntry %p %s: destroying locality entry",
parent_.get(), this, name_->AsHumanReadableString());
}
parent_.reset(DEBUG_LOCATION, "LocalityEntry");
}
grpc_channel_args*
XdsLb::LocalityMap::LocalityEntry::CreateChildPolicyArgsLocked(
const grpc_channel_args* args_in) {
@ -1808,7 +1833,7 @@ XdsLb::LocalityMap::LocalityEntry::CreateChildPolicyArgsLocked(
OrphanablePtr<LoadBalancingPolicy>
XdsLb::LocalityMap::LocalityEntry::CreateChildPolicyLocked(
const char* name, const grpc_channel_args* args) {
Helper* helper = New<Helper>(this->Ref());
Helper* helper = New<Helper>(this->Ref(DEBUG_LOCATION, "Helper"));
LoadBalancingPolicy::Args lb_policy_args;
lb_policy_args.combiner = parent_->combiner();
lb_policy_args.args = args;
@ -1818,13 +1843,16 @@ XdsLb::LocalityMap::LocalityEntry::CreateChildPolicyLocked(
LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy(
name, std::move(lb_policy_args));
if (GPR_UNLIKELY(lb_policy == nullptr)) {
gpr_log(GPR_ERROR, "[xdslb %p] Failure creating child policy %s", this,
name);
gpr_log(GPR_ERROR,
"[xdslb %p] LocalityEntry %p %s: failure creating child policy %s",
parent_.get(), this, name_->AsHumanReadableString(), name);
return nullptr;
}
helper->set_child(lb_policy.get());
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
gpr_log(GPR_INFO, "[xdslb %p] Created new child policy %s (%p)", this, name,
gpr_log(GPR_INFO,
"[xdslb %p] LocalityEntry %p %s: Created new child policy %s (%p)",
parent_.get(), this, name_->AsHumanReadableString(), name,
lb_policy.get());
}
// Add the xDS's interested_parties pollset_set to that of the newly created
@ -1915,17 +1943,14 @@ void XdsLb::LocalityMap::LocalityEntry::UpdateLocked(
// If child_policy_ is null, we set it (case 1), else we set
// pending_child_policy_ (cases 2b and 3b).
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
gpr_log(GPR_INFO, "[xdslb %p] Creating new %schild policy %s", this,
gpr_log(GPR_INFO,
"[xdslb %p] LocalityEntry %p %s: Creating new %schild policy %s",
parent_.get(), this, name_->AsHumanReadableString(),
child_policy_ == nullptr ? "" : "pending ", child_policy_name);
}
auto new_policy =
CreateChildPolicyLocked(child_policy_name, update_args.args);
auto& lb_policy =
child_policy_ == nullptr ? child_policy_ : pending_child_policy_;
{
MutexLock lock(&child_policy_mu_);
lb_policy = std::move(new_policy);
}
lb_policy = CreateChildPolicyLocked(child_policy_name, update_args.args);
policy_to_update = lb_policy.get();
} else {
// Cases 2a and 3a: update an existing policy.
@ -1938,7 +1963,9 @@ void XdsLb::LocalityMap::LocalityEntry::UpdateLocked(
GPR_ASSERT(policy_to_update != nullptr);
// Update the policy.
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
gpr_log(GPR_INFO, "[xdslb %p] Updating %schild policy %p", this,
gpr_log(GPR_INFO,
"[xdslb %p] LocalityEntry %p %s: Updating %schild policy %p",
parent_.get(), this, name_->AsHumanReadableString(),
policy_to_update == pending_child_policy_.get() ? "pending " : "",
policy_to_update);
}
@ -1946,20 +1973,25 @@ void XdsLb::LocalityMap::LocalityEntry::UpdateLocked(
}
void XdsLb::LocalityMap::LocalityEntry::ShutdownLocked() {
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
gpr_log(GPR_INFO,
"[xdslb %p] LocalityEntry %p %s: shutting down locality entry",
parent_.get(), this, name_->AsHumanReadableString());
}
// Remove the child policy's interested_parties pollset_set from the
// xDS policy.
grpc_pollset_set_del_pollset_set(child_policy_->interested_parties(),
parent_->interested_parties());
child_policy_.reset();
if (pending_child_policy_ != nullptr) {
grpc_pollset_set_del_pollset_set(
pending_child_policy_->interested_parties(),
parent_->interested_parties());
}
{
MutexLock lock(&child_policy_mu_);
child_policy_.reset();
pending_child_policy_.reset();
}
// Drop our ref to the child's picker, in case it's holding a ref to
// the child.
picker_ref_.reset();
}
void XdsLb::LocalityMap::LocalityEntry::ResetBackoffLocked() {
@ -1969,17 +2001,6 @@ void XdsLb::LocalityMap::LocalityEntry::ResetBackoffLocked() {
}
}
void XdsLb::LocalityMap::LocalityEntry::FillChildRefsForChannelz(
channelz::ChildRefsList* child_subchannels,
channelz::ChildRefsList* child_channels) {
MutexLock lock(&child_policy_mu_);
child_policy_->FillChildRefsForChannelz(child_subchannels, child_channels);
if (pending_child_policy_ != nullptr) {
pending_child_policy_->FillChildRefsForChannelz(child_subchannels,
child_channels);
}
}
void XdsLb::LocalityMap::LocalityEntry::Orphan() {
ShutdownLocked();
Unref();
@ -2034,7 +2055,6 @@ void XdsLb::LocalityMap::LocalityEntry::Helper::UpdateState(
grpc_pollset_set_del_pollset_set(
entry_->child_policy_->interested_parties(),
entry_->parent_->interested_parties());
MutexLock lock(&entry_->child_policy_mu_);
entry_->child_policy_ = std::move(entry_->pending_child_policy_);
} else if (!CalledByCurrentChild()) {
// This request is from an outdated child, so ignore it.
@ -2104,11 +2124,13 @@ void XdsLb::LocalityMap::LocalityEntry::Helper::UpdateState(
} else if (num_connecting > 0) {
entry_->parent_->channel_control_helper()->UpdateState(
GRPC_CHANNEL_CONNECTING,
UniquePtr<SubchannelPicker>(New<QueuePicker>(this->entry_->parent_)));
UniquePtr<SubchannelPicker>(New<QueuePicker>(
this->entry_->parent_->Ref(DEBUG_LOCATION, "QueuePicker"))));
} else if (num_idle > 0) {
entry_->parent_->channel_control_helper()->UpdateState(
GRPC_CHANNEL_IDLE,
UniquePtr<SubchannelPicker>(New<QueuePicker>(this->entry_->parent_)));
UniquePtr<SubchannelPicker>(New<QueuePicker>(
this->entry_->parent_->Ref(DEBUG_LOCATION, "QueuePicker"))));
} else {
GPR_ASSERT(num_transient_failures == locality_map.size());
grpc_error* error =
@ -2144,6 +2166,15 @@ void XdsLb::LocalityMap::LocalityEntry::Helper::RequestReresolution() {
}
}
void XdsLb::LocalityMap::LocalityEntry::Helper::AddTraceEvent(
TraceSeverity severity, const char* message) {
if (entry_->parent_->shutting_down_ ||
(!CalledByPendingChild() && !CalledByCurrentChild())) {
return;
}
entry_->parent_->channel_control_helper()->AddTraceEvent(severity, message);
}
//
// factory
//

@ -117,18 +117,16 @@ class Resolver : public InternallyRefCounted<Resolver> {
/// implementations. At that point, this method can go away.
virtual void ResetBackoffLocked() {}
// Note: This must be invoked while holding the combiner.
void Orphan() override {
// Invoke ShutdownAndUnrefLocked() inside of the combiner.
GRPC_CLOSURE_SCHED(
GRPC_CLOSURE_CREATE(&Resolver::ShutdownAndUnrefLocked, this,
grpc_combiner_scheduler(combiner_)),
GRPC_ERROR_NONE);
ShutdownLocked();
Unref();
}
GRPC_ABSTRACT_BASE_CLASS
protected:
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
/// Does NOT take ownership of the reference to \a combiner.
// TODO(roth): Once we have a C++-like interface for combiners, this
@ -147,12 +145,6 @@ class Resolver : public InternallyRefCounted<Resolver> {
ResultHandler* result_handler() const { return result_handler_.get(); }
private:
static void ShutdownAndUnrefLocked(void* arg, grpc_error* ignored) {
Resolver* resolver = static_cast<Resolver*>(arg);
resolver->ShutdownLocked();
resolver->Unref();
}
UniquePtr<ResultHandler> result_handler_;
grpc_combiner* combiner_;
};

@ -137,7 +137,6 @@ class ResolvingLoadBalancingPolicy::ResolvingControlHelper
grpc_pollset_set_del_pollset_set(
parent_->lb_policy_->interested_parties(),
parent_->interested_parties());
MutexLock lock(&parent_->lb_policy_mu_);
parent_->lb_policy_ = std::move(parent_->pending_lb_policy_);
} else if (!CalledByCurrentChild()) {
// This request is from an outdated child, so ignore it.
@ -214,7 +213,6 @@ ResolvingLoadBalancingPolicy::ResolvingLoadBalancingPolicy(
process_resolver_result_(process_resolver_result),
process_resolver_result_user_data_(process_resolver_result_user_data) {
GPR_ASSERT(process_resolver_result != nullptr);
gpr_mu_init(&lb_policy_mu_);
*error = Init(*args.args);
}
@ -234,13 +232,11 @@ grpc_error* ResolvingLoadBalancingPolicy::Init(const grpc_channel_args& args) {
ResolvingLoadBalancingPolicy::~ResolvingLoadBalancingPolicy() {
GPR_ASSERT(resolver_ == nullptr);
GPR_ASSERT(lb_policy_ == nullptr);
gpr_mu_destroy(&lb_policy_mu_);
}
void ResolvingLoadBalancingPolicy::ShutdownLocked() {
if (resolver_ != nullptr) {
resolver_.reset();
MutexLock lock(&lb_policy_mu_);
if (lb_policy_ != nullptr) {
if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) {
gpr_log(GPR_INFO, "resolving_lb=%p: shutting down lb_policy=%p", this,
@ -282,22 +278,6 @@ void ResolvingLoadBalancingPolicy::ResetBackoffLocked() {
if (pending_lb_policy_ != nullptr) pending_lb_policy_->ResetBackoffLocked();
}
void ResolvingLoadBalancingPolicy::FillChildRefsForChannelz(
channelz::ChildRefsList* child_subchannels,
channelz::ChildRefsList* child_channels) {
// Delegate to the lb_policy_ to fill the children subchannels.
// This must be done holding lb_policy_mu_, since this method does not
// run in the combiner.
MutexLock lock(&lb_policy_mu_);
if (lb_policy_ != nullptr) {
lb_policy_->FillChildRefsForChannelz(child_subchannels, child_channels);
}
if (pending_lb_policy_ != nullptr) {
pending_lb_policy_->FillChildRefsForChannelz(child_subchannels,
child_channels);
}
}
void ResolvingLoadBalancingPolicy::StartResolvingLocked() {
if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) {
gpr_log(GPR_INFO, "resolving_lb=%p: starting name resolution", this);
@ -403,13 +383,9 @@ void ResolvingLoadBalancingPolicy::CreateOrUpdateLbPolicyLocked(
gpr_log(GPR_INFO, "resolving_lb=%p: Creating new %schild policy %s", this,
lb_policy_ == nullptr ? "" : "pending ", lb_policy_name);
}
auto new_policy =
CreateLbPolicyLocked(lb_policy_name, *result.args, trace_strings);
auto& lb_policy = lb_policy_ == nullptr ? lb_policy_ : pending_lb_policy_;
{
MutexLock lock(&lb_policy_mu_);
lb_policy = std::move(new_policy);
}
lb_policy =
CreateLbPolicyLocked(lb_policy_name, *result.args, trace_strings);
policy_to_update = lb_policy.get();
} else {
// Cases 2a and 3a: update an existing policy.
@ -451,11 +427,9 @@ ResolvingLoadBalancingPolicy::CreateLbPolicyLocked(
lb_policy_name, std::move(lb_policy_args));
if (GPR_UNLIKELY(lb_policy == nullptr)) {
gpr_log(GPR_ERROR, "could not create LB policy \"%s\"", lb_policy_name);
if (channelz_node() != nullptr) {
char* str;
gpr_asprintf(&str, "Could not create LB policy \"%s\"", lb_policy_name);
trace_strings->push_back(str);
}
char* str;
gpr_asprintf(&str, "Could not create LB policy \"%s\"", lb_policy_name);
trace_strings->push_back(str);
return nullptr;
}
helper->set_child(lb_policy.get());
@ -463,16 +437,9 @@ ResolvingLoadBalancingPolicy::CreateLbPolicyLocked(
gpr_log(GPR_INFO, "resolving_lb=%p: created new LB policy \"%s\" (%p)",
this, lb_policy_name, lb_policy.get());
}
if (channelz_node() != nullptr) {
char* str;
gpr_asprintf(&str, "Created new LB policy \"%s\"", lb_policy_name);
trace_strings->push_back(str);
}
// Propagate channelz node.
auto* channelz = channelz_node();
if (channelz != nullptr) {
lb_policy->set_channelz_node(channelz->Ref());
}
char* str;
gpr_asprintf(&str, "Created new LB policy \"%s\"", lb_policy_name);
trace_strings->push_back(str);
grpc_pollset_set_add_pollset_set(lb_policy->interested_parties(),
interested_parties());
return lb_policy;
@ -502,11 +469,10 @@ void ResolvingLoadBalancingPolicy::ConcatenateAndAddChannelTraceLocked(
is_first = false;
gpr_strvec_add(&v, (*trace_strings)[i]);
}
char* flat;
size_t flat_len = 0;
flat = gpr_strvec_flatten(&v, &flat_len);
channelz_node()->AddTraceEvent(channelz::ChannelTrace::Severity::Info,
grpc_slice_new(flat, flat_len, gpr_free));
size_t len = 0;
UniquePtr<char> message(gpr_strvec_flatten(&v, &len));
channel_control_helper()->AddTraceEvent(ChannelControlHelper::TRACE_INFO,
message.get());
gpr_strvec_destroy(&v);
}
}
@ -560,21 +526,18 @@ void ResolvingLoadBalancingPolicy::OnResolverResultChangedLocked(
std::move(result), &trace_strings);
}
// Add channel trace event.
if (channelz_node() != nullptr) {
if (service_config_changed) {
// TODO(ncteisen): might be worth somehow including a snippet of the
// config in the trace, at the risk of bloating the trace logs.
trace_strings.push_back(gpr_strdup("Service config changed"));
}
if (service_config_error_string != nullptr) {
trace_strings.push_back(service_config_error_string);
service_config_error_string = nullptr;
}
MaybeAddTraceMessagesForAddressChangesLocked(resolution_contains_addresses,
&trace_strings);
ConcatenateAndAddChannelTraceLocked(&trace_strings);
if (service_config_changed) {
// TODO(ncteisen): might be worth somehow including a snippet of the
// config in the trace, at the risk of bloating the trace logs.
trace_strings.push_back(gpr_strdup("Service config changed"));
}
if (service_config_error_string != nullptr) {
trace_strings.push_back(service_config_error_string);
service_config_error_string = nullptr;
}
gpr_free(service_config_error_string);
MaybeAddTraceMessagesForAddressChangesLocked(resolution_contains_addresses,
&trace_strings);
ConcatenateAndAddChannelTraceLocked(&trace_strings);
}
} // namespace grpc_core

@ -21,7 +21,6 @@
#include <grpc/support/port_platform.h>
#include "src/core/ext/filters/client_channel/client_channel_channelz.h"
#include "src/core/ext/filters/client_channel/lb_policy.h"
#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
#include "src/core/ext/filters/client_channel/resolver.h"
@ -91,10 +90,6 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy {
void ResetBackoffLocked() override;
void FillChildRefsForChannelz(
channelz::ChildRefsList* child_subchannels,
channelz::ChildRefsList* child_channels) override;
private:
using TraceStringVector = InlinedVector<char*, 3>;
@ -137,9 +132,6 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy {
// Child LB policy.
OrphanablePtr<LoadBalancingPolicy> lb_policy_;
OrphanablePtr<LoadBalancingPolicy> pending_lb_policy_;
// Lock held when modifying the value of child_policy_ or
// pending_child_policy_.
gpr_mu lb_policy_mu_;
};
} // namespace grpc_core

@ -39,12 +39,10 @@ ServerAddress::ServerAddress(const void* address, size_t address_len,
address_.len = static_cast<socklen_t>(address_len);
}
int ServerAddress::Cmp(const ServerAddress& other) const {
if (address_.len > other.address_.len) return 1;
if (address_.len < other.address_.len) return -1;
int retval = memcmp(address_.addr, other.address_.addr, address_.len);
if (retval != 0) return retval;
return grpc_channel_args_compare(args_, other.args_);
bool ServerAddress::operator==(const grpc_core::ServerAddress& other) const {
return address_.len == other.address_.len &&
memcmp(address_.addr, other.address_.addr, address_.len) == 0 &&
grpc_channel_args_compare(args_, other.args_) == 0;
}
bool ServerAddress::IsBalancer() const {

@ -73,9 +73,7 @@ class ServerAddress {
return *this;
}
bool operator==(const ServerAddress& other) const { return Cmp(other) == 0; }
int Cmp(const ServerAddress& other) const;
bool operator==(const ServerAddress& other) const;
const grpc_resolved_address& address() const { return address_; }
const grpc_channel_args* args() const { return args_; }

@ -75,6 +75,9 @@
namespace grpc_core {
TraceFlag grpc_trace_subchannel(false, "subchannel");
DebugOnlyTraceFlag grpc_trace_subchannel_refcount(false, "subchannel_refcount");
//
// ConnectedSubchannel
//
@ -83,7 +86,7 @@ ConnectedSubchannel::ConnectedSubchannel(
grpc_channel_stack* channel_stack, const grpc_channel_args* args,
RefCountedPtr<channelz::SubchannelNode> channelz_subchannel,
intptr_t socket_uuid)
: ConnectedSubchannelInterface(&grpc_trace_stream_refcount),
: RefCounted<ConnectedSubchannel>(&grpc_trace_subchannel_refcount),
channel_stack_(channel_stack),
args_(grpc_channel_args_copy(args)),
channelz_subchannel_(std::move(channelz_subchannel)),
@ -332,7 +335,7 @@ class Subchannel::ConnectedSubchannelStateWatcher {
case GRPC_CHANNEL_TRANSIENT_FAILURE:
case GRPC_CHANNEL_SHUTDOWN: {
if (!c->disconnected_ && c->connected_subchannel_ != nullptr) {
if (grpc_trace_stream_refcount.enabled()) {
if (grpc_trace_subchannel.enabled()) {
gpr_log(GPR_INFO,
"Connected subchannel %p of subchannel %p has gone into "
"%s. Attempting to reconnect.",
@ -375,12 +378,12 @@ class Subchannel::ConnectedSubchannelStateWatcher {
//
void Subchannel::ConnectivityStateWatcherList::AddWatcherLocked(
UniquePtr<ConnectivityStateWatcher> watcher) {
OrphanablePtr<ConnectivityStateWatcherInterface> watcher) {
watchers_.insert(MakePair(watcher.get(), std::move(watcher)));
}
void Subchannel::ConnectivityStateWatcherList::RemoveWatcherLocked(
ConnectivityStateWatcher* watcher) {
ConnectivityStateWatcherInterface* watcher) {
watchers_.erase(watcher);
}
@ -435,8 +438,9 @@ class Subchannel::HealthWatcherMap::HealthWatcher
grpc_connectivity_state state() const { return state_; }
void AddWatcherLocked(grpc_connectivity_state initial_state,
UniquePtr<ConnectivityStateWatcher> watcher) {
void AddWatcherLocked(
grpc_connectivity_state initial_state,
OrphanablePtr<ConnectivityStateWatcherInterface> watcher) {
if (state_ != initial_state) {
RefCountedPtr<ConnectedSubchannel> connected_subchannel;
if (state_ == GRPC_CHANNEL_READY) {
@ -448,7 +452,7 @@ class Subchannel::HealthWatcherMap::HealthWatcher
watcher_list_.AddWatcherLocked(std::move(watcher));
}
void RemoveWatcherLocked(ConnectivityStateWatcher* watcher) {
void RemoveWatcherLocked(ConnectivityStateWatcherInterface* watcher) {
watcher_list_.RemoveWatcherLocked(watcher);
}
@ -524,7 +528,7 @@ class Subchannel::HealthWatcherMap::HealthWatcher
void Subchannel::HealthWatcherMap::AddWatcherLocked(
Subchannel* subchannel, grpc_connectivity_state initial_state,
UniquePtr<char> health_check_service_name,
UniquePtr<ConnectivityStateWatcher> watcher) {
OrphanablePtr<ConnectivityStateWatcherInterface> watcher) {
// If the health check service name is not already present in the map,
// add it.
auto it = map_.find(health_check_service_name.get());
@ -543,7 +547,8 @@ void Subchannel::HealthWatcherMap::AddWatcherLocked(
}
void Subchannel::HealthWatcherMap::RemoveWatcherLocked(
const char* health_check_service_name, ConnectivityStateWatcher* watcher) {
const char* health_check_service_name,
ConnectivityStateWatcherInterface* watcher) {
auto it = map_.find(health_check_service_name);
GPR_ASSERT(it != map_.end());
it->second->RemoveWatcherLocked(watcher);
@ -815,7 +820,7 @@ grpc_connectivity_state Subchannel::CheckConnectivityState(
void Subchannel::WatchConnectivityState(
grpc_connectivity_state initial_state,
UniquePtr<char> health_check_service_name,
UniquePtr<ConnectivityStateWatcher> watcher) {
OrphanablePtr<ConnectivityStateWatcherInterface> watcher) {
MutexLock lock(&mu_);
grpc_pollset_set* interested_parties = watcher->interested_parties();
if (interested_parties != nullptr) {
@ -834,7 +839,8 @@ void Subchannel::WatchConnectivityState(
}
void Subchannel::CancelConnectivityStateWatch(
const char* health_check_service_name, ConnectivityStateWatcher* watcher) {
const char* health_check_service_name,
ConnectivityStateWatcherInterface* watcher) {
MutexLock lock(&mu_);
grpc_pollset_set* interested_parties = watcher->interested_parties();
if (interested_parties != nullptr) {
@ -1106,7 +1112,7 @@ gpr_atm Subchannel::RefMutate(
gpr_atm old_val = barrier ? gpr_atm_full_fetch_add(&ref_pair_, delta)
: gpr_atm_no_barrier_fetch_add(&ref_pair_, delta);
#ifndef NDEBUG
if (grpc_trace_stream_refcount.enabled()) {
if (grpc_trace_subchannel_refcount.enabled()) {
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
"SUBCHANNEL: %p %12s 0x%" PRIxPTR " -> 0x%" PRIxPTR " [%s]", this,
purpose, old_val, old_val + delta, reason);

@ -23,7 +23,6 @@
#include "src/core/ext/filters/client_channel/client_channel_channelz.h"
#include "src/core/ext/filters/client_channel/connector.h"
#include "src/core/ext/filters/client_channel/subchannel_interface.h"
#include "src/core/ext/filters/client_channel/subchannel_pool_interface.h"
#include "src/core/lib/backoff/backoff.h"
#include "src/core/lib/channel/channel_stack.h"
@ -70,7 +69,7 @@ namespace grpc_core {
class SubchannelCall;
class ConnectedSubchannel : public ConnectedSubchannelInterface {
class ConnectedSubchannel : public RefCounted<ConnectedSubchannel> {
public:
struct CallArgs {
grpc_polling_entity* pollent;
@ -97,7 +96,7 @@ class ConnectedSubchannel : public ConnectedSubchannelInterface {
grpc_error** error);
grpc_channel_stack* channel_stack() const { return channel_stack_; }
const grpc_channel_args* args() const override { return args_; }
const grpc_channel_args* args() const { return args_; }
channelz::SubchannelNode* channelz_subchannel() const {
return channelz_subchannel_.get();
}
@ -176,10 +175,35 @@ class SubchannelCall {
// A subchannel that knows how to connect to exactly one target address. It
// provides a target for load balancing.
//
// Note that this is the "real" subchannel implementation, whose API is
// different from the SubchannelInterface that is exposed to LB policy
// implementations. The client channel provides an adaptor class
// (SubchannelWrapper) that "converts" between the two.
class Subchannel {
public:
typedef SubchannelInterface::ConnectivityStateWatcher
ConnectivityStateWatcher;
class ConnectivityStateWatcherInterface
: public InternallyRefCounted<ConnectivityStateWatcherInterface> {
public:
virtual ~ConnectivityStateWatcherInterface() = default;
// Will be 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.
//
// When the state changes to READY, connected_subchannel will
// contain a ref to the connected subchannel. When it changes from
// READY to some other state, the implementation must release its
// ref to the connected subchannel.
virtual void OnConnectivityStateChange(
grpc_connectivity_state new_state,
RefCountedPtr<ConnectedSubchannel> connected_subchannel) // NOLINT
GRPC_ABSTRACT;
virtual grpc_pollset_set* interested_parties() GRPC_ABSTRACT;
GRPC_ABSTRACT_BASE_CLASS
};
// The ctor and dtor are not intended to use directly.
Subchannel(SubchannelKey* key, grpc_connector* connector,
@ -206,6 +230,8 @@ class Subchannel {
// Caller doesn't take ownership.
const char* GetTargetAddress();
const grpc_channel_args* channel_args() const { return args_; }
channelz::SubchannelNode* channelz_node();
// Returns the current connectivity state of the subchannel.
@ -225,14 +251,15 @@ class Subchannel {
// changes.
// The watcher will be destroyed either when the subchannel is
// destroyed or when CancelConnectivityStateWatch() is called.
void WatchConnectivityState(grpc_connectivity_state initial_state,
UniquePtr<char> health_check_service_name,
UniquePtr<ConnectivityStateWatcher> watcher);
void WatchConnectivityState(
grpc_connectivity_state initial_state,
UniquePtr<char> health_check_service_name,
OrphanablePtr<ConnectivityStateWatcherInterface> watcher);
// Cancels a connectivity state watch.
// If the watcher has already been destroyed, this is a no-op.
void CancelConnectivityStateWatch(const char* health_check_service_name,
ConnectivityStateWatcher* watcher);
ConnectivityStateWatcherInterface* watcher);
// Attempt to connect to the backend. Has no effect if already connected.
void AttemptToConnect();
@ -257,14 +284,15 @@ class Subchannel {
grpc_resolved_address* addr);
private:
// A linked list of ConnectivityStateWatchers that are monitoring the
// subchannel's state.
// A linked list of ConnectivityStateWatcherInterfaces that are monitoring
// the subchannel's state.
class ConnectivityStateWatcherList {
public:
~ConnectivityStateWatcherList() { Clear(); }
void AddWatcherLocked(UniquePtr<ConnectivityStateWatcher> watcher);
void RemoveWatcherLocked(ConnectivityStateWatcher* watcher);
void AddWatcherLocked(
OrphanablePtr<ConnectivityStateWatcherInterface> watcher);
void RemoveWatcherLocked(ConnectivityStateWatcherInterface* watcher);
// Notifies all watchers in the list about a change to state.
void NotifyLocked(Subchannel* subchannel, grpc_connectivity_state state);
@ -276,12 +304,13 @@ class Subchannel {
private:
// TODO(roth): This could be a set instead of a map if we had a set
// implementation.
Map<ConnectivityStateWatcher*, UniquePtr<ConnectivityStateWatcher>>
Map<ConnectivityStateWatcherInterface*,
OrphanablePtr<ConnectivityStateWatcherInterface>>
watchers_;
};
// A map that tracks ConnectivityStateWatchers using a particular health
// check service name.
// A map that tracks ConnectivityStateWatcherInterfaces using a particular
// health check service name.
//
// There is one entry in the map for each health check service name.
// Entries exist only as long as there are watchers using the
@ -291,12 +320,12 @@ class Subchannel {
// state READY.
class HealthWatcherMap {
public:
void AddWatcherLocked(Subchannel* subchannel,
grpc_connectivity_state initial_state,
UniquePtr<char> health_check_service_name,
UniquePtr<ConnectivityStateWatcher> watcher);
void AddWatcherLocked(
Subchannel* subchannel, grpc_connectivity_state initial_state,
UniquePtr<char> health_check_service_name,
OrphanablePtr<ConnectivityStateWatcherInterface> watcher);
void RemoveWatcherLocked(const char* health_check_service_name,
ConnectivityStateWatcher* watcher);
ConnectivityStateWatcherInterface* watcher);
// Notifies the watcher when the subchannel's state changes.
void NotifyLocked(grpc_connectivity_state state);

@ -21,42 +21,22 @@
#include <grpc/support/port_platform.h>
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
namespace grpc_core {
// TODO(roth): In a subsequent PR, remove this from this API.
class ConnectedSubchannelInterface
: public RefCounted<ConnectedSubchannelInterface> {
public:
virtual const grpc_channel_args* args() const GRPC_ABSTRACT;
protected:
template <typename TraceFlagT = TraceFlag>
explicit ConnectedSubchannelInterface(TraceFlagT* trace_flag = nullptr)
: RefCounted<ConnectedSubchannelInterface>(trace_flag) {}
};
// The interface for subchannels that is exposed to LB policy implementations.
class SubchannelInterface : public RefCounted<SubchannelInterface> {
public:
class ConnectivityStateWatcher {
class ConnectivityStateWatcherInterface {
public:
virtual ~ConnectivityStateWatcher() = default;
virtual ~ConnectivityStateWatcherInterface() = default;
// Will be 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.
//
// When the state changes to READY, connected_subchannel will
// contain a ref to the connected subchannel. When it changes from
// READY to some other state, the implementation must release its
// ref to the connected subchannel.
virtual void OnConnectivityStateChange(
grpc_connectivity_state new_state,
RefCountedPtr<ConnectedSubchannelInterface>
connected_subchannel) // NOLINT
virtual void OnConnectivityStateChange(grpc_connectivity_state new_state)
GRPC_ABSTRACT;
// TODO(roth): Remove this as soon as we move to EventManager-based
@ -66,12 +46,14 @@ class SubchannelInterface : public RefCounted<SubchannelInterface> {
GRPC_ABSTRACT_BASE_CLASS
};
template <typename TraceFlagT = TraceFlag>
explicit SubchannelInterface(TraceFlagT* trace_flag = nullptr)
: RefCounted<SubchannelInterface>(trace_flag) {}
virtual ~SubchannelInterface() = default;
// Returns the current connectivity state of the subchannel.
virtual grpc_connectivity_state CheckConnectivityState(
RefCountedPtr<ConnectedSubchannelInterface>* connected_subchannel)
GRPC_ABSTRACT;
virtual grpc_connectivity_state CheckConnectivityState() GRPC_ABSTRACT;
// Starts watching the subchannel's connectivity state.
// The first callback to the watcher will be delivered when the
@ -86,21 +68,28 @@ class SubchannelInterface : public RefCounted<SubchannelInterface> {
// the previous watcher using CancelConnectivityStateWatch().
virtual void WatchConnectivityState(
grpc_connectivity_state initial_state,
UniquePtr<ConnectivityStateWatcher> watcher) GRPC_ABSTRACT;
UniquePtr<ConnectivityStateWatcherInterface> watcher) GRPC_ABSTRACT;
// Cancels a connectivity state watch.
// If the watcher has already been destroyed, this is a no-op.
virtual void CancelConnectivityStateWatch(ConnectivityStateWatcher* watcher)
GRPC_ABSTRACT;
virtual void CancelConnectivityStateWatch(
ConnectivityStateWatcherInterface* watcher) GRPC_ABSTRACT;
// Attempt to connect to the backend. Has no effect if already connected.
// If the subchannel is currently in backoff delay due to a previously
// failed attempt, the new connection attempt will not start until the
// backoff delay has elapsed.
virtual void AttemptToConnect() GRPC_ABSTRACT;
// TODO(roth): These methods should be removed from this interface to
// bettter hide grpc-specific functionality from the LB policy API.
virtual channelz::SubchannelNode* channelz_node() GRPC_ABSTRACT;
// Resets the subchannel's connection backoff state. If AttemptToConnect()
// has been called since the subchannel entered TRANSIENT_FAILURE state,
// starts a new connection attempt immediately; otherwise, a new connection
// attempt will be started as soon as AttemptToConnect() is called.
virtual void ResetBackoff() GRPC_ABSTRACT;
// TODO(roth): Need a better non-grpc-specific abstraction here.
virtual const grpc_channel_args* channel_args() GRPC_ABSTRACT;
GRPC_ABSTRACT_BASE_CLASS
};

@ -109,7 +109,6 @@ grpc_error* grpc_deframe_unprocessed_incoming_frames(
end = GRPC_SLICE_END_PTR(*slice);
cur = beg;
uint32_t message_flags;
char* msg;
if (cur == end) {
grpc_slice_buffer_remove_first(slices);
@ -132,15 +131,16 @@ grpc_error* grpc_deframe_unprocessed_incoming_frames(
p->is_frame_compressed = true; /* GPR_TRUE */
break;
default:
char* msg;
gpr_asprintf(&msg, "Bad GRPC frame type 0x%02x", p->frame_type);
p->error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
p->error = grpc_error_set_int(p->error, GRPC_ERROR_INT_STREAM_ID,
static_cast<intptr_t>(s->id));
gpr_free(msg);
msg = grpc_dump_slice(*slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
p->error = grpc_error_set_str(p->error, GRPC_ERROR_STR_RAW_BYTES,
grpc_slice_from_copied_string(msg));
gpr_free(msg);
p->error =
grpc_error_set_str(p->error, GRPC_ERROR_STR_RAW_BYTES,
grpc_dump_slice_to_slice(
*slice, GPR_DUMP_HEX | GPR_DUMP_ASCII));
p->error =
grpc_error_set_int(p->error, GRPC_ERROR_INT_OFFSET, cur - beg);
p->state = GRPC_CHTTP2_DATA_ERROR;

@ -26,6 +26,7 @@
#include <grpc/support/string_util.h>
#include "src/core/ext/transport/chttp2/transport/frame.h"
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/transport/http2_errors.h"
grpc_slice grpc_chttp2_rst_stream_create(uint32_t id, uint32_t code,
@ -102,9 +103,9 @@ grpc_error* grpc_chttp2_rst_stream_parser_parse(void* parser,
error = grpc_error_set_int(
grpc_error_set_str(GRPC_ERROR_CREATE_FROM_STATIC_STRING("RST_STREAM"),
GRPC_ERROR_STR_GRPC_MESSAGE,
grpc_slice_from_copied_string(message)),
grpc_slice_from_moved_string(
grpc_core::UniquePtr<char>(message))),
GRPC_ERROR_INT_HTTP2_ERROR, static_cast<intptr_t>(reason));
gpr_free(message);
}
grpc_chttp2_mark_stream_closed(t, s, true, true, error);
}

@ -40,12 +40,51 @@
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/surface/server.h"
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/error_utils.h"
#include "src/core/lib/uri/uri_parser.h"
namespace grpc_core {
namespace channelz {
//
// channel arg code
//
namespace {
void* parent_uuid_copy(void* p) { return p; }
void parent_uuid_destroy(void* p) {}
int parent_uuid_cmp(void* p1, void* p2) { return GPR_ICMP(p1, p2); }
const grpc_arg_pointer_vtable parent_uuid_vtable = {
parent_uuid_copy, parent_uuid_destroy, parent_uuid_cmp};
} // namespace
grpc_arg MakeParentUuidArg(intptr_t parent_uuid) {
// We would ideally like to store the uuid in an integer argument.
// Unfortunately, that won't work, because intptr_t (the type used for
// uuids) doesn't fit in an int (the type used for integer args).
// So instead, we use a hack to store it as a pointer, because
// intptr_t should be the same size as void*.
static_assert(sizeof(intptr_t) <= sizeof(void*),
"can't fit intptr_t inside of void*");
return grpc_channel_arg_pointer_create(
const_cast<char*>(GRPC_ARG_CHANNELZ_PARENT_UUID),
reinterpret_cast<void*>(parent_uuid), &parent_uuid_vtable);
}
intptr_t GetParentUuidFromArgs(const grpc_channel_args& args) {
const grpc_arg* arg =
grpc_channel_args_find(&args, GRPC_ARG_CHANNELZ_PARENT_UUID);
if (arg == nullptr || arg->type != GRPC_ARG_POINTER) return 0;
return reinterpret_cast<intptr_t>(arg->value.pointer.p);
}
//
// BaseNode
//
BaseNode::BaseNode(EntityType type) : type_(type), uuid_(-1) {
// The registry will set uuid_ under its lock.
ChannelzRegistry::Register(this);
@ -61,6 +100,10 @@ char* BaseNode::RenderJsonString() {
return json_str;
}
//
// CallCountingHelper
//
CallCountingHelper::CallCountingHelper() {
num_cores_ = GPR_MAX(1, gpr_cpu_num_cores());
per_cpu_counter_data_storage_ = static_cast<AtomicCounterData*>(
@ -137,15 +180,17 @@ void CallCountingHelper::PopulateCallCounts(grpc_json* json) {
}
}
ChannelNode::ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes,
bool is_top_level_channel)
: BaseNode(is_top_level_channel ? EntityType::kTopLevelChannel
: EntityType::kInternalChannel),
channel_(channel),
target_(UniquePtr<char>(grpc_channel_get_target(channel_))),
trace_(channel_tracer_max_nodes) {}
//
// ChannelNode
//
ChannelNode::~ChannelNode() {}
ChannelNode::ChannelNode(UniquePtr<char> target,
size_t channel_tracer_max_nodes, intptr_t parent_uuid)
: BaseNode(parent_uuid == 0 ? EntityType::kTopLevelChannel
: EntityType::kInternalChannel),
target_(std::move(target)),
trace_(channel_tracer_max_nodes),
parent_uuid_(parent_uuid) {}
grpc_json* ChannelNode::RenderJson() {
// We need to track these three json objects to build our object
@ -167,9 +212,19 @@ grpc_json* ChannelNode::RenderJson() {
GRPC_JSON_OBJECT, false);
json = data;
json_iterator = nullptr;
// template method. Child classes may override this to add their specific
// functionality.
PopulateConnectivityState(json);
// connectivity state
// If low-order bit is on, then the field is set.
int state_field = connectivity_state_.Load(MemoryOrder::RELAXED);
if ((state_field & 1) != 0) {
grpc_connectivity_state state =
static_cast<grpc_connectivity_state>(state_field >> 1);
json = grpc_json_create_child(nullptr, json, "state", nullptr,
GRPC_JSON_OBJECT, false);
grpc_json_create_child(nullptr, json, "state",
grpc_connectivity_state_name(state),
GRPC_JSON_STRING, false);
json = data;
}
// populate the target.
GPR_ASSERT(target_.get() != nullptr);
grpc_json_create_child(nullptr, json, "target", target_.get(),
@ -189,13 +244,64 @@ grpc_json* ChannelNode::RenderJson() {
return top_level_json;
}
RefCountedPtr<ChannelNode> ChannelNode::MakeChannelNode(
grpc_channel* channel, size_t channel_tracer_max_nodes,
bool is_top_level_channel) {
return MakeRefCounted<grpc_core::channelz::ChannelNode>(
channel, channel_tracer_max_nodes, is_top_level_channel);
void ChannelNode::PopulateChildRefs(grpc_json* json) {
MutexLock lock(&child_mu_);
grpc_json* json_iterator = nullptr;
if (!child_subchannels_.empty()) {
grpc_json* array_parent = grpc_json_create_child(
nullptr, json, "subchannelRef", nullptr, GRPC_JSON_ARRAY, false);
for (const auto& p : child_subchannels_) {
json_iterator =
grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr,
GRPC_JSON_OBJECT, false);
grpc_json_add_number_string_child(json_iterator, nullptr, "subchannelId",
p.first);
}
}
if (!child_channels_.empty()) {
grpc_json* array_parent = grpc_json_create_child(
nullptr, json, "channelRef", nullptr, GRPC_JSON_ARRAY, false);
json_iterator = nullptr;
for (const auto& p : child_channels_) {
json_iterator =
grpc_json_create_child(json_iterator, array_parent, nullptr, nullptr,
GRPC_JSON_OBJECT, false);
grpc_json_add_number_string_child(json_iterator, nullptr, "channelId",
p.first);
}
}
}
void ChannelNode::SetConnectivityState(grpc_connectivity_state state) {
// Store with low-order bit set to indicate that the field is set.
int state_field = (state << 1) + 1;
connectivity_state_.Store(state_field, MemoryOrder::RELAXED);
}
void ChannelNode::AddChildChannel(intptr_t child_uuid) {
MutexLock lock(&child_mu_);
child_channels_.insert(MakePair(child_uuid, true));
}
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(MakePair(child_uuid, true));
}
void ChannelNode::RemoveChildSubchannel(intptr_t child_uuid) {
MutexLock lock(&child_mu_);
child_subchannels_.erase(child_uuid);
}
//
// ServerNode
//
ServerNode::ServerNode(grpc_server* server, size_t channel_tracer_max_nodes)
: BaseNode(EntityType::kServer),
server_(server),
@ -281,8 +387,14 @@ grpc_json* ServerNode::RenderJson() {
return top_level_json;
}
static void PopulateSocketAddressJson(grpc_json* json, const char* name,
const char* addr_str) {
//
// SocketNode
//
namespace {
void PopulateSocketAddressJson(grpc_json* json, const char* name,
const char* addr_str) {
if (addr_str == nullptr) return;
grpc_json* json_iterator = nullptr;
json_iterator = grpc_json_create_child(json_iterator, json, name, nullptr,
@ -312,7 +424,6 @@ static void PopulateSocketAddressJson(grpc_json* json, const char* name,
b64_host, GRPC_JSON_STRING, true);
gpr_free(host);
gpr_free(port);
} else if (uri != nullptr && strcmp(uri->scheme, "unix") == 0) {
json_iterator = grpc_json_create_child(json_iterator, json, "uds_address",
nullptr, GRPC_JSON_OBJECT, false);
@ -332,6 +443,8 @@ static void PopulateSocketAddressJson(grpc_json* json, const char* name,
grpc_uri_destroy(uri);
}
} // namespace
SocketNode::SocketNode(UniquePtr<char> local, UniquePtr<char> remote)
: BaseNode(EntityType::kSocket),
local_(std::move(local)),
@ -448,6 +561,10 @@ grpc_json* SocketNode::RenderJson() {
return top_level_json;
}
//
// ListenSocketNode
//
ListenSocketNode::ListenSocketNode(UniquePtr<char> local_addr)
: BaseNode(EntityType::kSocket), local_addr_(std::move(local_addr)) {}

@ -26,19 +26,19 @@
#include "src/core/lib/channel/channel_trace.h"
#include "src/core/lib/gprpp/inlined_vector.h"
#include "src/core/lib/gprpp/manual_constructor.h"
#include "src/core/lib/gprpp/map.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/gprpp/sync.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/json/json.h"
// Channel arg key for client channel factory.
#define GRPC_ARG_CHANNELZ_CHANNEL_NODE_CREATION_FUNC \
"grpc.channelz_channel_node_creation_func"
// Channel arg key for channelz node.
#define GRPC_ARG_CHANNELZ_CHANNEL_NODE "grpc.channelz_channel_node"
// Channel arg key to signal that the channel is an internal channel.
#define GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL \
"grpc.channelz_channel_is_internal_channel"
// Channel arg key to encode the channelz uuid of the channel's parent.
#define GRPC_ARG_CHANNELZ_PARENT_UUID "grpc.channelz_parent_uuid"
/** This is the default value for whether or not to enable channelz. If
* GRPC_ARG_ENABLE_CHANNELZ is set, it will override this default value. */
@ -54,6 +54,10 @@ namespace grpc_core {
namespace channelz {
// Helpers for getting and setting GRPC_ARG_CHANNELZ_PARENT_UUID.
grpc_arg MakeParentUuidArg(intptr_t parent_uuid);
intptr_t GetParentUuidFromArgs(const grpc_channel_args& args);
// TODO(ncteisen), this only contains the uuids of the children for now,
// since that is all that is strictly needed. In a future enhancement we will
// add human readable names as in the channelz.proto
@ -147,38 +151,13 @@ class CallCountingHelper {
// Handles channelz bookkeeping for channels
class ChannelNode : public BaseNode {
public:
static RefCountedPtr<ChannelNode> MakeChannelNode(
grpc_channel* channel, size_t channel_tracer_max_nodes,
bool is_top_level_channel);
ChannelNode(UniquePtr<char> target, size_t channel_tracer_max_nodes,
intptr_t parent_uuid);
ChannelNode(grpc_channel* channel, size_t channel_tracer_max_nodes,
bool is_top_level_channel);
~ChannelNode() override;
intptr_t parent_uuid() const { return parent_uuid_; }
grpc_json* RenderJson() override;
// template methods. RenderJSON uses these methods to render its JSON
// representation. These are virtual so that children classes may provide
// their specific mechanism for populating these parts of the channelz
// object.
//
// ChannelNode does not have a notion of connectivity state or child refs,
// so it leaves these implementations blank.
//
// This is utilizing the template method design pattern.
//
// TODO(ncteisen): remove these template methods in favor of manual traversal
// and mutation of the grpc_json object.
virtual void PopulateConnectivityState(grpc_json* json) {}
virtual void PopulateChildRefs(grpc_json* json) {}
void MarkChannelDestroyed() {
GPR_ASSERT(channel_ != nullptr);
channel_ = nullptr;
}
bool ChannelIsDestroyed() { return channel_ == nullptr; }
// proxy methods to composed classes.
void AddTraceEvent(ChannelTrace::Severity severity, const grpc_slice& data) {
trace_.AddTraceEvent(severity, data);
@ -193,13 +172,35 @@ class ChannelNode : public BaseNode {
void RecordCallFailed() { call_counter_.RecordCallFailed(); }
void RecordCallSucceeded() { call_counter_.RecordCallSucceeded(); }
void SetConnectivityState(grpc_connectivity_state state);
void AddChildChannel(intptr_t child_uuid);
void RemoveChildChannel(intptr_t child_uuid);
void AddChildSubchannel(intptr_t child_uuid);
void RemoveChildSubchannel(intptr_t child_uuid);
private:
void PopulateChildRefs(grpc_json* json);
// to allow the channel trace test to access trace_.
friend class testing::ChannelNodePeer;
grpc_channel* channel_ = nullptr;
UniquePtr<char> target_;
CallCountingHelper call_counter_;
ChannelTrace trace_;
const intptr_t parent_uuid_;
// Least significant bit indicates whether the value is set. Remaining
// bits are a grpc_connectivity_state value.
Atomic<int> connectivity_state_{0};
Mutex child_mu_; // Guards child maps below.
// TODO(roth): We don't actually use the values here, only the keys, so
// these should be sets instead of maps, but we don't currently have a set
// implementation. Change this if/when we have one.
Map<intptr_t, bool> child_channels_;
Map<intptr_t, bool> child_subchannels_;
};
// Handles channelz bookkeeping for servers
@ -285,11 +286,6 @@ class ListenSocketNode : public BaseNode {
UniquePtr<char> local_addr_;
};
// Creation functions
typedef RefCountedPtr<ChannelNode> (*ChannelNodeCreationFunc)(grpc_channel*,
size_t, bool);
} // namespace channelz
} // namespace grpc_core

@ -18,6 +18,9 @@
#include <grpc/impl/codegen/port_platform.h>
#include <algorithm>
#include <cstring>
#include "src/core/lib/channel/channel_trace.h"
#include "src/core/lib/channel/channelz.h"
#include "src/core/lib/channel/channelz_registry.h"
@ -29,8 +32,6 @@
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <cstring>
namespace grpc_core {
namespace channelz {
namespace {
@ -51,70 +52,17 @@ ChannelzRegistry* ChannelzRegistry::Default() {
return g_channelz_registry;
}
ChannelzRegistry::ChannelzRegistry() { gpr_mu_init(&mu_); }
ChannelzRegistry::~ChannelzRegistry() { gpr_mu_destroy(&mu_); }
void ChannelzRegistry::InternalRegister(BaseNode* node) {
MutexLock lock(&mu_);
entities_.push_back(node);
node->uuid_ = ++uuid_generator_;
}
void ChannelzRegistry::MaybePerformCompactionLocked() {
constexpr double kEmptinessTheshold = 1. / 3;
double emptiness_ratio =
double(num_empty_slots_) / double(entities_.capacity());
if (emptiness_ratio > kEmptinessTheshold) {
int front = 0;
for (size_t i = 0; i < entities_.size(); ++i) {
if (entities_[i] != nullptr) {
entities_[front++] = entities_[i];
}
}
for (int i = 0; i < num_empty_slots_; ++i) {
entities_.pop_back();
}
num_empty_slots_ = 0;
}
}
int ChannelzRegistry::FindByUuidLocked(intptr_t target_uuid,
bool direct_hit_needed) {
int left = 0;
int right = int(entities_.size() - 1);
while (left <= right) {
int true_middle = left + (right - left) / 2;
int first_non_null = true_middle;
while (first_non_null < right && entities_[first_non_null] == nullptr) {
first_non_null++;
}
if (entities_[first_non_null] == nullptr) {
right = true_middle - 1;
continue;
}
intptr_t uuid = entities_[first_non_null]->uuid();
if (uuid == target_uuid) {
return int(first_non_null);
}
if (uuid < target_uuid) {
left = first_non_null + 1;
} else {
right = true_middle - 1;
}
}
return direct_hit_needed ? -1 : left;
node_map_[node->uuid_] = node;
}
void ChannelzRegistry::InternalUnregister(intptr_t uuid) {
GPR_ASSERT(uuid >= 1);
MutexLock lock(&mu_);
GPR_ASSERT(uuid <= uuid_generator_);
int idx = FindByUuidLocked(uuid, true);
GPR_ASSERT(idx >= 0);
entities_[idx] = nullptr;
num_empty_slots_++;
MaybePerformCompactionLocked();
node_map_.erase(uuid);
}
RefCountedPtr<BaseNode> ChannelzRegistry::InternalGet(intptr_t uuid) {
@ -122,12 +70,13 @@ RefCountedPtr<BaseNode> ChannelzRegistry::InternalGet(intptr_t uuid) {
if (uuid < 1 || uuid > uuid_generator_) {
return nullptr;
}
int idx = FindByUuidLocked(uuid, true);
if (idx < 0 || entities_[idx] == nullptr) 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).
if (!entities_[idx]->RefIfNonZero()) return nullptr;
return RefCountedPtr<BaseNode>(entities_[idx]);
BaseNode* node = it->second;
if (!node->RefIfNonZero()) return nullptr;
return RefCountedPtr<BaseNode>(node);
}
char* ChannelzRegistry::InternalGetTopChannels(intptr_t start_channel_id) {
@ -138,13 +87,11 @@ char* ChannelzRegistry::InternalGetTopChannels(intptr_t start_channel_id) {
RefCountedPtr<BaseNode> node_after_pagination_limit;
{
MutexLock lock(&mu_);
const int start_idx = GPR_MAX(FindByUuidLocked(start_channel_id, false), 0);
for (size_t i = start_idx; i < entities_.size(); ++i) {
if (entities_[i] != nullptr &&
entities_[i]->type() ==
grpc_core::channelz::BaseNode::EntityType::kTopLevelChannel &&
entities_[i]->uuid() >= start_channel_id &&
entities_[i]->RefIfNonZero()) {
for (auto it = node_map_.lower_bound(start_channel_id);
it != node_map_.end(); ++it) {
BaseNode* node = it->second;
if (node->type() == BaseNode::EntityType::kTopLevelChannel &&
node->RefIfNonZero()) {
// 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.
@ -152,10 +99,10 @@ char* ChannelzRegistry::InternalGetTopChannels(intptr_t start_channel_id) {
// 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.reset(entities_[i]);
node_after_pagination_limit.reset(node);
break;
}
top_level_channels.emplace_back(entities_[i]);
top_level_channels.emplace_back(node);
}
}
}
@ -186,13 +133,11 @@ char* ChannelzRegistry::InternalGetServers(intptr_t start_server_id) {
RefCountedPtr<BaseNode> node_after_pagination_limit;
{
MutexLock lock(&mu_);
const int start_idx = GPR_MAX(FindByUuidLocked(start_server_id, false), 0);
for (size_t i = start_idx; i < entities_.size(); ++i) {
if (entities_[i] != nullptr &&
entities_[i]->type() ==
grpc_core::channelz::BaseNode::EntityType::kServer &&
entities_[i]->uuid() >= start_server_id &&
entities_[i]->RefIfNonZero()) {
for (auto it = node_map_.lower_bound(start_server_id);
it != node_map_.end(); ++it) {
BaseNode* node = it->second;
if (node->type() == BaseNode::EntityType::kServer &&
node->RefIfNonZero()) {
// 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.
@ -200,10 +145,10 @@ char* ChannelzRegistry::InternalGetServers(intptr_t start_server_id) {
// 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.reset(entities_[i]);
node_after_pagination_limit.reset(node);
break;
}
servers.emplace_back(entities_[i]);
servers.emplace_back(node);
}
}
}
@ -230,9 +175,10 @@ void ChannelzRegistry::InternalLogAllEntities() {
InlinedVector<RefCountedPtr<BaseNode>, 10> nodes;
{
MutexLock lock(&mu_);
for (size_t i = 0; i < entities_.size(); ++i) {
if (entities_[i] != nullptr && entities_[i]->RefIfNonZero()) {
nodes.emplace_back(entities_[i]);
for (auto& p : node_map_) {
BaseNode* node = p.second;
if (node->RefIfNonZero()) {
nodes.emplace_back(node);
}
}
}

@ -21,19 +21,16 @@
#include <grpc/impl/codegen/port_platform.h>
#include <stdint.h>
#include "src/core/lib/channel/channel_trace.h"
#include "src/core/lib/channel/channelz.h"
#include "src/core/lib/gprpp/inlined_vector.h"
#include <stdint.h>
#include "src/core/lib/gprpp/map.h"
#include "src/core/lib/gprpp/sync.h"
namespace grpc_core {
namespace channelz {
namespace testing {
class ChannelzRegistryPeer;
}
// singleton registry object to track all objects that are needed to support
// channelz bookkeeping. All objects share globally distributed uuids.
class ChannelzRegistry {
@ -69,13 +66,6 @@ class ChannelzRegistry {
static void LogAllEntities() { Default()->InternalLogAllEntities(); }
private:
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
friend class testing::ChannelzRegistryPeer;
ChannelzRegistry();
~ChannelzRegistry();
// Returned the singleton instance of ChannelzRegistry;
static ChannelzRegistry* Default();
@ -93,22 +83,12 @@ class ChannelzRegistry {
char* InternalGetTopChannels(intptr_t start_channel_id);
char* InternalGetServers(intptr_t start_server_id);
// If entities_ has over a certain threshold of empty slots, it will
// compact the vector and move all used slots to the front.
void MaybePerformCompactionLocked();
// Performs binary search on entities_ to find the index with that uuid.
// If direct_hit_needed, then will return -1 in case of absence.
// Else, will return idx of the first uuid higher than the target.
int FindByUuidLocked(intptr_t uuid, bool direct_hit_needed);
void InternalLogAllEntities();
// protects members
gpr_mu mu_;
InlinedVector<BaseNode*, 20> entities_;
Mutex mu_;
Map<intptr_t, BaseNode*> node_map_;
intptr_t uuid_generator_ = 0;
int num_empty_slots_ = 0;
};
} // namespace channelz

@ -126,7 +126,8 @@ static void asciidump(dump_out* out, const char* buf, size_t len) {
}
}
char* gpr_dump(const char* buf, size_t len, uint32_t flags) {
char* gpr_dump_return_len(const char* buf, size_t len, uint32_t flags,
size_t* out_len) {
dump_out out = dump_out_create();
if (flags & GPR_DUMP_HEX) {
hexdump(&out, buf, len);
@ -135,9 +136,15 @@ char* gpr_dump(const char* buf, size_t len, uint32_t flags) {
asciidump(&out, buf, len);
}
dump_out_append(&out, 0);
*out_len = out.length;
return out.data;
}
char* gpr_dump(const char* buf, size_t len, uint32_t flags) {
size_t unused;
return gpr_dump_return_len(buf, len, flags, &unused);
}
int gpr_parse_bytes_to_uint32(const char* buf, size_t len, uint32_t* result) {
uint32_t out = 0;
uint32_t new_val;

@ -32,9 +32,14 @@
#define GPR_DUMP_HEX 0x00000001
#define GPR_DUMP_ASCII 0x00000002
/* Converts array buf, of length len, into a C string according to the flags.
/* Converts array buf, of length len, into a C string according to the flags.
Result should be freed with gpr_free() */
char* gpr_dump(const char* buf, size_t len, uint32_t flags);
/* Converts array buf, of length len, into a C string according to the flags.
The length of the returned buffer is stored in out_len.
Result should be freed with gpr_free() */
char* gpr_dump_return_len(const char* buf, size_t len, uint32_t flags,
size_t* out_len);
/* Parses an array of bytes into an integer (base 10). Returns 1 on success,
0 on failure. */

@ -97,6 +97,14 @@ class InlinedVector {
return data()[offset];
}
bool operator==(const InlinedVector& other) const {
if (size_ != other.size_) return false;
for (size_t i = 0; i < size_; ++i) {
if (data()[i] != other.data()[i]) return false;
}
return true;
}
void reserve(size_t capacity) {
if (capacity > capacity_) {
T* new_dynamic = static_cast<T*>(gpr_malloc(sizeof(T) * capacity));

@ -22,11 +22,15 @@
#include <grpc/support/port_platform.h>
#include <string.h>
#include <algorithm>
#include <functional>
#include <iterator>
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/gprpp/pair.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
namespace grpc_core {
struct StringLess {
@ -38,6 +42,13 @@ struct StringLess {
}
};
template <typename T>
struct RefCountedPtrLess {
bool operator()(const RefCountedPtr<T>& p1, const RefCountedPtr<T>& p2) {
return p1.get() < p2.get();
}
};
namespace testing {
class MapTest;
}
@ -52,8 +63,28 @@ class Map {
typedef Compare key_compare;
class iterator;
Map() {}
~Map() { clear(); }
// Copying not currently supported.
Map(const Map& other) = delete;
// Move support.
Map(Map&& other) : root_(other.root_), size_(other.size_) {
other.root_ = nullptr;
other.size_ = 0;
}
Map& operator=(Map&& other) {
if (this != &other) {
clear();
root_ = other.root_;
size_ = other.size_;
other.root_ = nullptr;
other.size_ = 0;
}
return *this;
}
T& operator[](key_type&& key);
T& operator[](const key_type& key);
iterator find(const key_type& k);
@ -88,6 +119,13 @@ class Map {
iterator end() { return iterator(this, nullptr); }
iterator lower_bound(const Key& k) {
key_compare compare;
return std::find_if(begin(), end(), [&k, &compare](const value_type& v) {
return !compare(v.first, k);
});
}
private:
friend class testing::MapTest;
struct Entry {

@ -29,12 +29,12 @@
// Add this to a class that want to use Delete(), but has a private or
// protected destructor.
#define GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE \
#define GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE \
template <typename T> \
friend void grpc_core::Delete(T*);
// Add this to a class that want to use New(), but has a private or
// protected constructor.
#define GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW \
#define GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW \
template <typename T, typename... Args> \
friend T* grpc_core::New(Args&&...);

@ -84,7 +84,7 @@ class InternallyRefCounted : public Orphanable {
GRPC_ABSTRACT_BASE_CLASS
protected:
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
// Allow RefCountedPtr<> to access Unref() and IncrementRefCount().
template <typename T>

@ -44,7 +44,7 @@ class PolymorphicRefCount {
GRPC_ABSTRACT_BASE_CLASS
protected:
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
virtual ~PolymorphicRefCount() = default;
};
@ -57,7 +57,7 @@ class NonPolymorphicRefCount {
GRPC_ABSTRACT_BASE_CLASS
protected:
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
~NonPolymorphicRefCount() = default;
};
@ -233,7 +233,7 @@ class RefCounted : public Impl {
GRPC_ABSTRACT_BASE_CLASS
protected:
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
// TraceFlagT is defined to accept both DebugOnlyTraceFlag and TraceFlag.
// Note: RefCount tracing is only enabled on debug builds, even when a

@ -28,6 +28,7 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/http/format_request.h"
#include "src/core/lib/http/parser.h"
#include "src/core/lib/iomgr/endpoint.h"
@ -112,12 +113,11 @@ static void append_error(internal_request* req, grpc_error* error) {
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed HTTP/1 client request");
}
grpc_resolved_address* addr = &req->addresses->addrs[req->next_address - 1];
char* addr_text = grpc_sockaddr_to_uri(addr);
grpc_core::UniquePtr<char> addr_text(grpc_sockaddr_to_uri(addr));
req->overall_error = grpc_error_add_child(
req->overall_error,
grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS,
grpc_slice_from_copied_string(addr_text)));
gpr_free(addr_text);
grpc_slice_from_moved_string(std::move(addr_text))));
}
static void do_read(internal_request* req) {

@ -133,7 +133,7 @@ class TracedBuffer {
grpc_error* shutdown_err);
private:
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW
GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW
TracedBuffer(uint32_t seq_no, void* arg)
: seq_no_(seq_no), arg_(arg), next_(nullptr) {}

@ -28,7 +28,7 @@
namespace grpc_core {
TraceFlag grpc_call_combiner_trace(false, "call_combiner");
DebugOnlyTraceFlag grpc_call_combiner_trace(false, "call_combiner");
namespace {

@ -43,7 +43,7 @@
namespace grpc_core {
extern TraceFlag grpc_call_combiner_trace;
extern DebugOnlyTraceFlag grpc_call_combiner_trace;
class CallCombiner {
public:

@ -18,6 +18,7 @@
#include <grpc/support/port_platform.h>
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/iomgr/port.h"
#ifdef GRPC_CFSTREAM
@ -47,7 +48,7 @@ void CFStreamHandle::Release(void* info) {
CFStreamHandle* CFStreamHandle::CreateStreamHandle(
CFReadStreamRef read_stream, CFWriteStreamRef write_stream) {
return new CFStreamHandle(read_stream, write_stream);
return grpc_core::New<CFStreamHandle>(read_stream, write_stream);
}
void CFStreamHandle::ReadCallback(CFReadStreamRef stream,
@ -188,7 +189,7 @@ void CFStreamHandle::Unref(const char* file, int line, const char* reason) {
reason, val, val - 1);
}
if (gpr_unref(&refcount_)) {
delete this;
grpc_core::Delete<CFStreamHandle>(this);
}
}

@ -29,6 +29,7 @@
#ifdef GRPC_CFSTREAM
#import <CoreFoundation/CoreFoundation.h>
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/iomgr/closure.h"
#include "src/core/lib/iomgr/lockfree_event.h"
@ -65,6 +66,9 @@ class CFStreamHandle final {
dispatch_queue_t dispatch_queue_;
gpr_refcount refcount_;
GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_NEW
GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
};
#ifdef DEBUG

@ -44,11 +44,11 @@ GPR_GLOBAL_CONFIG_DEFINE_STRING(
"This is a comma-separated list of engines, which are tried in priority "
"order first -> last.")
grpc_core::TraceFlag grpc_polling_trace(false,
"polling"); /* Disabled by default */
grpc_core::DebugOnlyTraceFlag grpc_polling_trace(
false, "polling"); /* Disabled by default */
/* Traces fd create/close operations */
grpc_core::TraceFlag grpc_fd_trace(false, "fd_trace");
grpc_core::DebugOnlyTraceFlag grpc_fd_trace(false, "fd_trace");
grpc_core::DebugOnlyTraceFlag grpc_trace_fd_refcount(false, "fd_refcount");
grpc_core::DebugOnlyTraceFlag grpc_polling_api_trace(false, "polling_api");

@ -32,8 +32,9 @@
GPR_GLOBAL_CONFIG_DECLARE_STRING(grpc_poll_strategy);
extern grpc_core::TraceFlag grpc_fd_trace; /* Disabled by default */
extern grpc_core::TraceFlag grpc_polling_trace; /* Disabled by default */
extern grpc_core::DebugOnlyTraceFlag grpc_fd_trace; /* Disabled by default */
extern grpc_core::DebugOnlyTraceFlag
grpc_polling_trace; /* Disabled by default */
#define GRPC_FD_TRACE(format, ...) \
if (GRPC_TRACE_FLAG_ENABLED(grpc_fd_trace)) { \

@ -24,7 +24,7 @@
#include "src/core/lib/debug/trace.h"
grpc_core::TraceFlag grpc_polling_trace(false,
"polling"); /* Disabled by default */
grpc_core::DebugOnlyTraceFlag grpc_polling_trace(
false, "polling"); /* Disabled by default */
#endif // GRPC_WINSOCK_SOCKET

@ -24,7 +24,7 @@
#include "src/core/lib/debug/trace.h"
extern grpc_core::TraceFlag grpc_polling_trace;
extern grpc_core::DebugOnlyTraceFlag grpc_polling_trace;
/* 'state' holds the to call when the fd is readable or writable respectively.
It can contain one of the following values:

@ -26,6 +26,11 @@
#define GRPC_CUSTOM_SOCKET
#endif
#endif
/* This needs to be separate from the other conditions because it needs to
* apply to custom sockets too */
#ifdef GPR_WINDOWS
#define GRPC_ARES_RESOLVE_LOCALHOST_MANUALLY 1
#endif
#if defined(GRPC_CUSTOM_SOCKET)
// Do Nothing
#elif defined(GPR_MANYLINUX1)
@ -45,7 +50,6 @@
#define GRPC_WINSOCK_SOCKET 1
#define GRPC_WINDOWS_SOCKETUTILS 1
#define GRPC_WINDOWS_SOCKET_ARES_EV_DRIVER 1
#define GRPC_ARES_RESOLVE_LOCALHOST_MANUALLY 1
#elif defined(GPR_ANDROID)
#define GRPC_HAVE_IPV6_RECVPKTINFO 1
#define GRPC_HAVE_IP_PKTINFO 1

@ -685,7 +685,6 @@ static bool tcp_write_with_timestamps(grpc_tcp* tcp, struct msghdr* msg,
uint32_t opt = grpc_core::kTimestampingSocketOptions;
if (setsockopt(tcp->fd, SOL_SOCKET, SO_TIMESTAMPING,
static_cast<void*>(&opt), sizeof(opt)) != 0) {
grpc_slice_buffer_reset_and_unref_internal(tcp->outgoing_buffer);
if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) {
gpr_log(GPR_ERROR, "Failed to set timestamping options on the socket.");
}

@ -53,7 +53,7 @@ typedef struct uv_socket_t {
char* read_buf;
size_t read_len;
bool pending_connection;
int pending_connections;
grpc_custom_socket* accept_socket;
grpc_error* accept_error;
@ -206,7 +206,7 @@ static grpc_error* uv_socket_init_helper(uv_socket_t* uv_socket, int domain) {
// Node uses a garbage collector to call destructors, so we don't
// want to hold the uv loop open with active gRPC objects.
uv_unref((uv_handle_t*)uv_socket->handle);
uv_socket->pending_connection = false;
uv_socket->pending_connections = 0;
uv_socket->accept_socket = nullptr;
uv_socket->accept_error = GRPC_ERROR_NONE;
return GRPC_ERROR_NONE;
@ -243,14 +243,14 @@ static grpc_error* uv_socket_getsockname(grpc_custom_socket* socket,
static void accept_new_connection(grpc_custom_socket* socket) {
uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
if (!uv_socket->pending_connection || !uv_socket->accept_socket) {
if (uv_socket->pending_connections == 0 || !uv_socket->accept_socket) {
return;
}
grpc_custom_socket* new_socket = uv_socket->accept_socket;
grpc_error* error = uv_socket->accept_error;
uv_socket->accept_socket = nullptr;
uv_socket->accept_error = GRPC_ERROR_NONE;
uv_socket->pending_connection = false;
uv_socket->pending_connections -= 1;
if (uv_socket->accept_error != GRPC_ERROR_NONE) {
uv_stream_t dummy_handle;
uv_accept((uv_stream_t*)uv_socket->handle, &dummy_handle);
@ -270,8 +270,6 @@ static void accept_new_connection(grpc_custom_socket* socket) {
static void uv_on_connect(uv_stream_t* server, int status) {
grpc_custom_socket* socket = (grpc_custom_socket*)server->data;
uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
GPR_ASSERT(!uv_socket->pending_connection);
uv_socket->pending_connection = true;
if (status < 0) {
switch (status) {
case UV_EINTR:
@ -281,6 +279,7 @@ static void uv_on_connect(uv_stream_t* server, int status) {
uv_socket->accept_error = tcp_error_create("accept failed", status);
}
}
uv_socket->pending_connections += 1;
accept_new_connection(socket);
}

@ -195,7 +195,7 @@ void SecurityHandshaker::HandshakeFailedLocked(grpc_error* error) {
void SecurityHandshaker::OnPeerCheckedInner(grpc_error* error) {
MutexLock lock(&mu_);
if (error != GRPC_ERROR_NONE || is_shutdown_) {
HandshakeFailedLocked(GRPC_ERROR_REF(error));
HandshakeFailedLocked(error);
return;
}
// Create zero-copy frame protector, if implemented.
@ -255,7 +255,7 @@ void SecurityHandshaker::OnPeerCheckedInner(grpc_error* error) {
void SecurityHandshaker::OnPeerCheckedFn(void* arg, grpc_error* error) {
RefCountedPtr<SecurityHandshaker>(static_cast<SecurityHandshaker*>(arg))
->OnPeerCheckedInner(error);
->OnPeerCheckedInner(GRPC_ERROR_REF(error));
}
grpc_error* SecurityHandshaker::CheckPeerLocked() {

@ -102,18 +102,19 @@ class NewSliceRefcount {
}
NewSliceRefcount(void (*destroy)(void*), void* user_data)
: rc_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this, &rc_),
: base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
&base_),
user_destroy_(destroy),
user_data_(user_data) {}
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
grpc_slice_refcount* base_refcount() { return &rc_; }
grpc_slice_refcount* base_refcount() { return &base_; }
private:
~NewSliceRefcount() { user_destroy_(user_data_); }
grpc_slice_refcount rc_;
grpc_slice_refcount base_;
RefCount refs_;
void (*user_destroy_)(void*);
void* user_data_;
@ -141,7 +142,6 @@ grpc_slice grpc_slice_new(void* p, size_t len, void (*destroy)(void*)) {
namespace grpc_core {
/* grpc_slice_new_with_len support structures - we create a refcount object
extended with the user provided data pointer & destroy function */
class NewWithLenSliceRefcount {
public:
static void Destroy(void* arg) {
@ -150,25 +150,48 @@ class NewWithLenSliceRefcount {
NewWithLenSliceRefcount(void (*destroy)(void*, size_t), void* user_data,
size_t user_length)
: rc_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this, &rc_),
: base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
&base_),
user_data_(user_data),
user_length_(user_length),
user_destroy_(destroy) {}
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
grpc_slice_refcount* base_refcount() { return &rc_; }
grpc_slice_refcount* base_refcount() { return &base_; }
private:
~NewWithLenSliceRefcount() { user_destroy_(user_data_, user_length_); }
grpc_slice_refcount rc_;
grpc_slice_refcount base_;
RefCount refs_;
void* user_data_;
size_t user_length_;
void (*user_destroy_)(void*, size_t);
};
/** grpc_slice_from_moved_(string|buffer) ref count .*/
class MovedStringSliceRefCount {
public:
MovedStringSliceRefCount(grpc_core::UniquePtr<char>&& str)
: base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
&base_),
str_(std::move(str)) {}
GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
grpc_slice_refcount* base_refcount() { return &base_; }
private:
static void Destroy(void* arg) {
Delete(static_cast<MovedStringSliceRefCount*>(arg));
}
grpc_slice_refcount base_;
grpc_core::RefCount refs_;
grpc_core::UniquePtr<char> str_;
};
} // namespace grpc_core
grpc_slice grpc_slice_new_with_len(void* p, size_t len,
@ -193,6 +216,29 @@ grpc_slice grpc_slice_from_copied_string(const char* source) {
return grpc_slice_from_copied_buffer(source, strlen(source));
}
grpc_slice grpc_slice_from_moved_buffer(grpc_core::UniquePtr<char> p,
size_t len) {
uint8_t* ptr = reinterpret_cast<uint8_t*>(p.get());
grpc_slice slice;
if (len <= sizeof(slice.data.inlined.bytes)) {
slice.refcount = nullptr;
slice.data.inlined.length = len;
memcpy(GRPC_SLICE_START_PTR(slice), ptr, len);
} else {
slice.refcount =
grpc_core::New<grpc_core::MovedStringSliceRefCount>(std::move(p))
->base_refcount();
slice.data.refcounted.bytes = ptr;
slice.data.refcounted.length = len;
}
return slice;
}
grpc_slice grpc_slice_from_moved_string(grpc_core::UniquePtr<char> p) {
const size_t len = strlen(p.get());
return grpc_slice_from_moved_buffer(std::move(p), len);
}
namespace {
class MallocRefCount {

@ -28,6 +28,7 @@
#include <string.h>
#include "src/core/lib/gpr/murmur_hash.h"
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/transport/static_metadata.h"
@ -302,6 +303,10 @@ inline uint32_t grpc_slice_hash_internal(const grpc_slice& s) {
: grpc_slice_hash_refcounted(s);
}
grpc_slice grpc_slice_from_moved_buffer(grpc_core::UniquePtr<char> p,
size_t len);
grpc_slice grpc_slice_from_moved_string(grpc_core::UniquePtr<char> p);
// Returns the memory used by this slice, not counting the slice structure
// itself. This means that inlined and slices from static strings will return
// 0. All other slices will return the size of the allocated chars.

@ -25,6 +25,7 @@
#include <grpc/support/log.h>
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/slice/slice_internal.h"
char* grpc_dump_slice(const grpc_slice& s, uint32_t flags) {
@ -32,6 +33,14 @@ char* grpc_dump_slice(const grpc_slice& s, uint32_t flags) {
GRPC_SLICE_LENGTH(s), flags);
}
grpc_slice grpc_dump_slice_to_slice(const grpc_slice& s, uint32_t flags) {
size_t len;
grpc_core::UniquePtr<char> ptr(
gpr_dump_return_len(reinterpret_cast<const char*> GRPC_SLICE_START_PTR(s),
GRPC_SLICE_LENGTH(s), flags, &len));
return grpc_slice_from_moved_buffer(std::move(ptr), len);
}
/** Finds the initial (\a begin) and final (\a end) offsets of the next
* substring from \a str + \a read_offset until the next \a sep or the end of \a
* str.

@ -31,6 +31,8 @@
/* Calls gpr_dump on a slice. */
char* grpc_dump_slice(const grpc_slice& slice, uint32_t flags);
/* Calls gpr_dump on a slice and returns the result as a slice. */
grpc_slice grpc_dump_slice_to_slice(const grpc_slice& slice, uint32_t flags);
/** Split \a str by the separator \a sep. Results are stored in \a dst, which
* should be a properly initialized instance. */

@ -33,6 +33,7 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/channel_trace.h"
#include "src/core/lib/channel/channelz.h"
#include "src/core/lib/channel/channelz_registry.h"
#include "src/core/lib/debug/stats.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/manual_constructor.h"
@ -86,18 +87,9 @@ grpc_channel* grpc_channel_create_with_builder(
grpc_channel_args_destroy(args);
return channel;
}
channel->target = target;
channel->resource_user = resource_user;
channel->is_client = grpc_channel_stack_type_is_client(channel_stack_type);
bool channelz_enabled = GRPC_ENABLE_CHANNELZ_DEFAULT;
size_t channel_tracer_max_memory =
GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT;
bool internal_channel = false;
// this creates the default ChannelNode. Different types of channels may
// override this to ensure a correct ChannelNode is created.
grpc_core::channelz::ChannelNodeCreationFunc channel_node_create_func =
grpc_core::channelz::ChannelNode::MakeChannelNode;
gpr_mu_init(&channel->registered_call_mu);
channel->registered_calls = nullptr;
@ -129,40 +121,16 @@ grpc_channel* grpc_channel_create_with_builder(
channel->compression_options.enabled_algorithms_bitset =
static_cast<uint32_t>(args->args[i].value.integer) |
0x1; /* always support no compression */
} else if (0 == strcmp(args->args[i].key,
GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE)) {
const grpc_integer_options options = {
GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT, 0, INT_MAX};
channel_tracer_max_memory =
(size_t)grpc_channel_arg_get_integer(&args->args[i], options);
} else if (0 == strcmp(args->args[i].key, GRPC_ARG_ENABLE_CHANNELZ)) {
// channelz will not be enabled by default until all concerns in
// https://github.com/grpc/grpc/issues/15986 are addressed.
channelz_enabled = grpc_channel_arg_get_bool(
&args->args[i], GRPC_ENABLE_CHANNELZ_DEFAULT);
} else if (0 == strcmp(args->args[i].key,
GRPC_ARG_CHANNELZ_CHANNEL_NODE_CREATION_FUNC)) {
} else if (0 == strcmp(args->args[i].key, GRPC_ARG_CHANNELZ_CHANNEL_NODE)) {
GPR_ASSERT(args->args[i].type == GRPC_ARG_POINTER);
GPR_ASSERT(args->args[i].value.pointer.p != nullptr);
channel_node_create_func =
reinterpret_cast<grpc_core::channelz::ChannelNodeCreationFunc>(
args->args[i].value.pointer.p);
} else if (0 == strcmp(args->args[i].key,
GRPC_ARG_CHANNELZ_CHANNEL_IS_INTERNAL_CHANNEL)) {
internal_channel = grpc_channel_arg_get_bool(&args->args[i], false);
channel->channelz_node = static_cast<grpc_core::channelz::ChannelNode*>(
args->args[i].value.pointer.p)
->Ref();
}
}
grpc_channel_args_destroy(args);
// we only need to do the channelz bookkeeping for clients here. The channelz
// bookkeeping for server channels occurs in src/core/lib/surface/server.cc
if (channelz_enabled && channel->is_client) {
channel->channelz_channel = channel_node_create_func(
channel, channel_tracer_max_memory, !internal_channel);
channel->channelz_channel->AddTraceEvent(
grpc_core::channelz::ChannelTrace::Severity::Info,
grpc_slice_from_static_string("Channel created"));
}
return channel;
}
@ -197,6 +165,71 @@ static grpc_channel_args* build_channel_args(
return grpc_channel_args_copy_and_add(input_args, new_args, num_new_args);
}
namespace {
void* channelz_node_copy(void* p) {
grpc_core::channelz::ChannelNode* node =
static_cast<grpc_core::channelz::ChannelNode*>(p);
node->Ref().release();
return p;
}
void channelz_node_destroy(void* p) {
grpc_core::channelz::ChannelNode* node =
static_cast<grpc_core::channelz::ChannelNode*>(p);
node->Unref();
}
int channelz_node_cmp(void* p1, void* p2) { return GPR_ICMP(p1, p2); }
const grpc_arg_pointer_vtable channelz_node_arg_vtable = {
channelz_node_copy, channelz_node_destroy, channelz_node_cmp};
void CreateChannelzNode(grpc_channel_stack_builder* builder) {
const grpc_channel_args* args =
grpc_channel_stack_builder_get_channel_arguments(builder);
// Check whether channelz is enabled.
const bool channelz_enabled = grpc_channel_arg_get_bool(
grpc_channel_args_find(args, GRPC_ARG_ENABLE_CHANNELZ),
GRPC_ENABLE_CHANNELZ_DEFAULT);
if (!channelz_enabled) return;
// Get parameters needed to create the channelz node.
const size_t channel_tracer_max_memory = grpc_channel_arg_get_integer(
grpc_channel_args_find(args,
GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE),
{GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT, 0, INT_MAX});
const intptr_t channelz_parent_uuid =
grpc_core::channelz::GetParentUuidFromArgs(*args);
// Create the channelz node.
grpc_core::RefCountedPtr<grpc_core::channelz::ChannelNode> channelz_node =
grpc_core::MakeRefCounted<grpc_core::channelz::ChannelNode>(
grpc_core::UniquePtr<char>(
gpr_strdup(grpc_channel_stack_builder_get_target(builder))),
channel_tracer_max_memory, channelz_parent_uuid);
channelz_node->AddTraceEvent(
grpc_core::channelz::ChannelTrace::Severity::Info,
grpc_slice_from_static_string("Channel created"));
// Update parent channel node, if any.
if (channelz_parent_uuid > 0) {
grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> parent_node =
grpc_core::channelz::ChannelzRegistry::Get(channelz_parent_uuid);
if (parent_node != nullptr) {
grpc_core::channelz::ChannelNode* parent =
static_cast<grpc_core::channelz::ChannelNode*>(parent_node.get());
parent->AddChildChannel(channelz_node->uuid());
}
}
// Add channelz node to channel args.
// We remove the arg for the parent uuid, since we no longer need it.
grpc_arg new_arg = grpc_channel_arg_pointer_create(
const_cast<char*>(GRPC_ARG_CHANNELZ_CHANNEL_NODE), channelz_node.get(),
&channelz_node_arg_vtable);
const char* args_to_remove[] = {GRPC_ARG_CHANNELZ_PARENT_UUID};
grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove(
args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), &new_arg, 1);
grpc_channel_stack_builder_set_channel_arguments(builder, new_args);
grpc_channel_args_destroy(new_args);
}
} // namespace
grpc_channel* grpc_channel_create(const char* target,
const grpc_channel_args* input_args,
grpc_channel_stack_type channel_stack_type,
@ -219,9 +252,12 @@ grpc_channel* grpc_channel_create(const char* target,
}
return nullptr;
}
grpc_channel* channel =
grpc_channel_create_with_builder(builder, channel_stack_type);
return channel;
// We only need to do this for clients here. For servers, this will be
// done in src/core/lib/surface/server.cc.
if (grpc_channel_stack_type_is_client(channel_stack_type)) {
CreateChannelzNode(builder);
}
return grpc_channel_create_with_builder(builder, channel_stack_type);
}
size_t grpc_channel_get_call_size_estimate(grpc_channel* channel) {
@ -401,12 +437,21 @@ grpc_call* grpc_channel_create_registered_call(
static void destroy_channel(void* arg, grpc_error* error) {
grpc_channel* channel = static_cast<grpc_channel*>(arg);
if (channel->channelz_channel != nullptr) {
channel->channelz_channel->AddTraceEvent(
if (channel->channelz_node != nullptr) {
if (channel->channelz_node->parent_uuid() > 0) {
grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> parent_node =
grpc_core::channelz::ChannelzRegistry::Get(
channel->channelz_node->parent_uuid());
if (parent_node != nullptr) {
grpc_core::channelz::ChannelNode* parent =
static_cast<grpc_core::channelz::ChannelNode*>(parent_node.get());
parent->RemoveChildChannel(channel->channelz_node->uuid());
}
}
channel->channelz_node->AddTraceEvent(
grpc_core::channelz::ChannelTrace::Severity::Info,
grpc_slice_from_static_string("Channel destroyed"));
channel->channelz_channel->MarkChannelDestroyed();
channel->channelz_channel.reset();
channel->channelz_node.reset();
}
grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CHANNEL(channel));
while (channel->registered_calls) {

@ -88,7 +88,7 @@ struct grpc_channel {
gpr_mu registered_call_mu;
registered_call* registered_calls;
grpc_core::RefCountedPtr<grpc_core::channelz::ChannelNode> channelz_channel;
grpc_core::RefCountedPtr<grpc_core::channelz::ChannelNode> channelz_node;
char* target;
};
@ -106,7 +106,7 @@ inline grpc_channel_stack* grpc_channel_get_channel_stack(
inline grpc_core::channelz::ChannelNode* grpc_channel_get_channelz_node(
grpc_channel* channel) {
return channel->channelz_channel.get();
return channel->channelz_node.get();
}
#ifndef NDEBUG

@ -1194,12 +1194,12 @@ void grpc_server_setup_transport(
bool has_host;
grpc_slice method;
if (rm->host != nullptr) {
host = grpc_slice_intern(grpc_slice_from_static_string(rm->host));
host = grpc_slice_from_static_string(rm->host);
has_host = true;
} else {
has_host = false;
}
method = grpc_slice_intern(grpc_slice_from_static_string(rm->method));
method = grpc_slice_from_static_string(rm->method);
hash = GRPC_MDSTR_KV_HASH(has_host ? grpc_slice_hash_internal(host) : 0,
grpc_slice_hash_internal(method));
for (probes = 0; chand->registered_methods[(hash + probes) % slots]

@ -24,6 +24,7 @@
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
@ -39,13 +40,12 @@ static grpc_error* conforms_to(const grpc_slice& slice,
int byte = idx / 8;
int bit = idx % 8;
if ((legal_bits[byte] & (1 << bit)) == 0) {
char* dump = grpc_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
grpc_error* error = grpc_error_set_str(
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(err_desc),
GRPC_ERROR_INT_OFFSET,
p - GRPC_SLICE_START_PTR(slice)),
GRPC_ERROR_STR_RAW_BYTES, grpc_slice_from_copied_string(dump));
gpr_free(dump);
GRPC_ERROR_STR_RAW_BYTES,
grpc_dump_slice_to_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII));
return error;
}
}

@ -222,7 +222,12 @@ void grpc_mdctx_global_shutdown() {
abort();
}
}
// For ASAN builds, we don't want to crash here, because that will
// prevent ASAN from providing leak detection information, which is
// far more useful than this simple assertion.
#ifndef GRPC_ASAN_ENABLED
GPR_DEBUG_ASSERT(shard->count == 0);
#endif
gpr_free(shard->elems);
}
}

@ -90,7 +90,7 @@ void grpc_stream_ref_init(grpc_stream_refcount* refcount, int initial_refs,
#endif
GRPC_CLOSURE_INIT(&refcount->destroy, cb, cb_arg, grpc_schedule_on_exec_ctx);
new (&refcount->refs) grpc_core::RefCount();
new (&refcount->refs) grpc_core::RefCount(1, &grpc_trace_stream_refcount);
new (&refcount->slice_refcount) grpc_slice_refcount(
grpc_slice_refcount::Type::REGULAR, &refcount->refs, slice_stream_destroy,
refcount, &refcount->slice_refcount);

@ -80,11 +80,13 @@ inline void grpc_stream_ref(grpc_stream_refcount* refcount,
gpr_log(GPR_DEBUG, "%s %p:%p REF %s", refcount->object_type, refcount,
refcount->destroy.cb_arg, reason);
}
refcount->refs.RefNonZero(DEBUG_LOCATION, reason);
}
#else
inline void grpc_stream_ref(grpc_stream_refcount* refcount) {
#endif
refcount->refs.RefNonZero();
}
#endif
void grpc_stream_destroy(grpc_stream_refcount* refcount);
@ -95,13 +97,17 @@ inline void grpc_stream_unref(grpc_stream_refcount* refcount,
gpr_log(GPR_DEBUG, "%s %p:%p UNREF %s", refcount->object_type, refcount,
refcount->destroy.cb_arg, reason);
}
if (GPR_UNLIKELY(refcount->refs.Unref(DEBUG_LOCATION, reason))) {
grpc_stream_destroy(refcount);
}
}
#else
inline void grpc_stream_unref(grpc_stream_refcount* refcount) {
#endif
if (GPR_UNLIKELY(refcount->refs.Unref())) {
grpc_stream_destroy(refcount);
}
}
#endif
/* Wrap a buffer that is owned by some stream object into a slice that shares
the same refcount */

@ -144,7 +144,7 @@ void ChannelResetConnectionBackoff(Channel* channel) {
// ClientRpcInfo should be set before call because set_call also checks
// whether the call has been cancelled, and if the call was cancelled, we
// should notify the interceptors too/
// should notify the interceptors too.
auto* info =
context->set_client_rpc_info(method.name(), method.method_type(), this,
interceptor_creators_, interceptor_pos);

@ -34,9 +34,6 @@
namespace grpc_impl {
class Channel;
}
namespace grpc {
class DefaultGlobalClientCallbacks final
: public ClientContext::GlobalCallbacks {
@ -46,7 +43,7 @@ class DefaultGlobalClientCallbacks final
void Destructor(ClientContext* context) override {}
};
static internal::GrpcLibraryInitializer g_gli_initializer;
static grpc::internal::GrpcLibraryInitializer g_gli_initializer;
static DefaultGlobalClientCallbacks* g_default_client_callbacks =
new DefaultGlobalClientCallbacks();
static ClientContext::GlobalCallbacks* g_client_callbacks =
@ -76,7 +73,7 @@ ClientContext::~ClientContext() {
}
std::unique_ptr<ClientContext> ClientContext::FromServerContext(
const ServerContext& context, PropagationOptions options) {
const grpc::ServerContext& context, PropagationOptions options) {
std::unique_ptr<ClientContext> ctx(new ClientContext);
ctx->propagate_from_call_ = context.call_;
ctx->propagation_options_ = options;
@ -130,7 +127,7 @@ void ClientContext::TryCancel() {
}
void ClientContext::SendCancelToInterceptors() {
internal::CancelInterceptorBatchMethods cancel_methods;
grpc::internal::CancelInterceptorBatchMethods cancel_methods;
for (size_t i = 0; i < rpc_info_.interceptors_.size(); i++) {
rpc_info_.RunInterceptor(&cancel_methods, i);
}
@ -153,4 +150,4 @@ void ClientContext::SetGlobalCallbacks(GlobalCallbacks* client_callbacks) {
g_client_callbacks = client_callbacks;
}
} // namespace grpc
} // namespace grpc_impl

@ -25,8 +25,11 @@
#include "include/grpcpp/opencensus.h"
#include "opencensus/stats/stats.h"
namespace grpc {
namespace grpc_impl {
class ServerContext;
}
namespace grpc {
// The tag keys set when recording RPC stats.
::opencensus::stats::TagKey ClientMethodTagKey();

@ -16,7 +16,7 @@
*
*/
#include <grpcpp/server_context.h>
#include <grpcpp/impl/codegen/server_context_impl.h>
#include <grpcpp/support/server_callback.h>
#include <algorithm>
@ -28,23 +28,25 @@
#include <grpc/load_reporting.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpcpp/completion_queue.h>
#include <grpcpp/impl/call.h>
#include <grpcpp/impl/codegen/completion_queue_impl.h>
#include <grpcpp/support/time.h>
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/gprpp/sync.h"
#include "src/core/lib/surface/call.h"
namespace grpc {
namespace grpc_impl {
// CompletionOp
class ServerContext::CompletionOp final : public internal::CallOpSetInterface {
class ServerContext::CompletionOp final
: public ::grpc::internal::CallOpSetInterface {
public:
// initial refs: one in the server context, one in the cq
// must ref the call before calling constructor and after deleting this
CompletionOp(internal::Call* call, internal::ServerReactor* reactor)
CompletionOp(::grpc::internal::Call* call,
::grpc::internal::ServerReactor* reactor)
: call_(*call),
reactor_(reactor),
has_tag_(false),
@ -67,7 +69,7 @@ class ServerContext::CompletionOp final : public internal::CallOpSetInterface {
}
}
void FillOps(internal::Call* call) override;
void FillOps(::grpc::internal::Call* call) override;
// This should always be arena allocated in the call, so override delete.
// But this class is not trivially destructible, so must actually call delete
@ -149,8 +151,8 @@ class ServerContext::CompletionOp final : public internal::CallOpSetInterface {
return finalized_ ? (cancelled_ != 0) : false;
}
internal::Call call_;
internal::ServerReactor* const reactor_;
::grpc::internal::Call call_;
::grpc::internal::ServerReactor* const reactor_;
bool has_tag_;
void* tag_;
void* core_cq_tag_;
@ -160,7 +162,7 @@ class ServerContext::CompletionOp final : public internal::CallOpSetInterface {
int cancelled_; // This is an int (not bool) because it is passed to core
std::function<void()> cancel_callback_;
bool done_intercepting_;
internal::InterceptorBatchMethodsImpl interceptor_methods_;
::grpc::internal::InterceptorBatchMethodsImpl interceptor_methods_;
};
void ServerContext::CompletionOp::Unref() {
@ -171,7 +173,7 @@ void ServerContext::CompletionOp::Unref() {
}
}
void ServerContext::CompletionOp::FillOps(internal::Call* call) {
void ServerContext::CompletionOp::FillOps(::grpc::internal::Call* call) {
grpc_op ops;
ops.op = GRPC_OP_RECV_CLOSE_ON_SERVER;
ops.data.recv_close_on_server.cancelled = &cancelled_;
@ -227,7 +229,7 @@ bool ServerContext::CompletionOp::FinalizeResult(void** tag, bool* status) {
}
/* Add interception point and run through interceptors */
interceptor_methods_.AddInterceptionHookPoint(
experimental::InterceptionHookPoints::POST_RECV_CLOSE);
::grpc::experimental::InterceptionHookPoints::POST_RECV_CLOSE);
if (interceptor_methods_.RunInterceptors()) {
/* No interceptors were run */
if (has_tag_) {
@ -292,9 +294,9 @@ void ServerContext::Clear() {
}
}
void ServerContext::BeginCompletionOp(internal::Call* call,
std::function<void(bool)> callback,
internal::ServerReactor* reactor) {
void ServerContext::BeginCompletionOp(
::grpc::internal::Call* call, std::function<void(bool)> callback,
::grpc::internal::ServerReactor* reactor) {
GPR_ASSERT(!completion_op_);
if (rpc_info_) {
rpc_info_->Ref();
@ -313,8 +315,8 @@ void ServerContext::BeginCompletionOp(internal::Call* call,
call->PerformOps(completion_op_);
}
internal::CompletionQueueTag* ServerContext::GetCompletionOpTag() {
return static_cast<internal::CompletionQueueTag*>(completion_op_);
::grpc::internal::CompletionQueueTag* ServerContext::GetCompletionOpTag() {
return static_cast<::grpc::internal::CompletionQueueTag*>(completion_op_);
}
void ServerContext::AddInitialMetadata(const grpc::string& key,
@ -328,7 +330,7 @@ void ServerContext::AddTrailingMetadata(const grpc::string& key,
}
void ServerContext::TryCancel() const {
internal::CancelInterceptorBatchMethods cancel_methods;
::grpc::internal::CancelInterceptorBatchMethods cancel_methods;
if (rpc_info_) {
for (size_t i = 0; i < rpc_info_->interceptors_.size(); i++) {
rpc_info_->RunInterceptor(&cancel_methods, i);
@ -398,4 +400,4 @@ void ServerContext::SetLoadReportingCosts(
}
}
} // namespace grpc
} // namespace grpc_impl

@ -36,6 +36,7 @@ using Grpc.Core.Utils;
[assembly:TypeForwardedToAttribute(typeof(CallCredentials))]
[assembly:TypeForwardedToAttribute(typeof(CallFlags))]
[assembly:TypeForwardedToAttribute(typeof(CallInvoker))]
[assembly:TypeForwardedToAttribute(typeof(CallInvokerExtensions))]
[assembly:TypeForwardedToAttribute(typeof(CallOptions))]
[assembly:TypeForwardedToAttribute(typeof(ClientInterceptorContext<,>))]
[assembly:TypeForwardedToAttribute(typeof(ContextPropagationOptions))]
@ -45,6 +46,7 @@ using Grpc.Core.Utils;
[assembly:TypeForwardedToAttribute(typeof(IAsyncStreamWriter<>))]
[assembly:TypeForwardedToAttribute(typeof(IClientStreamWriter<>))]
[assembly:TypeForwardedToAttribute(typeof(Interceptor))]
[assembly:TypeForwardedToAttribute(typeof(InterceptingCallInvoker))]
[assembly:TypeForwardedToAttribute(typeof(IServerStreamWriter<>))]
[assembly:TypeForwardedToAttribute(typeof(Marshaller<>))]
[assembly:TypeForwardedToAttribute(typeof(Marshallers))]

@ -103,7 +103,7 @@ namespace Grpc.Core
/// <summary>
/// Server requests client certificate and enforces that the client presents a
/// certificate.
/// The cerificate presented by the client is verified by the gRPC framework.
/// The certificate presented by the client is verified by the gRPC framework.
/// (For a successful connection the client needs to present a certificate that
/// can be verified against the root certificate configured by the server)
/// The client's key certificate pair must be valid for the SSL connection to

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

Loading…
Cancel
Save