grpc 1.60.2 → 1.61.0.pre2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (279) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +208 -165
  3. data/include/grpc/event_engine/event_engine.h +59 -12
  4. data/include/grpc/event_engine/internal/memory_allocator_impl.h +6 -0
  5. data/include/grpc/event_engine/internal/slice_cast.h +12 -0
  6. data/include/grpc/event_engine/memory_allocator.h +3 -1
  7. data/include/grpc/event_engine/slice.h +5 -0
  8. data/include/grpc/grpc_security.h +22 -1
  9. data/include/grpc/impl/call.h +29 -0
  10. data/include/grpc/impl/channel_arg_names.h +12 -1
  11. data/include/grpc/impl/slice_type.h +1 -1
  12. data/include/grpc/module.modulemap +1 -0
  13. data/src/core/ext/filters/backend_metrics/backend_metric_filter.cc +54 -7
  14. data/src/core/ext/filters/backend_metrics/backend_metric_filter.h +20 -6
  15. data/src/core/ext/filters/channel_idle/channel_idle_filter.cc +10 -13
  16. data/src/core/ext/filters/channel_idle/channel_idle_filter.h +18 -10
  17. data/src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc +326 -0
  18. data/src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h +143 -0
  19. data/src/core/ext/filters/client_channel/backend_metric.cc +2 -2
  20. data/src/core/ext/filters/client_channel/client_channel.cc +32 -6
  21. data/src/core/ext/filters/client_channel/client_channel_internal.h +2 -0
  22. data/src/core/ext/filters/client_channel/global_subchannel_pool.cc +1 -1
  23. data/src/core/ext/filters/client_channel/lb_policy/address_filtering.cc +54 -21
  24. data/src/core/ext/filters/client_channel/lb_policy/address_filtering.h +3 -2
  25. data/src/core/ext/filters/client_channel/lb_policy/child_policy_handler.cc +2 -1
  26. data/src/core/ext/filters/client_channel/lb_policy/endpoint_list.cc +12 -15
  27. data/src/core/ext/filters/client_channel/lb_policy/endpoint_list.h +8 -5
  28. data/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc +139 -92
  29. data/src/core/ext/filters/client_channel/lb_policy/health_check_client.cc +9 -4
  30. data/src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.cc +9 -4
  31. data/src/core/ext/filters/client_channel/lb_policy/outlier_detection/outlier_detection.cc +10 -11
  32. data/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc +94 -93
  33. data/src/core/ext/filters/client_channel/lb_policy/priority/priority.cc +5 -3
  34. data/src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc +12 -15
  35. data/src/core/ext/filters/client_channel/lb_policy/rls/rls.cc +38 -16
  36. data/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc +25 -28
  37. data/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h +10 -10
  38. data/src/core/ext/filters/client_channel/lb_policy/weighted_round_robin/weighted_round_robin.cc +37 -35
  39. data/src/core/ext/filters/client_channel/lb_policy/weighted_target/weighted_target.cc +11 -9
  40. data/src/core/ext/filters/client_channel/lb_policy/xds/cds.cc +504 -461
  41. data/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_impl.cc +232 -122
  42. data/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_manager.cc +8 -6
  43. data/src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.cc +642 -251
  44. data/src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.h +2 -6
  45. data/src/core/ext/filters/client_channel/lb_policy/xds/xds_wrr_locality.cc +7 -8
  46. data/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc +2 -1
  47. data/src/core/ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc +3 -1
  48. data/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc +2 -2
  49. data/src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc +2 -2
  50. data/src/core/ext/filters/client_channel/resolver/polling_resolver.cc +6 -8
  51. data/src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.cc +1031 -0
  52. data/src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.h +277 -0
  53. data/src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc +128 -270
  54. data/src/core/ext/filters/client_channel/resolver/xds/{xds_resolver.h → xds_resolver_attributes.h} +5 -4
  55. data/src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.cc +25 -0
  56. data/src/core/ext/filters/client_channel/resolver/xds/xds_resolver_trace.h +30 -0
  57. data/src/core/ext/filters/client_channel/retry_filter.cc +1 -0
  58. data/src/core/ext/filters/client_channel/service_config_channel_arg_filter.cc +35 -17
  59. data/src/core/ext/filters/deadline/deadline_filter.cc +12 -0
  60. data/src/core/ext/filters/fault_injection/fault_injection_filter.cc +17 -13
  61. data/src/core/ext/filters/fault_injection/fault_injection_filter.h +13 -4
  62. data/src/core/ext/filters/http/client/http_client_filter.cc +23 -32
  63. data/src/core/ext/filters/http/client/http_client_filter.h +10 -5
  64. data/src/core/ext/filters/http/client_authority_filter.cc +14 -14
  65. data/src/core/ext/filters/http/client_authority_filter.h +12 -4
  66. data/src/core/ext/filters/http/http_filters_plugin.cc +42 -20
  67. data/src/core/ext/filters/http/message_compress/compression_filter.cc +55 -80
  68. data/src/core/ext/filters/http/message_compress/compression_filter.h +54 -12
  69. data/src/core/ext/filters/http/message_compress/legacy_compression_filter.cc +325 -0
  70. data/src/core/ext/filters/http/message_compress/legacy_compression_filter.h +139 -0
  71. data/src/core/ext/filters/http/server/http_server_filter.cc +41 -41
  72. data/src/core/ext/filters/http/server/http_server_filter.h +11 -4
  73. data/src/core/ext/filters/message_size/message_size_filter.cc +56 -76
  74. data/src/core/ext/filters/message_size/message_size_filter.h +35 -23
  75. data/src/core/ext/filters/rbac/rbac_filter.cc +15 -11
  76. data/src/core/ext/filters/rbac/rbac_filter.h +11 -4
  77. data/src/core/ext/filters/server_config_selector/server_config_selector_filter.cc +25 -13
  78. data/src/core/ext/filters/stateful_session/stateful_session_filter.cc +47 -50
  79. data/src/core/ext/filters/stateful_session/stateful_session_filter.h +21 -4
  80. data/src/core/ext/transport/chttp2/alpn/alpn.cc +1 -1
  81. data/src/core/ext/transport/chttp2/client/chttp2_connector.cc +2 -2
  82. data/src/core/ext/transport/chttp2/server/chttp2_server.cc +11 -2
  83. data/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +68 -145
  84. data/src/core/ext/transport/chttp2/transport/chttp2_transport.h +3 -3
  85. data/src/core/ext/transport/chttp2/transport/flow_control.cc +21 -82
  86. data/src/core/ext/transport/chttp2/transport/flow_control.h +1 -8
  87. data/src/core/ext/transport/chttp2/transport/frame.cc +506 -0
  88. data/src/core/ext/transport/chttp2/transport/frame.h +214 -0
  89. data/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc +1 -1
  90. data/src/core/ext/transport/chttp2/transport/frame_settings.cc +33 -79
  91. data/src/core/ext/transport/chttp2/transport/frame_settings.h +4 -7
  92. data/src/core/ext/transport/chttp2/transport/hpack_parser.cc +27 -36
  93. data/src/core/ext/transport/chttp2/transport/hpack_parser.h +0 -2
  94. data/src/core/ext/transport/chttp2/transport/http2_settings.cc +122 -32
  95. data/src/core/ext/transport/chttp2/transport/http2_settings.h +142 -37
  96. data/src/core/ext/transport/chttp2/transport/internal.h +1 -22
  97. data/src/core/ext/transport/chttp2/transport/parsing.cc +23 -37
  98. data/src/core/ext/transport/chttp2/transport/writing.cc +26 -58
  99. data/src/core/ext/transport/inproc/inproc_transport.cc +172 -13
  100. data/src/core/ext/upb-gen/envoy/extensions/upstreams/http/v3/http_protocol_options.upb.h +712 -0
  101. data/src/core/ext/upb-gen/envoy/extensions/upstreams/http/v3/http_protocol_options.upb_minitable.c +151 -0
  102. data/src/core/ext/upb-gen/envoy/extensions/upstreams/http/v3/http_protocol_options.upb_minitable.h +33 -0
  103. data/src/core/ext/upbdefs-gen/envoy/extensions/upstreams/http/v3/http_protocol_options.upbdefs.c +133 -0
  104. data/src/core/ext/upbdefs-gen/envoy/extensions/upstreams/http/v3/http_protocol_options.upbdefs.h +50 -0
  105. data/src/core/ext/xds/certificate_provider_store.cc +2 -1
  106. data/src/core/ext/xds/certificate_provider_store.h +0 -5
  107. data/src/core/ext/xds/xds_api.cc +31 -18
  108. data/src/core/ext/xds/xds_api.h +2 -2
  109. data/src/core/ext/xds/xds_bootstrap.h +3 -0
  110. data/src/core/ext/xds/xds_certificate_provider.cc +88 -287
  111. data/src/core/ext/xds/xds_certificate_provider.h +44 -111
  112. data/src/core/ext/xds/xds_client.cc +420 -414
  113. data/src/core/ext/xds/xds_client.h +31 -22
  114. data/src/core/ext/xds/xds_client_grpc.cc +3 -1
  115. data/src/core/ext/xds/xds_cluster.cc +104 -11
  116. data/src/core/ext/xds/xds_cluster.h +9 -1
  117. data/src/core/ext/xds/xds_cluster_specifier_plugin.cc +9 -5
  118. data/src/core/ext/xds/xds_common_types.cc +14 -10
  119. data/src/core/ext/xds/xds_endpoint.cc +9 -4
  120. data/src/core/ext/xds/xds_endpoint.h +5 -1
  121. data/src/core/ext/xds/xds_health_status.cc +12 -2
  122. data/src/core/ext/xds/xds_health_status.h +4 -2
  123. data/src/core/ext/xds/xds_http_rbac_filter.cc +5 -3
  124. data/src/core/ext/xds/xds_listener.cc +14 -8
  125. data/src/core/ext/xds/xds_resource_type_impl.h +6 -4
  126. data/src/core/ext/xds/xds_route_config.cc +34 -22
  127. data/src/core/ext/xds/xds_route_config.h +1 -0
  128. data/src/core/ext/xds/xds_server_config_fetcher.cc +61 -57
  129. data/src/core/ext/xds/xds_transport.h +3 -0
  130. data/src/core/ext/xds/xds_transport_grpc.cc +47 -50
  131. data/src/core/ext/xds/xds_transport_grpc.h +4 -0
  132. data/src/core/lib/channel/call_tracer.cc +12 -0
  133. data/src/core/lib/channel/call_tracer.h +17 -3
  134. data/src/core/lib/channel/channel_args.cc +24 -14
  135. data/src/core/lib/channel/channel_args.h +74 -13
  136. data/src/core/lib/channel/channel_stack.cc +27 -0
  137. data/src/core/lib/channel/channel_stack.h +10 -10
  138. data/src/core/lib/channel/connected_channel.cc +64 -18
  139. data/src/core/lib/channel/promise_based_filter.h +1041 -1
  140. data/src/core/lib/channel/server_call_tracer_filter.cc +43 -35
  141. data/src/core/lib/compression/compression_internal.cc +0 -3
  142. data/src/core/lib/event_engine/ares_resolver.cc +35 -14
  143. data/src/core/lib/event_engine/ares_resolver.h +9 -10
  144. data/src/core/lib/event_engine/cf_engine/dns_service_resolver.cc +8 -1
  145. data/src/core/lib/event_engine/posix_engine/native_posix_dns_resolver.cc +132 -0
  146. data/src/core/lib/event_engine/posix_engine/native_posix_dns_resolver.h +61 -0
  147. data/src/core/lib/event_engine/posix_engine/posix_engine.cc +52 -36
  148. data/src/core/lib/event_engine/posix_engine/posix_engine.h +4 -9
  149. data/src/core/lib/event_engine/posix_engine/posix_engine_listener_utils.cc +11 -3
  150. data/src/core/lib/event_engine/posix_engine/tcp_socket_utils.cc +9 -2
  151. data/src/core/lib/event_engine/posix_engine/tcp_socket_utils.h +7 -0
  152. data/src/core/lib/event_engine/posix_engine/timer_manager.cc +17 -27
  153. data/src/core/lib/event_engine/posix_engine/timer_manager.h +0 -3
  154. data/src/core/lib/event_engine/ref_counted_dns_resolver_interface.h +55 -0
  155. data/src/core/lib/event_engine/windows/native_windows_dns_resolver.cc +114 -0
  156. data/src/core/lib/event_engine/windows/native_windows_dns_resolver.h +51 -0
  157. data/src/core/lib/event_engine/windows/windows_engine.cc +7 -7
  158. data/src/core/lib/experiments/config.cc +13 -0
  159. data/src/core/lib/experiments/config.h +3 -0
  160. data/src/core/lib/experiments/experiments.cc +245 -366
  161. data/src/core/lib/experiments/experiments.h +50 -156
  162. data/src/core/lib/gprpp/debug_location.h +13 -0
  163. data/src/core/lib/gprpp/dual_ref_counted.h +36 -7
  164. data/src/core/lib/gprpp/orphanable.h +27 -0
  165. data/src/core/lib/gprpp/ref_counted.h +63 -22
  166. data/src/core/lib/gprpp/ref_counted_ptr.h +70 -27
  167. data/src/core/lib/gprpp/ref_counted_string.h +13 -0
  168. data/src/core/lib/gprpp/status_helper.cc +1 -2
  169. data/src/core/lib/iomgr/combiner.cc +15 -51
  170. data/src/core/lib/iomgr/event_engine_shims/endpoint.cc +31 -0
  171. data/src/core/lib/iomgr/event_engine_shims/endpoint.h +16 -0
  172. data/src/core/lib/iomgr/tcp_client_posix.cc +4 -3
  173. data/src/core/lib/load_balancing/lb_policy.h +1 -1
  174. data/src/core/lib/promise/activity.cc +17 -2
  175. data/src/core/lib/promise/activity.h +5 -4
  176. data/src/core/lib/promise/all_ok.h +80 -0
  177. data/src/core/lib/promise/detail/join_state.h +2077 -0
  178. data/src/core/lib/promise/detail/promise_factory.h +1 -0
  179. data/src/core/lib/promise/detail/promise_like.h +8 -1
  180. data/src/core/lib/promise/detail/seq_state.h +3458 -150
  181. data/src/core/lib/promise/detail/status.h +42 -5
  182. data/src/core/lib/promise/for_each.h +13 -1
  183. data/src/core/lib/promise/if.h +4 -0
  184. data/src/core/lib/promise/latch.h +6 -3
  185. data/src/core/lib/promise/party.cc +33 -31
  186. data/src/core/lib/promise/party.h +142 -6
  187. data/src/core/lib/promise/poll.h +39 -13
  188. data/src/core/lib/promise/promise.h +4 -0
  189. data/src/core/lib/promise/seq.h +107 -7
  190. data/src/core/lib/promise/status_flag.h +196 -0
  191. data/src/core/lib/promise/try_join.h +132 -0
  192. data/src/core/lib/promise/try_seq.h +132 -10
  193. data/src/core/lib/resolver/endpoint_addresses.cc +0 -1
  194. data/src/core/lib/resolver/endpoint_addresses.h +48 -0
  195. data/src/core/lib/resource_quota/arena.h +2 -2
  196. data/src/core/lib/resource_quota/memory_quota.cc +57 -8
  197. data/src/core/lib/resource_quota/memory_quota.h +6 -0
  198. data/src/core/lib/security/authorization/grpc_server_authz_filter.cc +14 -11
  199. data/src/core/lib/security/authorization/grpc_server_authz_filter.h +14 -5
  200. data/src/core/lib/security/credentials/external/aws_external_account_credentials.cc +4 -0
  201. data/src/core/lib/security/credentials/external/aws_external_account_credentials.h +4 -0
  202. data/src/core/lib/security/credentials/external/external_account_credentials.cc +28 -20
  203. data/src/core/lib/security/credentials/external/external_account_credentials.h +4 -0
  204. data/src/core/lib/security/credentials/external/file_external_account_credentials.cc +4 -0
  205. data/src/core/lib/security/credentials/external/file_external_account_credentials.h +4 -0
  206. data/src/core/lib/security/credentials/external/url_external_account_credentials.cc +4 -0
  207. data/src/core/lib/security/credentials/external/url_external_account_credentials.h +4 -0
  208. data/src/core/lib/security/credentials/plugin/plugin_credentials.cc +2 -1
  209. data/src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h +0 -3
  210. data/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc +12 -0
  211. data/src/core/lib/security/credentials/tls/grpc_tls_crl_provider.cc +22 -5
  212. data/src/core/lib/security/credentials/tls/grpc_tls_crl_provider.h +1 -5
  213. data/src/core/lib/security/credentials/tls/tls_credentials.cc +16 -0
  214. data/src/core/lib/security/credentials/xds/xds_credentials.cc +21 -28
  215. data/src/core/lib/security/credentials/xds/xds_credentials.h +2 -4
  216. data/src/core/lib/security/security_connector/tls/tls_security_connector.cc +4 -3
  217. data/src/core/lib/security/transport/auth_filters.h +71 -4
  218. data/src/core/lib/security/transport/client_auth_filter.cc +2 -4
  219. data/src/core/lib/security/transport/legacy_server_auth_filter.cc +244 -0
  220. data/src/core/lib/security/transport/server_auth_filter.cc +70 -90
  221. data/src/core/lib/slice/slice_buffer.h +3 -0
  222. data/src/core/lib/surface/builtins.cc +1 -1
  223. data/src/core/lib/surface/call.cc +683 -196
  224. data/src/core/lib/surface/call.h +26 -13
  225. data/src/core/lib/surface/call_trace.cc +42 -1
  226. data/src/core/lib/surface/channel.cc +0 -1
  227. data/src/core/lib/surface/channel.h +0 -6
  228. data/src/core/lib/surface/channel_init.h +26 -0
  229. data/src/core/lib/surface/init.cc +14 -8
  230. data/src/core/lib/surface/server.cc +256 -237
  231. data/src/core/lib/surface/server.h +26 -54
  232. data/src/core/lib/surface/version.cc +2 -2
  233. data/src/core/lib/surface/wait_for_cq_end_op.h +94 -0
  234. data/src/core/lib/transport/call_final_info.cc +38 -0
  235. data/src/core/lib/transport/call_final_info.h +54 -0
  236. data/src/core/lib/transport/connectivity_state.cc +3 -2
  237. data/src/core/lib/transport/connectivity_state.h +4 -0
  238. data/src/core/lib/transport/metadata_batch.h +4 -4
  239. data/src/core/lib/transport/transport.cc +70 -19
  240. data/src/core/lib/transport/transport.h +395 -25
  241. data/src/core/plugin_registry/grpc_plugin_registry.cc +3 -0
  242. data/src/core/plugin_registry/grpc_plugin_registry_extra.cc +0 -3
  243. data/src/core/tsi/alts/handshaker/alts_handshaker_client.cc +1 -1
  244. data/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc +1 -1
  245. data/src/core/tsi/alts/handshaker/transport_security_common_api.cc +1 -1
  246. data/src/core/tsi/ssl_transport_security.cc +65 -43
  247. data/src/ruby/ext/grpc/rb_channel_args.c +3 -1
  248. data/src/ruby/ext/grpc/rb_grpc.c +0 -1
  249. data/src/ruby/ext/grpc/rb_grpc.h +0 -2
  250. data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +4 -0
  251. data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +6 -0
  252. data/src/ruby/lib/grpc/version.rb +1 -1
  253. data/third_party/upb/upb/reflection/def_pool.h +2 -2
  254. data/third_party/zlib/adler32.c +5 -27
  255. data/third_party/zlib/compress.c +5 -16
  256. data/third_party/zlib/crc32.c +86 -162
  257. data/third_party/zlib/deflate.c +233 -336
  258. data/third_party/zlib/deflate.h +8 -8
  259. data/third_party/zlib/gzguts.h +11 -12
  260. data/third_party/zlib/infback.c +7 -23
  261. data/third_party/zlib/inffast.c +1 -4
  262. data/third_party/zlib/inffast.h +1 -1
  263. data/third_party/zlib/inflate.c +30 -99
  264. data/third_party/zlib/inftrees.c +6 -11
  265. data/third_party/zlib/inftrees.h +3 -3
  266. data/third_party/zlib/trees.c +224 -302
  267. data/third_party/zlib/uncompr.c +4 -12
  268. data/third_party/zlib/zconf.h +6 -2
  269. data/third_party/zlib/zlib.h +191 -188
  270. data/third_party/zlib/zutil.c +16 -44
  271. data/third_party/zlib/zutil.h +10 -10
  272. metadata +35 -13
  273. data/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc +0 -1173
  274. data/src/core/lib/event_engine/memory_allocator.cc +0 -74
  275. data/src/core/lib/transport/pid_controller.cc +0 -51
  276. data/src/core/lib/transport/pid_controller.h +0 -116
  277. data/third_party/upb/upb/collections/array.h +0 -17
  278. data/third_party/upb/upb/collections/map.h +0 -17
  279. data/third_party/upb/upb/upb.hpp +0 -18
