grpc 1.60.0 → 1.61.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (277) 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 +67 -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/http2_settings.cc +122 -32
  93. data/src/core/ext/transport/chttp2/transport/http2_settings.h +142 -37
  94. data/src/core/ext/transport/chttp2/transport/internal.h +1 -22
  95. data/src/core/ext/transport/chttp2/transport/parsing.cc +23 -37
  96. data/src/core/ext/transport/chttp2/transport/writing.cc +26 -58
  97. data/src/core/ext/transport/inproc/inproc_transport.cc +172 -13
  98. data/src/core/ext/upb-gen/envoy/extensions/upstreams/http/v3/http_protocol_options.upb.h +712 -0
  99. data/src/core/ext/upb-gen/envoy/extensions/upstreams/http/v3/http_protocol_options.upb_minitable.c +151 -0
  100. data/src/core/ext/upb-gen/envoy/extensions/upstreams/http/v3/http_protocol_options.upb_minitable.h +33 -0
  101. data/src/core/ext/upbdefs-gen/envoy/extensions/upstreams/http/v3/http_protocol_options.upbdefs.c +133 -0
  102. data/src/core/ext/upbdefs-gen/envoy/extensions/upstreams/http/v3/http_protocol_options.upbdefs.h +50 -0
  103. data/src/core/ext/xds/certificate_provider_store.cc +2 -1
  104. data/src/core/ext/xds/certificate_provider_store.h +0 -5
  105. data/src/core/ext/xds/xds_api.cc +31 -18
  106. data/src/core/ext/xds/xds_api.h +2 -2
  107. data/src/core/ext/xds/xds_bootstrap.h +3 -0
  108. data/src/core/ext/xds/xds_certificate_provider.cc +88 -287
  109. data/src/core/ext/xds/xds_certificate_provider.h +44 -111
  110. data/src/core/ext/xds/xds_client.cc +420 -414
  111. data/src/core/ext/xds/xds_client.h +31 -22
  112. data/src/core/ext/xds/xds_client_grpc.cc +3 -1
  113. data/src/core/ext/xds/xds_cluster.cc +104 -11
  114. data/src/core/ext/xds/xds_cluster.h +9 -1
  115. data/src/core/ext/xds/xds_cluster_specifier_plugin.cc +9 -5
  116. data/src/core/ext/xds/xds_common_types.cc +14 -10
  117. data/src/core/ext/xds/xds_endpoint.cc +9 -4
  118. data/src/core/ext/xds/xds_endpoint.h +5 -1
  119. data/src/core/ext/xds/xds_health_status.cc +12 -2
  120. data/src/core/ext/xds/xds_health_status.h +4 -2
  121. data/src/core/ext/xds/xds_http_rbac_filter.cc +5 -3
  122. data/src/core/ext/xds/xds_listener.cc +14 -8
  123. data/src/core/ext/xds/xds_resource_type_impl.h +6 -4
  124. data/src/core/ext/xds/xds_route_config.cc +34 -22
  125. data/src/core/ext/xds/xds_route_config.h +1 -0
  126. data/src/core/ext/xds/xds_server_config_fetcher.cc +61 -57
  127. data/src/core/ext/xds/xds_transport.h +3 -0
  128. data/src/core/ext/xds/xds_transport_grpc.cc +47 -50
  129. data/src/core/ext/xds/xds_transport_grpc.h +4 -0
  130. data/src/core/lib/channel/call_tracer.cc +12 -0
  131. data/src/core/lib/channel/call_tracer.h +17 -3
  132. data/src/core/lib/channel/channel_args.cc +24 -14
  133. data/src/core/lib/channel/channel_args.h +74 -13
  134. data/src/core/lib/channel/channel_stack.cc +27 -0
  135. data/src/core/lib/channel/channel_stack.h +10 -10
  136. data/src/core/lib/channel/connected_channel.cc +64 -18
  137. data/src/core/lib/channel/promise_based_filter.h +1041 -1
  138. data/src/core/lib/channel/server_call_tracer_filter.cc +43 -35
  139. data/src/core/lib/compression/compression_internal.cc +0 -3
  140. data/src/core/lib/event_engine/ares_resolver.cc +35 -14
  141. data/src/core/lib/event_engine/ares_resolver.h +9 -10
  142. data/src/core/lib/event_engine/cf_engine/dns_service_resolver.cc +8 -1
  143. data/src/core/lib/event_engine/posix_engine/native_posix_dns_resolver.cc +132 -0
  144. data/src/core/lib/event_engine/posix_engine/native_posix_dns_resolver.h +61 -0
  145. data/src/core/lib/event_engine/posix_engine/posix_engine.cc +52 -36
  146. data/src/core/lib/event_engine/posix_engine/posix_engine.h +4 -9
  147. data/src/core/lib/event_engine/posix_engine/posix_engine_listener_utils.cc +11 -3
  148. data/src/core/lib/event_engine/posix_engine/tcp_socket_utils.cc +9 -2
  149. data/src/core/lib/event_engine/posix_engine/tcp_socket_utils.h +7 -0
  150. data/src/core/lib/event_engine/posix_engine/timer_manager.cc +17 -27
  151. data/src/core/lib/event_engine/posix_engine/timer_manager.h +0 -3
  152. data/src/core/lib/event_engine/ref_counted_dns_resolver_interface.h +55 -0
  153. data/src/core/lib/event_engine/windows/native_windows_dns_resolver.cc +114 -0
  154. data/src/core/lib/event_engine/windows/native_windows_dns_resolver.h +51 -0
  155. data/src/core/lib/event_engine/windows/windows_engine.cc +7 -7
  156. data/src/core/lib/experiments/config.cc +13 -0
  157. data/src/core/lib/experiments/config.h +3 -0
  158. data/src/core/lib/experiments/experiments.cc +245 -366
  159. data/src/core/lib/experiments/experiments.h +50 -156
  160. data/src/core/lib/gprpp/debug_location.h +13 -0
  161. data/src/core/lib/gprpp/dual_ref_counted.h +36 -7
  162. data/src/core/lib/gprpp/orphanable.h +27 -0
  163. data/src/core/lib/gprpp/ref_counted.h +63 -22
  164. data/src/core/lib/gprpp/ref_counted_ptr.h +70 -27
  165. data/src/core/lib/gprpp/ref_counted_string.h +13 -0
  166. data/src/core/lib/gprpp/status_helper.cc +1 -2
  167. data/src/core/lib/iomgr/combiner.cc +15 -51
  168. data/src/core/lib/iomgr/event_engine_shims/endpoint.cc +31 -0
  169. data/src/core/lib/iomgr/event_engine_shims/endpoint.h +16 -0
  170. data/src/core/lib/iomgr/tcp_client_posix.cc +4 -3
  171. data/src/core/lib/load_balancing/lb_policy.h +1 -1
  172. data/src/core/lib/promise/activity.cc +17 -2
  173. data/src/core/lib/promise/activity.h +5 -4
  174. data/src/core/lib/promise/all_ok.h +80 -0
  175. data/src/core/lib/promise/detail/join_state.h +2077 -0
  176. data/src/core/lib/promise/detail/promise_factory.h +1 -0
  177. data/src/core/lib/promise/detail/promise_like.h +8 -1
  178. data/src/core/lib/promise/detail/seq_state.h +3458 -150
  179. data/src/core/lib/promise/detail/status.h +42 -5
  180. data/src/core/lib/promise/for_each.h +13 -1
  181. data/src/core/lib/promise/if.h +4 -0
  182. data/src/core/lib/promise/latch.h +6 -3
  183. data/src/core/lib/promise/party.cc +33 -31
  184. data/src/core/lib/promise/party.h +142 -6
  185. data/src/core/lib/promise/poll.h +39 -13
  186. data/src/core/lib/promise/promise.h +4 -0
  187. data/src/core/lib/promise/seq.h +107 -7
  188. data/src/core/lib/promise/status_flag.h +196 -0
  189. data/src/core/lib/promise/try_join.h +132 -0
  190. data/src/core/lib/promise/try_seq.h +132 -10
  191. data/src/core/lib/resolver/endpoint_addresses.cc +0 -1
  192. data/src/core/lib/resolver/endpoint_addresses.h +48 -0
  193. data/src/core/lib/resource_quota/arena.h +2 -2
  194. data/src/core/lib/resource_quota/memory_quota.cc +57 -8
  195. data/src/core/lib/resource_quota/memory_quota.h +6 -0
  196. data/src/core/lib/security/authorization/grpc_server_authz_filter.cc +14 -11
  197. data/src/core/lib/security/authorization/grpc_server_authz_filter.h +14 -5
  198. data/src/core/lib/security/credentials/external/aws_external_account_credentials.cc +4 -0
  199. data/src/core/lib/security/credentials/external/aws_external_account_credentials.h +4 -0
  200. data/src/core/lib/security/credentials/external/external_account_credentials.cc +28 -20
  201. data/src/core/lib/security/credentials/external/external_account_credentials.h +4 -0
  202. data/src/core/lib/security/credentials/external/file_external_account_credentials.cc +4 -0
  203. data/src/core/lib/security/credentials/external/file_external_account_credentials.h +4 -0
  204. data/src/core/lib/security/credentials/external/url_external_account_credentials.cc +4 -0
  205. data/src/core/lib/security/credentials/external/url_external_account_credentials.h +4 -0
  206. data/src/core/lib/security/credentials/plugin/plugin_credentials.cc +2 -1
  207. data/src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h +0 -3
  208. data/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc +12 -0
  209. data/src/core/lib/security/credentials/tls/grpc_tls_crl_provider.cc +22 -5
  210. data/src/core/lib/security/credentials/tls/grpc_tls_crl_provider.h +1 -5
  211. data/src/core/lib/security/credentials/tls/tls_credentials.cc +16 -0
  212. data/src/core/lib/security/credentials/xds/xds_credentials.cc +21 -28
  213. data/src/core/lib/security/credentials/xds/xds_credentials.h +2 -4
  214. data/src/core/lib/security/security_connector/tls/tls_security_connector.cc +4 -3
  215. data/src/core/lib/security/transport/auth_filters.h +71 -4
  216. data/src/core/lib/security/transport/client_auth_filter.cc +2 -4
  217. data/src/core/lib/security/transport/legacy_server_auth_filter.cc +244 -0
  218. data/src/core/lib/security/transport/server_auth_filter.cc +70 -90
  219. data/src/core/lib/slice/slice_buffer.h +3 -0
  220. data/src/core/lib/surface/builtins.cc +1 -1
  221. data/src/core/lib/surface/call.cc +683 -196
  222. data/src/core/lib/surface/call.h +26 -13
  223. data/src/core/lib/surface/call_trace.cc +42 -1
  224. data/src/core/lib/surface/channel.cc +0 -1
  225. data/src/core/lib/surface/channel.h +0 -6
  226. data/src/core/lib/surface/channel_init.h +26 -0
  227. data/src/core/lib/surface/init.cc +14 -8
  228. data/src/core/lib/surface/server.cc +256 -237
  229. data/src/core/lib/surface/server.h +26 -54
  230. data/src/core/lib/surface/version.cc +2 -2
  231. data/src/core/lib/surface/wait_for_cq_end_op.h +94 -0
  232. data/src/core/lib/transport/call_final_info.cc +38 -0
  233. data/src/core/lib/transport/call_final_info.h +54 -0
  234. data/src/core/lib/transport/connectivity_state.cc +3 -2
  235. data/src/core/lib/transport/connectivity_state.h +4 -0
  236. data/src/core/lib/transport/metadata_batch.h +4 -4
  237. data/src/core/lib/transport/transport.cc +70 -19
  238. data/src/core/lib/transport/transport.h +395 -25
  239. data/src/core/plugin_registry/grpc_plugin_registry.cc +3 -0
  240. data/src/core/plugin_registry/grpc_plugin_registry_extra.cc +0 -3
  241. data/src/core/tsi/alts/handshaker/alts_handshaker_client.cc +1 -1
  242. data/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc +1 -1
  243. data/src/core/tsi/alts/handshaker/transport_security_common_api.cc +1 -1
  244. data/src/core/tsi/ssl_transport_security.cc +65 -43
  245. data/src/ruby/ext/grpc/rb_channel_args.c +3 -1
  246. data/src/ruby/ext/grpc/rb_grpc.c +0 -1
  247. data/src/ruby/ext/grpc/rb_grpc.h +0 -2
  248. data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +4 -0
  249. data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +6 -0
  250. data/src/ruby/lib/grpc/version.rb +1 -1
  251. data/third_party/upb/upb/reflection/def_pool.h +2 -2
  252. data/third_party/zlib/adler32.c +5 -27
  253. data/third_party/zlib/compress.c +5 -16
  254. data/third_party/zlib/crc32.c +86 -162
  255. data/third_party/zlib/deflate.c +233 -336
  256. data/third_party/zlib/deflate.h +8 -8
  257. data/third_party/zlib/gzguts.h +11 -12
  258. data/third_party/zlib/infback.c +7 -23
  259. data/third_party/zlib/inffast.c +1 -4
  260. data/third_party/zlib/inffast.h +1 -1
  261. data/third_party/zlib/inflate.c +30 -99
  262. data/third_party/zlib/inftrees.c +6 -11
  263. data/third_party/zlib/inftrees.h +3 -3
  264. data/third_party/zlib/trees.c +224 -302
  265. data/third_party/zlib/uncompr.c +4 -12
  266. data/third_party/zlib/zconf.h +6 -2
  267. data/third_party/zlib/zlib.h +191 -188
  268. data/third_party/zlib/zutil.c +16 -44
  269. data/third_party/zlib/zutil.h +10 -10
  270. metadata +35 -13
  271. data/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc +0 -1173
  272. data/src/core/lib/event_engine/memory_allocator.cc +0 -74
  273. data/src/core/lib/transport/pid_controller.cc +0 -51
  274. data/src/core/lib/transport/pid_controller.h +0 -116
  275. data/third_party/upb/upb/collections/array.h +0 -17
  276. data/third_party/upb/upb/collections/map.h +0 -17
  277. 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
  }