@@ -18,11 +18,9 @@
18
18
 
19
19
  #include "src/core/ext/filters/client_channel/lb_policy/xds/xds_override_host.h"
20
20
 
21
- #include <inttypes.h>
22
21
  #include <stddef.h>
23
22
 
24
23
  #include <algorithm>
25
- #include <atomic>
26
24
  #include <functional>
27
25
  #include <map>
28
26
  #include <memory>
@@ -34,6 +32,7 @@
34
32
  #include <vector>
35
33
 
36
34
  #include "absl/base/thread_annotations.h"
35
+ #include "absl/functional/function_ref.h"
37
36
  #include "absl/status/status.h"
38
37
  #include "absl/status/statusor.h"
39
38
  #include "absl/strings/str_cat.h"
@@ -44,13 +43,16 @@
44
43
  #include "absl/types/span.h"
45
44
  #include "absl/types/variant.h"
46
45
 
46
+ #include <grpc/event_engine/event_engine.h>
47
47
  #include <grpc/impl/connectivity_state.h>
48
48
  #include <grpc/support/log.h>
49
49
 
50
50
  #include "src/core/ext/filters/client_channel/client_channel_internal.h"
51
51
  #include "src/core/ext/filters/client_channel/lb_policy/child_policy_handler.h"
52
+ #include "src/core/ext/filters/client_channel/resolver/xds/xds_dependency_manager.h"
52
53
  #include "src/core/ext/filters/stateful_session/stateful_session_filter.h"
53
54
  #include "src/core/ext/xds/xds_health_status.h"
55
+ #include "src/core/lib/address_utils/parse_address.h"
54
56
  #include "src/core/lib/address_utils/sockaddr_utils.h"
55
57
  #include "src/core/lib/channel/channel_args.h"
56
58
  #include "src/core/lib/config/core_configuration.h"
@@ -82,6 +84,9 @@
82
84
  #include "src/core/lib/transport/connectivity_state.h"
83
85
 
84
86
  namespace grpc_core {
87
+
88
+ using ::grpc_event_engine::experimental::EventEngine;
89
+
85
90
  TraceFlag grpc_lb_xds_override_host_trace(false, "xds_override_host_lb");
86
91
 
87
92
  namespace {
@@ -102,16 +107,10 @@ struct PtrLessThan {
102
107
  }
103
108
  };
104
109
 
105
- XdsHealthStatus GetEndpointHealthStatus(const EndpointAddresses& endpoint) {
106
- return XdsHealthStatus(static_cast<XdsHealthStatus::HealthStatus>(
107
- endpoint.args()
108
- .GetInt(GRPC_ARG_XDS_HEALTH_STATUS)
109
- .value_or(XdsHealthStatus::HealthStatus::kUnknown)));
110
- }
111
-
112
110
  //
113
111
  // xds_override_host LB policy
114
112
  //
113
+
115
114
  class XdsOverrideHostLb : public LoadBalancingPolicy {
116
115
  public:
117
116
  explicit XdsOverrideHostLb(Args args);
@@ -125,12 +124,18 @@ class XdsOverrideHostLb : public LoadBalancingPolicy {
125
124
  void ResetBackoffLocked() override;
126
125
 
127
126
  private:
127
+ class SubchannelEntry;
128
+
128
129
  class SubchannelWrapper : public DelegatingSubchannel {
129
130
  public:
130
131
  SubchannelWrapper(RefCountedPtr<SubchannelInterface> subchannel,
131
132
  RefCountedPtr<XdsOverrideHostLb> policy);
132
133
 
133
- ~SubchannelWrapper() override;
134
+ // Called immediately after construction. We use two-phase initialization
135
+ // to avoid doing an allocation while holding the lock.
136
+ void set_subchannel_entry(RefCountedPtr<SubchannelEntry> subchannel_entry) {
137
+ subchannel_entry_ = std::move(subchannel_entry);
138
+ }
134
139
 
135
140
  void WatchConnectivityState(
136
141
  std::unique_ptr<ConnectivityStateWatcherInterface> watcher) override;
@@ -138,14 +143,24 @@ class XdsOverrideHostLb : public LoadBalancingPolicy {
138
143
  void CancelConnectivityStateWatch(
139
144
  ConnectivityStateWatcherInterface* watcher) override;
140
145
 
141
- grpc_connectivity_state connectivity_state() {
142
- return connectivity_state_.load();
146
+ RefCountedStringValue address_list() const
147
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsOverrideHostLb::mu_) {
148
+ return subchannel_entry_->address_list();
143
149
  }
144
150
 
145
- XdsOverrideHostLb* policy() { return policy_.get(); }
151
+ void set_last_used_time()
152
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsOverrideHostLb::mu_) {
153
+ subchannel_entry_->set_last_used_time();
154
+ }
155
+
156
+ XdsOverrideHostLb* policy() const { return policy_.get(); }
146
157
 
147
- void set_key(absl::string_view key) { key_ = std::string(key); }
148
- const absl::optional<std::string>& key() const { return key_; }
158
+ RefCountedPtr<SubchannelWrapper> Clone() const {
159
+ auto subchannel =
160
+ MakeRefCounted<SubchannelWrapper>(wrapped_subchannel(), policy_);
161
+ subchannel->set_subchannel_entry(subchannel_entry_);
162
+ return subchannel;
163
+ }
149
164
 
150
165
  private:
151
166
  class ConnectivityStateWatcher : public ConnectivityStateWatcherInterface {
@@ -155,9 +170,13 @@ class XdsOverrideHostLb : public LoadBalancingPolicy {
155
170
  : subchannel_(std::move(subchannel)) {}
156
171
 
157
172
  void OnConnectivityStateChange(grpc_connectivity_state state,
158
- absl::Status status) override;
173
+ absl::Status status) override {
174
+ subchannel_->UpdateConnectivityState(state, status);
175
+ }
159
176
 
160
- grpc_pollset_set* interested_parties() override;
177
+ grpc_pollset_set* interested_parties() override {
178
+ return subchannel_->policy()->interested_parties();
179
+ }
161
180
 
162
181
  private:
163
182
  WeakRefCountedPtr<SubchannelWrapper> subchannel_;
@@ -168,68 +187,129 @@ class XdsOverrideHostLb : public LoadBalancingPolicy {
168
187
  void UpdateConnectivityState(grpc_connectivity_state state,
169
188
  absl::Status status);
170
189
 
171
- ConnectivityStateWatcher* watcher_;
172
- absl::optional<std::string> key_;
173
190
  RefCountedPtr<XdsOverrideHostLb> policy_;
191
+ RefCountedPtr<SubchannelEntry> subchannel_entry_;
192
+ ConnectivityStateWatcher* watcher_;
174
193
  std::set<std::unique_ptr<ConnectivityStateWatcherInterface>,
175
194
  PtrLessThan<ConnectivityStateWatcherInterface>>
176
195
  watchers_;
177
- std::atomic<grpc_connectivity_state> connectivity_state_ = {
178
- GRPC_CHANNEL_IDLE};
179
196
  };
180
197
 
181
- class SubchannelEntry {
198
+ // An entry in the subchannel map.
199
+ //
200
+ // The entry may hold either an owned (RefCountedPtr<>) or unowned
201
+ // (raw pointer) SubchannelWrapper, but not both. It will be unowned
202
+ // in the case where the SubchannelWrapper is owned by the child policy.
203
+ // It will be owned in the case where the child policy has not created a
204
+ // subchannel but we have RPCs whose cookies point to that address.
205
+ //
206
+ // Note that when a SubchannelWrapper is orphaned, it will try to
207
+ // acquire the lock to remove itself from the entry. This means that
208
+ // whenever we need to remove an owned subchannel from an entry, if we
209
+ // released our ref to the SubchannelWrapper immediately, we would
210
+ // cause a deadlock, since our caller is already holding the lock. To
211
+ // avoid that, any method that may result in releasing a ref to the
212
+ // SubchannelWrapper will instead return that ref to the caller, who is
213
+ // responsible for releasing the ref after releasing the lock.
214
+ class SubchannelEntry : public RefCounted<SubchannelEntry> {
182
215
  public:
183
- explicit SubchannelEntry(XdsHealthStatus eds_health_status)
184
- : eds_health_status_(eds_health_status) {}
185
-
186
- void SetSubchannel(SubchannelWrapper* subchannel) {
187
- if (eds_health_status_.status() == XdsHealthStatus::kDraining) {
188
- subchannel_ = subchannel->Ref();
189
- } else {
190
- subchannel_ = subchannel->WeakRef();
191
- }
216
+ bool HasOwnedSubchannel() const
217
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsOverrideHostLb::mu_) {
218
+ auto* sc = absl::get_if<RefCountedPtr<SubchannelWrapper>>(&subchannel_);
219
+ return sc != nullptr && *sc != nullptr;
192
220
  }
193
221
 
194
- void UnsetSubchannel() {
195
- subchannel_ = WeakRefCountedPtr<SubchannelWrapper>(nullptr);
222
+ // Sets the unowned subchannel. If the entry previously had an
223
+ // owned subchannel, returns the ref to it.
224
+ RefCountedPtr<SubchannelWrapper> SetUnownedSubchannel(
225
+ SubchannelWrapper* subchannel)
226
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsOverrideHostLb::mu_);
227
+
228
+ // Sets the owned subchannel. Must not be called if the entry
229
+ // already has an owned subchannel.
230
+ void SetOwnedSubchannel(RefCountedPtr<SubchannelWrapper> subchannel)
231
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsOverrideHostLb::mu_) {
232
+ GPR_DEBUG_ASSERT(!HasOwnedSubchannel());
233
+ subchannel_ = std::move(subchannel);
196
234
  }
197
235
 
198
- SubchannelWrapper* GetSubchannel() const {
199
- return Match(
200
- subchannel_,
201
- [](WeakRefCountedPtr<XdsOverrideHostLb::SubchannelWrapper>
202
- subchannel) { return subchannel.get(); },
203
- [](RefCountedPtr<XdsOverrideHostLb::SubchannelWrapper> subchannel) {
204
- return subchannel.get();
205
- });
236
+ // Returns a pointer to the subchannel, regardless of whether it's
237
+ // owned or not.
238
+ SubchannelWrapper* GetSubchannel() const
239
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsOverrideHostLb::mu_);
240
+
241
+ // Returns a ref to the subchannel, regardless of whether it's owned
242
+ // or not. Returns null if there is no subchannel or if the
243
+ // subchannel's ref count is 0.
244
+ RefCountedPtr<SubchannelWrapper> GetSubchannelRef() const
245
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsOverrideHostLb::mu_);
246
+
247
+ // If the entry has an owned subchannel, moves it out of the entry
248
+ // and returns it.
249
+ RefCountedPtr<SubchannelWrapper> TakeOwnedSubchannel()
250
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsOverrideHostLb::mu_);
251
+
252
+ // Unsets the entry's subchannel.
253
+ // If the entry had an owned subchannel, moves the ref into
254
+ // owned_subchannels.
255
+ void UnsetSubchannel(
256
+ std::vector<RefCountedPtr<SubchannelWrapper>>* owned_subchannels)
257
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsOverrideHostLb::mu_);
258
+
259
+ // Called when a SubchannelWrapper is orphaned. May replace the
260
+ // unowned SubchannelWrapper with an owned one based on
261
+ // last_used_time_ and connection_idle_timeout.
262
+ void OnSubchannelWrapperOrphan(SubchannelWrapper* wrapper,
263
+ Duration connection_idle_timeout)
264
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsOverrideHostLb::mu_);
265
+
266
+ grpc_connectivity_state connectivity_state() const
267
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsOverrideHostLb::mu_) {
268
+ return connectivity_state_;
269
+ }
270
+ void set_connectivity_state(grpc_connectivity_state state)
271
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsOverrideHostLb::mu_) {
272
+ connectivity_state_ = state;
206
273
  }
207
274
 
208
- void SetEdsHealthStatus(XdsHealthStatus eds_health_status) {
275
+ XdsHealthStatus eds_health_status() const
276
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsOverrideHostLb::mu_) {
277
+ return eds_health_status_;
278
+ }
279
+ void set_eds_health_status(XdsHealthStatus eds_health_status)
280
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsOverrideHostLb::mu_) {
209
281
  eds_health_status_ = eds_health_status;
210
- auto subchannel = GetSubchannel();
211
- if (subchannel == nullptr) return;
212
- if (eds_health_status_.status() == XdsHealthStatus::kDraining) {
213
- subchannel_ = subchannel->Ref();
214
- } else {
215
- subchannel_ = subchannel->WeakRef();
216
- }
217
282
  }
218
283
 
219
- XdsHealthStatus eds_health_status() const { return eds_health_status_; }
220
-
221
- void set_address_list(RefCountedStringValue address_list) {
284
+ RefCountedStringValue address_list() const
285
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsOverrideHostLb::mu_) {
286
+ return address_list_;
287
+ }
288
+ void set_address_list(RefCountedStringValue address_list)
289
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsOverrideHostLb::mu_) {
222
290
  address_list_ = std::move(address_list);
223
291
  }
224
292
 
225
- RefCountedStringValue address_list() const { return address_list_; }
293
+ Timestamp last_used_time() const
294
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsOverrideHostLb::mu_) {
295
+ return last_used_time_;
296
+ }
297
+ void set_last_used_time()
298
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsOverrideHostLb::mu_) {
299
+ last_used_time_ = Timestamp::Now();
300
+ }
226
301
 
227
302
  private:
228
- absl::variant<WeakRefCountedPtr<SubchannelWrapper>,
229
- RefCountedPtr<SubchannelWrapper>>
230
- subchannel_;
231
- XdsHealthStatus eds_health_status_;
232
- RefCountedStringValue address_list_;
303
+ grpc_connectivity_state connectivity_state_
304
+ ABSL_GUARDED_BY(&XdsOverrideHostLb::mu_) = GRPC_CHANNEL_IDLE;
305
+ absl::variant<SubchannelWrapper*, RefCountedPtr<SubchannelWrapper>>
306
+ subchannel_ ABSL_GUARDED_BY(&XdsOverrideHostLb::mu_);
307
+ XdsHealthStatus eds_health_status_ ABSL_GUARDED_BY(
308
+ &XdsOverrideHostLb::mu_) = XdsHealthStatus(XdsHealthStatus::kUnknown);
309
+ RefCountedStringValue address_list_
310
+ ABSL_GUARDED_BY(&XdsOverrideHostLb::mu_);
311
+ Timestamp last_used_time_ ABSL_GUARDED_BY(&XdsOverrideHostLb::mu_) =
312
+ Timestamp::InfPast();
233
313
  };
234
314
 
235
315
  // A picker that wraps the picker from the child for cases when cookie is
@@ -249,8 +329,8 @@ class XdsOverrideHostLb : public LoadBalancingPolicy {
249
329
  RefCountedPtr<SubchannelWrapper> subchannel)
250
330
  : subchannel_(std::move(subchannel)) {
251
331
  GRPC_CLOSURE_INIT(&closure_, RunInExecCtx, this, nullptr);
252
- // Hop into ExecCtx, so that we're not holding the data plane mutex
253
- // while we run control-plane code.
332
+ // Hop into ExecCtx, so that we don't get stuck running
333
+ // arbitrary WorkSerializer callbacks while doing a pick.
254
334
  ExecCtx::Run(DEBUG_LOCATION, &closure_, absl::OkStatus());
255
335
  }
256
336
 
@@ -269,6 +349,33 @@ class XdsOverrideHostLb : public LoadBalancingPolicy {
269
349
  grpc_closure closure_;
270
350
  };
271
351
 
352
+ class SubchannelCreationRequester {
353
+ public:
354
+ SubchannelCreationRequester(RefCountedPtr<XdsOverrideHostLb> policy,
355
+ absl::string_view address)
356
+ : policy_(std::move(policy)), address_(address) {
357
+ GRPC_CLOSURE_INIT(&closure_, RunInExecCtx, this, nullptr);
358
+ // Hop into ExecCtx, so that we don't get stuck running
359
+ // arbitrary WorkSerializer callbacks while doing a pick.
360
+ ExecCtx::Run(DEBUG_LOCATION, &closure_, absl::OkStatus());
361
+ }
362
+
363
+ private:
364
+ static void RunInExecCtx(void* arg, grpc_error_handle /*error*/) {
365
+ auto* self = static_cast<SubchannelCreationRequester*>(arg);
366
+ self->policy_->work_serializer()->Run(
367
+ [self]() {
368
+ self->policy_->CreateSubchannelForAddress(self->address_);
369
+ delete self;
370
+ },
371
+ DEBUG_LOCATION);
372
+ }
373
+
374
+ RefCountedPtr<XdsOverrideHostLb> policy_;
375
+ std::string address_;
376
+ grpc_closure closure_;
377
+ };
378
+
272
379
  absl::optional<LoadBalancingPolicy::PickResult> PickOverridenHost(
273
380
  XdsOverrideHostAttribute* override_host_attr) const;
274
381
 
@@ -291,31 +398,45 @@ class XdsOverrideHostLb : public LoadBalancingPolicy {
291
398
  RefCountedPtr<SubchannelPicker> picker) override;
292
399
  };
293
400
 
401
+ class IdleTimer : public InternallyRefCounted<IdleTimer> {
402
+ public:
403
+ IdleTimer(RefCountedPtr<XdsOverrideHostLb> policy, Duration duration);
404
+
405
+ void Orphan() override;
406
+
407
+ private:
408
+ void OnTimerLocked();
409
+
410
+ RefCountedPtr<XdsOverrideHostLb> policy_;
411
+ absl::optional<EventEngine::TaskHandle> timer_handle_;
412
+ };
413
+
294
414
  ~XdsOverrideHostLb() override;
295
415
 
296
416
  void ShutdownLocked() override;
297
417
 
418
+ void ResetState();
419
+ void ReportTransientFailure(absl::Status status);
420
+
298
421
  OrphanablePtr<LoadBalancingPolicy> CreateChildPolicyLocked(
299
422
  const ChannelArgs& args);
300
423
 
301
424
  void MaybeUpdatePickerLocked();
302
425
 
303
- absl::StatusOr<EndpointAddressesList> UpdateAddressMap(
304
- absl::StatusOr<EndpointAddressesList> endpoints);
426
+ void UpdateAddressMap(const EndpointAddressesIterator& endpoints);
305
427
 
306
428
  RefCountedPtr<SubchannelWrapper> AdoptSubchannel(
307
429
  const grpc_resolved_address& address,
308
430
  RefCountedPtr<SubchannelInterface> subchannel);
309
431
 
310
- void UnsetSubchannel(absl::string_view key, SubchannelWrapper* subchannel);
432
+ void CreateSubchannelForAddress(absl::string_view address);
311
433
 
312
- void OnSubchannelConnectivityStateChange(absl::string_view subchannel_key)
313
- ABSL_NO_THREAD_SAFETY_ANALYSIS; // Called from within the
314
- // WorkSerializer and does not require
315
- // additional synchronization
434
+ void CleanupSubchannels();
316
435
 
317
- // Current config from the resolver.
318
- RefCountedPtr<XdsOverrideHostLbConfig> config_;
436
+ // State from most recent resolver update.
437
+ ChannelArgs args_;
438
+ XdsHealthStatusSet override_host_status_set_;
439
+ Duration connection_idle_timeout_;
319
440
 
320
441
  // Internal state.
321
442
  bool shutting_down_ = false;
@@ -326,9 +447,12 @@ class XdsOverrideHostLb : public LoadBalancingPolicy {
326
447
  grpc_connectivity_state state_ = GRPC_CHANNEL_CONNECTING;
327
448
  absl::Status status_;
328
449
  RefCountedPtr<SubchannelPicker> picker_;
329
- Mutex subchannel_map_mu_;
330
- std::map<std::string, SubchannelEntry, std::less<>> subchannel_map_
331
- ABSL_GUARDED_BY(subchannel_map_mu_);
450
+ Mutex mu_;
451
+ std::map<std::string, RefCountedPtr<SubchannelEntry>, std::less<>>
452
+ subchannel_map_ ABSL_GUARDED_BY(mu_);
453
+
454
+ // Timer handle for periodic subchannel sweep.
455
+ OrphanablePtr<IdleTimer> idle_timer_;
332
456
  };
333
457
 
334
458
  //
@@ -355,34 +479,36 @@ XdsOverrideHostLb::Picker::PickOverridenHost(
355
479
  auto cookie_address_list = override_host_attr->cookie_address_list();
356
480
  if (cookie_address_list.empty()) return absl::nullopt;
357
481
  // The cookie has an address list, so look through the addresses in order.
482
+ absl::string_view address_with_no_subchannel;
358
483
  RefCountedPtr<SubchannelWrapper> idle_subchannel;
359
484
  bool found_connecting = false;
360
485
  {
361
- MutexLock lock(&policy_->subchannel_map_mu_);
486
+ MutexLock lock(&policy_->mu_);
362
487
  for (absl::string_view address : absl::StrSplit(cookie_address_list, ',')) {
363
- RefCountedPtr<SubchannelWrapper> subchannel;
364
488
  auto it = policy_->subchannel_map_.find(address);
365
- if (it != policy_->subchannel_map_.end()) {
366
- subchannel = it->second.GetSubchannel()->RefIfNonZero();
367
- }
368
- if (subchannel == nullptr) {
369
- if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
370
- gpr_log(GPR_INFO, "Subchannel %s was not found",
371
- std::string(address).c_str());
372
- }
373
- continue;
374
- }
489
+ if (it == policy_->subchannel_map_.end()) continue;
375
490
  if (!override_host_health_status_set_.Contains(
376
- it->second.eds_health_status())) {
491
+ it->second->eds_health_status())) {
377
492
  if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
378
493
  gpr_log(GPR_INFO,
379
494
  "Subchannel %s health status is not overridden (%s)",
380
495
  std::string(address).c_str(),
381
- it->second.eds_health_status().ToString());
496
+ it->second->eds_health_status().ToString());
382
497
  }
383
498
  continue;
384
499
  }
385
- auto connectivity_state = subchannel->connectivity_state();
500
+ auto subchannel = it->second->GetSubchannelRef();
501
+ if (subchannel == nullptr) {
502
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
503
+ gpr_log(GPR_INFO, "No subchannel for %s",
504
+ std::string(address).c_str());
505
+ }
506
+ if (address_with_no_subchannel.empty()) {
507
+ address_with_no_subchannel = it->first;
508
+ }
509
+ continue;
510
+ }
511
+ auto connectivity_state = it->second->connectivity_state();
386
512
  if (connectivity_state == GRPC_CHANNEL_READY) {
387
513
  // Found a READY subchannel. Pass back the actual address list
388
514
  // and return the subchannel.
@@ -390,7 +516,8 @@ XdsOverrideHostLb::Picker::PickOverridenHost(
390
516
  gpr_log(GPR_INFO, "Picker override found READY subchannel %s",
391
517
  std::string(address).c_str());
392
518
  }
393
- override_host_attr->set_actual_address_list(it->second.address_list());
519
+ it->second->set_last_used_time();
520
+ override_host_attr->set_actual_address_list(it->second->address_list());
394
521
  return PickResult::Complete(subchannel->wrapped_subchannel());
395
522
  } else if (connectivity_state == GRPC_CHANNEL_IDLE) {
396
523
  if (idle_subchannel == nullptr) idle_subchannel = std::move(subchannel);
@@ -417,7 +544,26 @@ XdsOverrideHostLb::Picker::PickOverridenHost(
417
544
  }
418
545
  return PickResult::Queue();
419
546
  }
420
- // No READY, IDLE, or CONNECTING subchannels found.
547
+ // No READY, IDLE, or CONNECTING subchannels found. If we found an
548
+ // entry that has no subchannel, then queue the pick and trigger
549
+ // creation of a subchannel for that entry.
550
+ if (!address_with_no_subchannel.empty()) {
551
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
552
+ gpr_log(GPR_INFO, "Picker override found entry with no subchannel");
553
+ }
554
+ if (!IsWorkSerializerDispatchEnabled()) {
555
+ new SubchannelCreationRequester(policy_, address_with_no_subchannel);
556
+ } else {
557
+ policy_->work_serializer()->Run(
558
+ [policy = policy_,
559
+ address = std::string(address_with_no_subchannel)]() {
560
+ policy->CreateSubchannelForAddress(address);
561
+ },
562
+ DEBUG_LOCATION);
563
+ }
564
+ return PickResult::Queue();
565
+ }
566
+ // No entry found that was not in TRANSIENT_FAILURE.
421
567
  return absl::nullopt;
422
568
  }
423
569
 
@@ -444,15 +590,9 @@ LoadBalancingPolicy::PickResult XdsOverrideHostLb::Picker::Pick(PickArgs args) {
444
590
  // Populate the address list in the override host attribute so that
445
591
  // the StatefulSession filter can set the cookie.
446
592
  if (override_host_attr != nullptr) {
447
- auto& key = wrapper->key();
448
- if (key.has_value()) {
449
- MutexLock lock(&policy_->subchannel_map_mu_);
450
- auto it = policy_->subchannel_map_.find(*key);
451
- if (it != policy_->subchannel_map_.end()) { // Should always be true.
452
- override_host_attr->set_actual_address_list(
453
- it->second.address_list());
454
- }
455
- }
593
+ MutexLock lock(&wrapper->policy()->mu_);
594
+ wrapper->set_last_used_time();
595
+ override_host_attr->set_actual_address_list(wrapper->address_list());
456
596
  }
457
597
  // Unwrap the subchannel.
458
598
  complete_pick->subchannel = wrapper->wrapped_subchannel();
@@ -460,6 +600,56 @@ LoadBalancingPolicy::PickResult XdsOverrideHostLb::Picker::Pick(PickArgs args) {
460
600
  return result;
461
601
  }
462
602
 
603
+ //
604
+ // XdsOverrideHostLb::IdleTimer
605
+ //
606
+
607
+ XdsOverrideHostLb::IdleTimer::IdleTimer(RefCountedPtr<XdsOverrideHostLb> policy,
608
+ Duration duration)
609
+ : policy_(std::move(policy)) {
610
+ // Min time between timer runs is 5s so that we don't kill ourselves
611
+ // with lock contention and CPU usage due to sweeps over the map.
612
+ duration = std::max(duration, Duration::Seconds(5));
613
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
614
+ gpr_log(GPR_INFO,
615
+ "[xds_override_host_lb %p] idle timer %p: subchannel cleanup "
616
+ "pass will run in %s",
617
+ policy_.get(), this, duration.ToString().c_str());
618
+ }
619
+ timer_handle_ = policy_->channel_control_helper()->GetEventEngine()->RunAfter(
620
+ duration, [self = RefAsSubclass<IdleTimer>()]() mutable {
621
+ ApplicationCallbackExecCtx callback_exec_ctx;
622
+ ExecCtx exec_ctx;
623
+ auto self_ptr = self.get();
624
+ self_ptr->policy_->work_serializer()->Run(
625
+ [self = std::move(self)]() { self->OnTimerLocked(); },
626
+ DEBUG_LOCATION);
627
+ });
628
+ }
629
+
630
+ void XdsOverrideHostLb::IdleTimer::Orphan() {
631
+ if (timer_handle_.has_value()) {
632
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
633
+ gpr_log(GPR_INFO, "[xds_override_host_lb %p] idle timer %p: cancelling",
634
+ policy_.get(), this);
635
+ }
636
+ policy_->channel_control_helper()->GetEventEngine()->Cancel(*timer_handle_);
637
+ timer_handle_.reset();
638
+ }
639
+ Unref();
640
+ }
641
+
642
+ void XdsOverrideHostLb::IdleTimer::OnTimerLocked() {
643
+ if (timer_handle_.has_value()) {
644
+ timer_handle_.reset();
645
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
646
+ gpr_log(GPR_INFO, "[xds_override_host_lb %p] idle timer %p: timer fired",
647
+ policy_.get(), this);
648
+ }
649
+ policy_->CleanupSubchannels();
650
+ }
651
+ }
652
+
463
653
  //
464
654
  // XdsOverrideHostLb
465
655
  //
@@ -484,10 +674,22 @@ void XdsOverrideHostLb::ShutdownLocked() {
484
674
  gpr_log(GPR_INFO, "[xds_override_host_lb %p] shutting down", this);
485
675
  }
486
676
  shutting_down_ = true;
677
+ ResetState();
678
+ }
679
+
680
+ void XdsOverrideHostLb::ResetState() {
487
681
  {
488
- MutexLock lock(&subchannel_map_mu_);
682
+ // Drop subchannel refs after releasing the lock to avoid deadlock.
683
+ std::vector<RefCountedPtr<SubchannelWrapper>> subchannel_refs_to_drop;
684
+ MutexLock lock(&mu_);
685
+ subchannel_refs_to_drop.reserve(subchannel_map_.size());
686
+ for (auto& p : subchannel_map_) {
687
+ p.second->UnsetSubchannel(&subchannel_refs_to_drop);
688
+ }
489
689
  subchannel_map_.clear();
490
690
  }
691
+ // Cancel timer, if any.
692
+ idle_timer_.reset();
491
693
  // Remove the child policy's interested_parties pollset_set from the
492
694
  // xDS policy.
493
695
  if (child_policy_ != nullptr) {
@@ -500,6 +702,18 @@ void XdsOverrideHostLb::ShutdownLocked() {
500
702
  picker_.reset();
501
703
  }
502
704
 
705
+ void XdsOverrideHostLb::ReportTransientFailure(absl::Status status) {
706
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
707
+ gpr_log(GPR_INFO,
708
+ "[xds_override_host_lb %p] reporting TRANSIENT_FAILURE: %s", this,
709
+ status.ToString().c_str());
710
+ }
711
+ ResetState();
712
+ channel_control_helper()->UpdateState(
713
+ GRPC_CHANNEL_TRANSIENT_FAILURE, status,
714
+ MakeRefCounted<TransientFailurePicker>(status));
715
+ }
716
+
503
717
  void XdsOverrideHostLb::ExitIdleLocked() {
504
718
  if (child_policy_ != nullptr) child_policy_->ExitIdleLocked();
505
719
  }
@@ -508,29 +722,99 @@ void XdsOverrideHostLb::ResetBackoffLocked() {
508
722
  if (child_policy_ != nullptr) child_policy_->ResetBackoffLocked();
509
723
  }
510
724
 
725
+ XdsHealthStatus GetEndpointHealthStatus(const EndpointAddresses& endpoint) {
726
+ return XdsHealthStatus(static_cast<XdsHealthStatus::HealthStatus>(
727
+ endpoint.args()
728
+ .GetInt(GRPC_ARG_XDS_HEALTH_STATUS)
729
+ .value_or(XdsHealthStatus::HealthStatus::kUnknown)));
730
+ }
731
+
732
+ // Wraps the endpoint iterator and filters out endpoints in state DRAINING.
733
+ class ChildEndpointIterator : public EndpointAddressesIterator {
734
+ public:
735
+ explicit ChildEndpointIterator(
736
+ std::shared_ptr<EndpointAddressesIterator> parent_it)
737
+ : parent_it_(std::move(parent_it)) {}
738
+
739
+ void ForEach(absl::FunctionRef<void(const EndpointAddresses&)> callback)
740
+ const override {
741
+ parent_it_->ForEach([&](const EndpointAddresses& endpoint) {
742
+ XdsHealthStatus status = GetEndpointHealthStatus(endpoint);
743
+ if (status.status() != XdsHealthStatus::kDraining) {
744
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
745
+ gpr_log(GPR_INFO,
746
+ "[xds_override_host_lb %p] endpoint %s: not draining, "
747
+ "passing to child",
748
+ this, endpoint.ToString().c_str());
749
+ }
750
+ callback(endpoint);
751
+ }
752
+ });
753
+ }
754
+
755
+ private:
756
+ std::shared_ptr<EndpointAddressesIterator> parent_it_;
757
+ };
758
+
511
759
  absl::Status XdsOverrideHostLb::UpdateLocked(UpdateArgs args) {
512
760
  if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
513
- gpr_log(GPR_INFO,
514
- "[xds_override_host_lb %p] Received update with %" PRIuPTR
515
- " addresses",
516
- this, args.addresses.ok() ? args.addresses->size() : 0);
517
- }
518
- auto old_config = std::move(config_);
519
- // Update config.
520
- config_ = std::move(args.config);
521
- if (config_ == nullptr) {
761
+ gpr_log(GPR_INFO, "[xds_override_host_lb %p] Received update", this);
762
+ }
763
+ // Grab new LB policy config.
764
+ if (args.config == nullptr) {
522
765
  return absl::InvalidArgumentError("Missing policy config");
523
766
  }
767
+ auto new_config = args.config.TakeAsSubclass<XdsOverrideHostLbConfig>();
768
+ // Get xDS config.
769
+ auto new_xds_config =
770
+ args.args.GetObjectRef<XdsDependencyManager::XdsConfig>();
771
+ if (new_xds_config == nullptr) {
772
+ // Should never happen.
773
+ absl::Status status = absl::InternalError(
774
+ "xDS config not passed to xds_cluster_impl LB policy");
775
+ ReportTransientFailure(status);
776
+ return status;
777
+ }
778
+ auto it = new_xds_config->clusters.find(new_config->cluster_name());
779
+ if (it == new_xds_config->clusters.end() || !it->second.ok() ||
780
+ it->second->cluster == nullptr) {
781
+ // Should never happen.
782
+ absl::Status status = absl::InternalError(absl::StrCat(
783
+ "xDS config has no entry for cluster ", new_config->cluster_name()));
784
+ ReportTransientFailure(status);
785
+ return status;
786
+ }
787
+ args_ = std::move(args.args);
788
+ override_host_status_set_ = it->second->cluster->override_host_statuses;
789
+ connection_idle_timeout_ = it->second->cluster->connection_idle_timeout;
790
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
791
+ gpr_log(GPR_INFO,
792
+ "[xds_override_host_lb %p] override host status set: %s "
793
+ "connection idle timeout: %s",
794
+ this, override_host_status_set_.ToString().c_str(),
795
+ connection_idle_timeout_.ToString().c_str());
796
+ }
797
+ // Update address map and wrap endpoint iterator for child policy.
798
+ if (args.addresses.ok()) {
799
+ UpdateAddressMap(**args.addresses);
800
+ args.addresses =
801
+ std::make_shared<ChildEndpointIterator>(std::move(*args.addresses));
802
+ } else {
803
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
804
+ gpr_log(GPR_INFO, "[xds_override_host_lb %p] address error: %s", this,
805
+ args.addresses.status().ToString().c_str());
806
+ }
807
+ }
524
808
  // Create child policy if needed.
525
809
  if (child_policy_ == nullptr) {
526
810
  child_policy_ = CreateChildPolicyLocked(args.args);
527
811
  }
528
812
  // Update child policy.
529
813
  UpdateArgs update_args;
530
- update_args.addresses = UpdateAddressMap(std::move(args.addresses));
814
+ update_args.addresses = std::move(args.addresses);
531
815
  update_args.resolution_note = std::move(args.resolution_note);
532
- update_args.config = config_->child_config();
533
- update_args.args = std::move(args.args);
816
+ update_args.config = new_config->child_config();
817
+ update_args.args = args_;
534
818
  if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
535
819
  gpr_log(GPR_INFO,
536
820
  "[xds_override_host_lb %p] Updating child policy handler %p", this,
@@ -542,7 +826,7 @@ absl::Status XdsOverrideHostLb::UpdateLocked(UpdateArgs args) {
542
826
  void XdsOverrideHostLb::MaybeUpdatePickerLocked() {
543
827
  if (picker_ != nullptr) {
544
828
  auto xds_override_host_picker = MakeRefCounted<Picker>(
545
- Ref(), picker_, config_->override_host_status_set());
829
+ RefAsSubclass<XdsOverrideHostLb>(), picker_, override_host_status_set_);
546
830
  if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
547
831
  gpr_log(GPR_INFO,
548
832
  "[xds_override_host_lb %p] updating connectivity: state=%s "
@@ -560,8 +844,8 @@ OrphanablePtr<LoadBalancingPolicy> XdsOverrideHostLb::CreateChildPolicyLocked(
560
844
  LoadBalancingPolicy::Args lb_policy_args;
561
845
  lb_policy_args.work_serializer = work_serializer();
562
846
  lb_policy_args.args = args;
563
- lb_policy_args.channel_control_helper =
564
- std::make_unique<Helper>(Ref(DEBUG_LOCATION, "Helper"));
847
+ lb_policy_args.channel_control_helper = std::make_unique<Helper>(
848
+ RefAsSubclass<XdsOverrideHostLb>(DEBUG_LOCATION, "Helper"));
565
849
  OrphanablePtr<LoadBalancingPolicy> lb_policy =
566
850
  MakeOrphanable<ChildPolicyHandler>(std::move(lb_policy_args),
567
851
  &grpc_lb_xds_override_host_trace);
@@ -578,18 +862,9 @@ OrphanablePtr<LoadBalancingPolicy> XdsOverrideHostLb::CreateChildPolicyLocked(
578
862
  return lb_policy;
579
863
  }
580
864
 
581
- absl::StatusOr<EndpointAddressesList> XdsOverrideHostLb::UpdateAddressMap(
582
- absl::StatusOr<EndpointAddressesList> endpoints) {
583
- if (!endpoints.ok()) {
584
- if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
585
- gpr_log(GPR_INFO, "[xds_override_host_lb %p] address error: %s", this,
586
- endpoints.status().ToString().c_str());
587
- }
588
- return endpoints;
589
- }
590
- // Construct the list of addresses to pass to the child policy and a
591
- // map of address info from which to update subchannel_map_.
592
- EndpointAddressesList child_addresses;
865
+ void XdsOverrideHostLb::UpdateAddressMap(
866
+ const EndpointAddressesIterator& endpoints) {
867
+ // Construct a map of address info from which to update subchannel_map_.
593
868
  struct AddressInfo {
594
869
  XdsHealthStatus eds_health_status;
595
870
  RefCountedStringValue address_list;
@@ -597,36 +872,31 @@ absl::StatusOr<EndpointAddressesList> XdsOverrideHostLb::UpdateAddressMap(
597
872
  : eds_health_status(status), address_list(std::move(addresses)) {}
598
873
  };
599
874
  std::map<const std::string, AddressInfo> addresses_for_map;
600
- for (const auto& endpoint : *endpoints) {
875
+ endpoints.ForEach([&](const EndpointAddresses& endpoint) {
601
876
  XdsHealthStatus status = GetEndpointHealthStatus(endpoint);
602
- if (status.status() != XdsHealthStatus::kDraining) {
603
- if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
604
- gpr_log(GPR_INFO,
605
- "[xds_override_host_lb %p] endpoint %s: not draining, "
606
- "passing to child",
607
- this, endpoint.ToString().c_str());
608
- }
609
- child_addresses.push_back(endpoint);
610
- } else if (!config_->override_host_status_set().Contains(status)) {
611
- // Skip draining hosts if not in the override status set.
877
+ // Skip draining hosts if not in the override status set.
878
+ if (status.status() == XdsHealthStatus::kDraining &&
879
+ !override_host_status_set_.Contains(status)) {
612
880
  if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
613
881
  gpr_log(GPR_INFO,
614
882
  "[xds_override_host_lb %p] endpoint %s: draining but not in "
615
883
  "override_host_status set -- ignoring",
616
884
  this, endpoint.ToString().c_str());
617
885
  }
618
- continue;
886
+ return;
619
887
  }
620
888
  std::vector<std::string> addresses;
621
889
  addresses.reserve(endpoint.addresses().size());
622
890
  for (const auto& address : endpoint.addresses()) {
623
891
  auto key = grpc_sockaddr_to_string(&address, /*normalize=*/false);
624
- if (key.ok()) {
892
+ if (!key.ok()) {
625
893
  if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
626
894
  gpr_log(GPR_INFO,
627
- "[xds_override_host_lb %p] endpoint %s: adding map key %s",
628
- this, endpoint.ToString().c_str(), key->c_str());
895
+ "[xds_override_host_lb %p] no key for endpoint address; "
896
+ "not adding to map",
897
+ this);
629
898
  }
899
+ } else {
630
900
  addresses.push_back(*std::move(key));
631
901
  }
632
902
  }
@@ -641,16 +911,22 @@ absl::StatusOr<EndpointAddressesList> XdsOverrideHostLb::UpdateAddressMap(
641
911
  std::piecewise_construct, std::forward_as_tuple(addresses[i]),
642
912
  std::forward_as_tuple(status, std::move(address_list)));
643
913
  }
644
- }
914
+ });
645
915
  // Now grab the lock and update subchannel_map_ from addresses_for_map.
916
+ const Timestamp now = Timestamp::Now();
917
+ const Timestamp idle_threshold = now - connection_idle_timeout_;
918
+ Duration next_time = connection_idle_timeout_;
646
919
  {
647
- MutexLock lock(&subchannel_map_mu_);
920
+ // Drop subchannel refs after releasing the lock to avoid deadlock.
921
+ std::vector<RefCountedPtr<SubchannelWrapper>> subchannel_refs_to_drop;
922
+ MutexLock lock(&mu_);
648
923
  for (auto it = subchannel_map_.begin(); it != subchannel_map_.end();) {
649
924
  if (addresses_for_map.find(it->first) == addresses_for_map.end()) {
650
925
  if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
651
926
  gpr_log(GPR_INFO, "[xds_override_host_lb %p] removing map key %s",
652
927
  this, it->first.c_str());
653
928
  }
929
+ it->second->UnsetSubchannel(&subchannel_refs_to_drop);
654
930
  it = subchannel_map_.erase(it);
655
931
  } else {
656
932
  ++it;
@@ -665,70 +941,116 @@ absl::StatusOr<EndpointAddressesList> XdsOverrideHostLb::UpdateAddressMap(
665
941
  gpr_log(GPR_INFO, "[xds_override_host_lb %p] adding map key %s", this,
666
942
  address.c_str());
667
943
  }
668
- it = subchannel_map_
669
- .emplace(std::piecewise_construct,
670
- std::forward_as_tuple(address),
671
- std::forward_as_tuple(address_info.eds_health_status))
944
+ it = subchannel_map_.emplace(address, MakeRefCounted<SubchannelEntry>())
672
945
  .first;
673
- } else {
674
- if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
675
- gpr_log(GPR_INFO,
676
- "[xds_override_host_lb %p] setting EDS health status for "
677
- "%s to %s",
678
- this, address.c_str(),
679
- address_info.eds_health_status.ToString());
680
- }
681
- it->second.SetEdsHealthStatus(address_info.eds_health_status);
682
946
  }
683
947
  if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
684
948
  gpr_log(GPR_INFO,
685
- "[xds_override_host_lb %p] setting address list for %s to %s",
686
- this, address.c_str(), address_info.address_list.c_str());
949
+ "[xds_override_host_lb %p] map key %s: setting "
950
+ "eds_health_status=%s address_list=%s",
951
+ this, address.c_str(),
952
+ address_info.eds_health_status.ToString(),
953
+ address_info.address_list.c_str());
954
+ }
955
+ it->second->set_eds_health_status(address_info.eds_health_status);
956
+ it->second->set_address_list(std::move(address_info.address_list));
957
+ // Check the entry's last_used_time to determine the next time at
958
+ // which the timer needs to run.
959
+ if (it->second->last_used_time() > idle_threshold) {
960
+ const Duration next_time_for_entry =
961
+ it->second->last_used_time() + connection_idle_timeout_ - now;
962
+ next_time = std::min(next_time, next_time_for_entry);
687
963
  }
688
- it->second.set_address_list(std::move(address_info.address_list));
689
964
  }
690
965
  }
691
- return child_addresses;
966
+ idle_timer_ =
967
+ MakeOrphanable<IdleTimer>(RefAsSubclass<XdsOverrideHostLb>(), next_time);
692
968
  }
693
969
 
694
970
  RefCountedPtr<XdsOverrideHostLb::SubchannelWrapper>
695
971
  XdsOverrideHostLb::AdoptSubchannel(
696
972
  const grpc_resolved_address& address,
697
973
  RefCountedPtr<SubchannelInterface> subchannel) {
974
+ auto wrapper = MakeRefCounted<SubchannelWrapper>(
975
+ std::move(subchannel), RefAsSubclass<XdsOverrideHostLb>());
698
976
  auto key = grpc_sockaddr_to_string(&address, /*normalize=*/false);
699
- auto wrapper =
700
- MakeRefCounted<SubchannelWrapper>(std::move(subchannel), Ref());
701
977
  if (key.ok()) {
702
- MutexLock lock(&subchannel_map_mu_);
978
+ // Drop ref to previously owned subchannel (if any) after releasing
979
+ // the lock.
980
+ RefCountedPtr<SubchannelWrapper> subchannel_ref_to_drop;
981
+ MutexLock lock(&mu_);
703
982
  auto it = subchannel_map_.find(*key);
704
983
  if (it != subchannel_map_.end()) {
705
- wrapper->set_key(*key);
706
- it->second.SetSubchannel(wrapper.get());
984
+ wrapper->set_subchannel_entry(it->second);
985
+ subchannel_ref_to_drop = it->second->SetUnownedSubchannel(wrapper.get());
707
986
  }
708
987
  }
709
988
  return wrapper;
710
989
  }
711
990
 
712
- void XdsOverrideHostLb::UnsetSubchannel(absl::string_view key,
713
- SubchannelWrapper* subchannel) {
714
- MutexLock lock(&subchannel_map_mu_);
715
- auto it = subchannel_map_.find(key);
716
- if (it != subchannel_map_.end()) {
717
- if (subchannel == it->second.GetSubchannel()) {
718
- it->second.UnsetSubchannel();
719
- }
991
+ void XdsOverrideHostLb::CreateSubchannelForAddress(absl::string_view address) {
992
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
993
+ gpr_log(GPR_INFO,
994
+ "[xds_override_host_lb %p] creating owned subchannel for %s", this,
995
+ std::string(address).c_str());
996
+ }
997
+ auto addr = StringToSockaddr(address);
998
+ GPR_ASSERT(addr.ok());
999
+ // Note: We don't currently have any cases where per_address_args need to
1000
+ // be passed through. If we encounter any such cases in the future, we
1001
+ // will need to change this to store those attributes from the resolver
1002
+ // update in the map entry.
1003
+ auto subchannel = channel_control_helper()->CreateSubchannel(
1004
+ *addr, /*per_address_args=*/ChannelArgs(), args_);
1005
+ auto wrapper = MakeRefCounted<SubchannelWrapper>(
1006
+ std::move(subchannel), RefAsSubclass<XdsOverrideHostLb>());
1007
+ {
1008
+ MutexLock lock(&mu_);
1009
+ auto it = subchannel_map_.find(address);
1010
+ // This can happen if the map entry was removed between the time that
1011
+ // the picker requested the subchannel creation and the time that we got
1012
+ // here. In that case, we can just make it a no-op, since the update
1013
+ // that removed the entry will have generated a new picker already.
1014
+ if (it == subchannel_map_.end()) return;
1015
+ // This can happen if the picker requests subchannel creation for
1016
+ // the same address multiple times.
1017
+ if (it->second->HasOwnedSubchannel()) return;
1018
+ wrapper->set_subchannel_entry(it->second);
1019
+ it->second->SetOwnedSubchannel(std::move(wrapper));
720
1020
  }
1021
+ MaybeUpdatePickerLocked();
721
1022
  }
722
1023
 
723
- void XdsOverrideHostLb::OnSubchannelConnectivityStateChange(
724
- absl::string_view subchannel_key) {
725
- auto it = subchannel_map_.find(subchannel_key);
726
- if (it == subchannel_map_.end()) {
727
- return;
728
- }
729
- if (it->second.eds_health_status().status() == XdsHealthStatus::kDraining) {
730
- MaybeUpdatePickerLocked();
1024
+ void XdsOverrideHostLb::CleanupSubchannels() {
1025
+ const Timestamp now = Timestamp::Now();
1026
+ const Timestamp idle_threshold = now - connection_idle_timeout_;
1027
+ Duration next_time = connection_idle_timeout_;
1028
+ std::vector<RefCountedPtr<SubchannelWrapper>> subchannel_refs_to_drop;
1029
+ {
1030
+ MutexLock lock(&mu_);
1031
+ if (subchannel_map_.empty()) return;
1032
+ for (const auto& p : subchannel_map_) {
1033
+ if (p.second->last_used_time() <= idle_threshold) {
1034
+ auto subchannel = p.second->TakeOwnedSubchannel();
1035
+ if (subchannel != nullptr) {
1036
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
1037
+ gpr_log(GPR_INFO,
1038
+ "[xds_override_host_lb %p] dropping subchannel for %s",
1039
+ this, p.first.c_str());
1040
+ }
1041
+ subchannel_refs_to_drop.push_back(std::move(subchannel));
1042
+ }
1043
+ } else {
1044
+ // Not dropping the subchannel. Check the entry's last_used_time to
1045
+ // determine the next time at which the timer needs to run.
1046
+ const Duration next_time_for_entry =
1047
+ p.second->last_used_time() + connection_idle_timeout_ - now;
1048
+ next_time = std::min(next_time, next_time_for_entry);
1049
+ }
1050
+ }
731
1051
  }
1052
+ idle_timer_ =
1053
+ MakeOrphanable<IdleTimer>(RefAsSubclass<XdsOverrideHostLb>(), next_time);
732
1054
  }
733
1055
 
734
1056
  //
@@ -738,6 +1060,14 @@ void XdsOverrideHostLb::OnSubchannelConnectivityStateChange(
738
1060
  RefCountedPtr<SubchannelInterface> XdsOverrideHostLb::Helper::CreateSubchannel(
739
1061
  const grpc_resolved_address& address, const ChannelArgs& per_address_args,
740
1062
  const ChannelArgs& args) {
1063
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
1064
+ auto key = grpc_sockaddr_to_string(&address, /*normalize=*/false);
1065
+ gpr_log(GPR_INFO,
1066
+ "[xds_override_host_lb %p] creating subchannel for %s, "
1067
+ "per_address_args=%s, args=%s",
1068
+ this, key.value_or("<unknown>").c_str(),
1069
+ per_address_args.ToString().c_str(), args.ToString().c_str());
1070
+ }
741
1071
  auto subchannel = parent()->channel_control_helper()->CreateSubchannel(
742
1072
  address, per_address_args, args);
743
1073
  return parent()->AdoptSubchannel(address, std::move(subchannel));
@@ -756,24 +1086,19 @@ void XdsOverrideHostLb::Helper::UpdateState(
756
1086
  }
757
1087
 
758
1088
  //
759
- // XdsOverrideHostLb::SubchannelWrapper::SubchannelWrapper
1089
+ // XdsOverrideHostLb::SubchannelWrapper
760
1090
  //
761
1091
 
762
1092
  XdsOverrideHostLb::SubchannelWrapper::SubchannelWrapper(
763
1093
  RefCountedPtr<SubchannelInterface> subchannel,
764
1094
  RefCountedPtr<XdsOverrideHostLb> policy)
765
1095
  : DelegatingSubchannel(std::move(subchannel)), policy_(std::move(policy)) {
766
- auto watcher = std::make_unique<ConnectivityStateWatcher>(WeakRef());
1096
+ auto watcher = std::make_unique<ConnectivityStateWatcher>(
1097
+ WeakRefAsSubclass<SubchannelWrapper>());
767
1098
  watcher_ = watcher.get();
768
1099
  wrapped_subchannel()->WatchConnectivityState(std::move(watcher));
769
1100
  }
770
1101
 
771
- XdsOverrideHostLb::SubchannelWrapper::~SubchannelWrapper() {
772
- if (key_.has_value()) {
773
- policy_->UnsetSubchannel(*key_, this);
774
- }
775
- }
776
-
777
1102
  void XdsOverrideHostLb::SubchannelWrapper::WatchConnectivityState(
778
1103
  std::unique_ptr<ConnectivityStateWatcherInterface> watcher) {
779
1104
  watchers_.insert(std::move(watcher));
@@ -787,9 +1112,45 @@ void XdsOverrideHostLb::SubchannelWrapper::CancelConnectivityStateWatch(
787
1112
  }
788
1113
  }
789
1114
 
1115
+ void XdsOverrideHostLb::SubchannelWrapper::Orphan() {
1116
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
1117
+ gpr_log(GPR_INFO,
1118
+ "[xds_override_host_lb %p] subchannel wrapper %p orphaned",
1119
+ policy_.get(), this);
1120
+ }
1121
+ if (!IsWorkSerializerDispatchEnabled()) {
1122
+ wrapped_subchannel()->CancelConnectivityStateWatch(watcher_);
1123
+ if (subchannel_entry_ != nullptr) {
1124
+ MutexLock lock(&policy()->mu_);
1125
+ subchannel_entry_->OnSubchannelWrapperOrphan(
1126
+ this, policy()->connection_idle_timeout_);
1127
+ }
1128
+ return;
1129
+ }
1130
+ policy()->work_serializer()->Run(
1131
+ [self = WeakRefAsSubclass<SubchannelWrapper>()]() {
1132
+ self->wrapped_subchannel()->CancelConnectivityStateWatch(
1133
+ self->watcher_);
1134
+ if (self->subchannel_entry_ != nullptr) {
1135
+ MutexLock lock(&self->policy()->mu_);
1136
+ self->subchannel_entry_->OnSubchannelWrapperOrphan(
1137
+ self.get(), self->policy()->connection_idle_timeout_);
1138
+ }
1139
+ },
1140
+ DEBUG_LOCATION);
1141
+ }
1142
+
790
1143
  void XdsOverrideHostLb::SubchannelWrapper::UpdateConnectivityState(
791
1144
  grpc_connectivity_state state, absl::Status status) {
792
- connectivity_state_.store(state);
1145
+ bool update_picker = false;
1146
+ if (subchannel_entry_ != nullptr) {
1147
+ MutexLock lock(&policy()->mu_);
1148
+ if (subchannel_entry_->connectivity_state() != state) {
1149
+ subchannel_entry_->set_connectivity_state(state);
1150
+ update_picker = subchannel_entry_->HasOwnedSubchannel() &&
1151
+ subchannel_entry_->GetSubchannel() == this;
1152
+ }
1153
+ }
793
1154
  // Sending connectivity state notifications to the watchers may cause the set
794
1155
  // of watchers to change, so we can't be iterating over the set of watchers
795
1156
  // while we send the notifications
@@ -803,41 +1164,94 @@ void XdsOverrideHostLb::SubchannelWrapper::UpdateConnectivityState(
803
1164
  watcher->OnConnectivityStateChange(state, status);
804
1165
  }
805
1166
  }
806
- if (key_.has_value()) {
807
- policy_->OnSubchannelConnectivityStateChange(*key_);
808
- }
1167
+ if (update_picker) policy()->MaybeUpdatePickerLocked();
809
1168
  }
810
1169
 
811
- void XdsOverrideHostLb::SubchannelWrapper::Orphan() {
812
- if (!IsWorkSerializerDispatchEnabled()) {
813
- key_.reset();
814
- wrapped_subchannel()->CancelConnectivityStateWatch(watcher_);
815
- return;
816
- }
817
- WeakRefCountedPtr<SubchannelWrapper> self = WeakRef();
818
- policy_->work_serializer()->Run(
819
- [self = std::move(self)]() {
820
- self->key_.reset();
821
- self->wrapped_subchannel()->CancelConnectivityStateWatch(
822
- self->watcher_);
1170
+ //
1171
+ // XdsOverrideHostLb::SubchannelEntry
1172
+ //
1173
+
1174
+ RefCountedPtr<XdsOverrideHostLb::SubchannelWrapper>
1175
+ XdsOverrideHostLb::SubchannelEntry::SetUnownedSubchannel(
1176
+ SubchannelWrapper* subchannel)
1177
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsOverrideHostLb::mu_) {
1178
+ auto owned_subchannel = TakeOwnedSubchannel();
1179
+ subchannel_ = subchannel;
1180
+ return owned_subchannel;
1181
+ }
1182
+
1183
+ XdsOverrideHostLb::SubchannelWrapper*
1184
+ XdsOverrideHostLb::SubchannelEntry::GetSubchannel() const
1185
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsOverrideHostLb::mu_) {
1186
+ return Match(
1187
+ subchannel_, [](SubchannelWrapper* subchannel) { return subchannel; },
1188
+ [](const RefCountedPtr<SubchannelWrapper>& subchannel) {
1189
+ return subchannel.get();
1190
+ });
1191
+ }
1192
+
1193
+ RefCountedPtr<XdsOverrideHostLb::SubchannelWrapper>
1194
+ XdsOverrideHostLb::SubchannelEntry::GetSubchannelRef() const
1195
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsOverrideHostLb::mu_) {
1196
+ auto* sc = GetSubchannel();
1197
+ if (sc == nullptr) return nullptr;
1198
+ return sc->RefIfNonZero().TakeAsSubclass<SubchannelWrapper>();
1199
+ }
1200
+
1201
+ RefCountedPtr<XdsOverrideHostLb::SubchannelWrapper>
1202
+ XdsOverrideHostLb::SubchannelEntry::TakeOwnedSubchannel()
1203
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsOverrideHostLb::mu_) {
1204
+ return MatchMutable(
1205
+ &subchannel_,
1206
+ [](SubchannelWrapper**) -> RefCountedPtr<SubchannelWrapper> {
1207
+ return nullptr;
823
1208
  },
824
- DEBUG_LOCATION);
1209
+ [](RefCountedPtr<SubchannelWrapper>* subchannel) {
1210
+ return std::move(*subchannel);
1211
+ });
825
1212
  }
826
1213
 
827
- grpc_pollset_set* XdsOverrideHostLb::SubchannelWrapper::
828
- ConnectivityStateWatcher::interested_parties() {
829
- return subchannel_->policy_->interested_parties();
1214
+ void XdsOverrideHostLb::SubchannelEntry::UnsetSubchannel(
1215
+ std::vector<RefCountedPtr<SubchannelWrapper>>* owned_subchannels)
1216
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsOverrideHostLb::mu_) {
1217
+ auto subchannel = TakeOwnedSubchannel();
1218
+ if (subchannel != nullptr) {
1219
+ owned_subchannels->push_back(std::move(subchannel));
1220
+ }
1221
+ subchannel_ = nullptr;
830
1222
  }
831
1223
 
832
- void XdsOverrideHostLb::SubchannelWrapper::ConnectivityStateWatcher::
833
- OnConnectivityStateChange(grpc_connectivity_state state,
834
- absl::Status status) {
835
- subchannel_->UpdateConnectivityState(state, status);
1224
+ void XdsOverrideHostLb::SubchannelEntry::OnSubchannelWrapperOrphan(
1225
+ SubchannelWrapper* wrapper, Duration connection_idle_timeout)
1226
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(&XdsOverrideHostLb::mu_) {
1227
+ auto* subchannel = GetSubchannel();
1228
+ if (subchannel != wrapper) return;
1229
+ if (last_used_time_ < (Timestamp::Now() - connection_idle_timeout)) {
1230
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
1231
+ gpr_log(GPR_INFO,
1232
+ "[xds_override_host_lb] removing unowned subchannel wrapper %p",
1233
+ subchannel);
1234
+ }
1235
+ subchannel_ = nullptr;
1236
+ } else {
1237
+ // The subchannel is being released by the child policy, but it
1238
+ // is still within its idle timeout, so we make a new copy of
1239
+ // the wrapper with the same underlying subchannel, and we hold
1240
+ // our own ref to it.
1241
+ if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) {
1242
+ gpr_log(GPR_INFO,
1243
+ "[xds_override_host_lb] subchannel wrapper %p: cloning "
1244
+ "to gain ownership",
1245
+ subchannel);
1246
+ }
1247
+ subchannel_ = wrapper->Clone();
1248
+ }
836
1249
  }
837
1250
 
838
1251
  //
839
1252
  // factory
840
1253
  //
1254
+
841
1255
  class XdsOverrideHostLbFactory : public LoadBalancingPolicyFactory {
842
1256
  public:
843
1257
  OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
@@ -864,57 +1278,34 @@ void RegisterXdsOverrideHostLbPolicy(CoreConfiguration::Builder* builder) {
864
1278
  std::make_unique<XdsOverrideHostLbFactory>());
865
1279
  }
866
1280
 
1281
+ //
867
1282
  // XdsOverrideHostLbConfig
1283
+ //
868
1284
 
869
1285
  const JsonLoaderInterface* XdsOverrideHostLbConfig::JsonLoader(
870
1286
  const JsonArgs&) {
871
1287
  static const auto kJsonLoader =
872
1288
  JsonObjectLoader<XdsOverrideHostLbConfig>()
873
1289
  // Child policy config is parsed in JsonPostLoad
1290
+ .Field("clusterName", &XdsOverrideHostLbConfig::cluster_name_)
874
1291
  .Finish();
875
1292
  return kJsonLoader;
876
1293
  }
877
1294
 
878
- void XdsOverrideHostLbConfig::JsonPostLoad(const Json& json,
879
- const JsonArgs& args,
1295
+ void XdsOverrideHostLbConfig::JsonPostLoad(const Json& json, const JsonArgs&,
880
1296
  ValidationErrors* errors) {
881
- {
882
- ValidationErrors::ScopedField field(errors, ".childPolicy");
883
- auto it = json.object().find("childPolicy");
884
- if (it == json.object().end()) {
885
- errors->AddError("field not present");
886
- } else {
887
- auto child_policy_config = CoreConfiguration::Get()
888
- .lb_policy_registry()
889
- .ParseLoadBalancingConfig(it->second);
890
- if (!child_policy_config.ok()) {
891
- errors->AddError(child_policy_config.status().message());
892
- } else {
893
- child_config_ = std::move(*child_policy_config);
894
- }
895
- }
896
- }
897
- {
898
- ValidationErrors::ScopedField field(errors, ".overrideHostStatus");
899
- auto host_status_list = LoadJsonObjectField<std::vector<std::string>>(
900
- json.object(), args, "overrideHostStatus", errors,
901
- /*required=*/false);
902
- if (host_status_list.has_value()) {
903
- for (size_t i = 0; i < host_status_list->size(); ++i) {
904
- const std::string& host_status = (*host_status_list)[i];
905
- auto status = XdsHealthStatus::FromString(host_status);
906
- if (!status.has_value()) {
907
- ValidationErrors::ScopedField field(errors,
908
- absl::StrCat("[", i, "]"));
909
- errors->AddError("invalid host status");
910
- } else {
911
- override_host_status_set_.Add(*status);
912
- }
913
- }
1297
+ ValidationErrors::ScopedField field(errors, ".childPolicy");
1298
+ auto it = json.object().find("childPolicy");
1299
+ if (it == json.object().end()) {
1300
+ errors->AddError("field not present");
1301
+ } else {
1302
+ auto child_policy_config =
1303
+ CoreConfiguration::Get().lb_policy_registry().ParseLoadBalancingConfig(
1304
+ it->second);
1305
+ if (!child_policy_config.ok()) {
1306
+ errors->AddError(child_policy_config.status().message());
914
1307
  } else {
915
- override_host_status_set_ = XdsHealthStatusSet(
916
- {XdsHealthStatus(XdsHealthStatus::HealthStatus::kHealthy),
917
- XdsHealthStatus(XdsHealthStatus::HealthStatus::kUnknown)});
1308
+ child_config_ = std::move(*child_policy_config);
918
1309
  }
919
1310
  }
920
1311
  }