grpc 1.11.1 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of grpc might be problematic. Click here for more details.

Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +225 -87
  3. data/etc/roots.pem +0 -33
  4. data/include/grpc/grpc_security.h +70 -0
  5. data/include/grpc/impl/codegen/port_platform.h +11 -0
  6. data/include/grpc/support/log.h +9 -1
  7. data/src/core/ext/filters/client_channel/client_channel.cc +305 -210
  8. data/src/core/ext/filters/client_channel/http_connect_handshaker.cc +1 -1
  9. data/src/core/ext/filters/client_channel/lb_policy.cc +2 -2
  10. data/src/core/ext/filters/client_channel/lb_policy.h +4 -0
  11. data/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc +12 -9
  12. data/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc +168 -197
  13. data/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc +368 -373
  14. data/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h +498 -98
  15. data/src/core/ext/filters/client_channel/method_params.h +4 -0
  16. data/src/core/ext/filters/client_channel/resolver.h +4 -0
  17. data/src/core/ext/filters/client_channel/retry_throttle.h +4 -0
  18. data/src/core/ext/filters/http/message_compress/message_compress_filter.cc +2 -2
  19. data/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +40 -15
  20. data/src/core/ext/transport/chttp2/transport/frame_settings.cc +3 -3
  21. data/src/core/ext/transport/chttp2/transport/hpack_encoder.cc +2 -2
  22. data/src/core/ext/transport/chttp2/transport/hpack_parser.cc +1 -1
  23. data/src/core/ext/transport/chttp2/transport/hpack_table.cc +2 -2
  24. data/src/core/ext/transport/chttp2/transport/stream_lists.cc +3 -3
  25. data/src/core/ext/transport/chttp2/transport/writing.cc +5 -5
  26. data/src/core/ext/transport/inproc/inproc_transport.cc +41 -43
  27. data/src/core/lib/channel/channel_args.cc +28 -0
  28. data/src/core/lib/channel/channel_args.h +4 -0
  29. data/src/core/lib/channel/handshaker.cc +47 -0
  30. data/src/core/lib/channel/handshaker.h +4 -0
  31. data/src/core/lib/debug/trace.cc +2 -1
  32. data/src/core/lib/debug/trace.h +10 -1
  33. data/src/core/lib/gpr/log.cc +8 -2
  34. data/src/core/lib/gpr/log_android.cc +4 -0
  35. data/src/core/lib/gpr/log_linux.cc +4 -0
  36. data/src/core/lib/gpr/log_posix.cc +4 -0
  37. data/src/core/lib/gpr/log_windows.cc +5 -0
  38. data/src/core/lib/gprpp/inlined_vector.h +30 -34
  39. data/src/core/lib/gprpp/orphanable.h +4 -4
  40. data/src/core/lib/gprpp/ref_counted.h +4 -4
  41. data/src/core/lib/iomgr/call_combiner.cc +13 -13
  42. data/src/core/lib/iomgr/closure.h +3 -3
  43. data/src/core/lib/iomgr/combiner.cc +11 -11
  44. data/src/core/lib/iomgr/ev_epoll1_linux.cc +24 -24
  45. data/src/core/lib/iomgr/ev_epollex_linux.cc +48 -29
  46. data/src/core/lib/iomgr/ev_epollsig_linux.cc +2 -2
  47. data/src/core/lib/iomgr/ev_poll_posix.cc +9 -3
  48. data/src/core/lib/iomgr/ev_posix.cc +3 -3
  49. data/src/core/lib/iomgr/executor.cc +6 -6
  50. data/src/core/lib/iomgr/resource_quota.cc +10 -11
  51. data/src/core/lib/iomgr/socket_utils_common_posix.cc +24 -0
  52. data/src/core/lib/iomgr/socket_utils_linux.cc +0 -1
  53. data/src/core/lib/iomgr/socket_utils_posix.cc +2 -3
  54. data/src/core/lib/iomgr/socket_utils_posix.h +3 -0
  55. data/src/core/lib/iomgr/tcp_client_custom.cc +2 -2
  56. data/src/core/lib/iomgr/tcp_client_posix.cc +4 -4
  57. data/src/core/lib/iomgr/tcp_custom.cc +10 -10
  58. data/src/core/lib/iomgr/tcp_posix.cc +25 -25
  59. data/src/core/lib/iomgr/tcp_server_custom.cc +5 -5
  60. data/src/core/lib/iomgr/tcp_server_posix.cc +4 -25
  61. data/src/core/lib/iomgr/tcp_server_windows.cc +1 -0
  62. data/src/core/lib/iomgr/tcp_uv.cc +3 -0
  63. data/src/core/lib/iomgr/tcp_windows.cc +16 -0
  64. data/src/core/lib/iomgr/timer_generic.cc +27 -17
  65. data/src/core/lib/iomgr/timer_manager.cc +11 -12
  66. data/src/core/lib/iomgr/timer_uv.cc +3 -0
  67. data/src/core/lib/iomgr/udp_server.cc +104 -49
  68. data/src/core/lib/iomgr/udp_server.h +8 -4
  69. data/src/core/lib/profiling/basic_timers.cc +1 -0
  70. data/src/core/lib/security/credentials/alts/alts_credentials.h +0 -20
  71. data/src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc +7 -7
  72. data/src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h +1 -38
  73. data/src/core/lib/security/security_connector/security_connector.cc +19 -16
  74. data/src/core/lib/security/security_connector/security_connector.h +4 -3
  75. data/src/core/lib/security/transport/secure_endpoint.cc +2 -2
  76. data/src/core/lib/security/transport/security_handshaker.cc +6 -2
  77. data/src/core/lib/slice/slice.cc +6 -2
  78. data/src/core/lib/slice/slice_buffer.cc +12 -4
  79. data/src/core/lib/slice/slice_hash_table.h +4 -0
  80. data/src/core/lib/slice/slice_weak_hash_table.h +4 -0
  81. data/src/core/lib/surface/call.cc +6 -6
  82. data/src/core/lib/surface/server.cc +16 -0
  83. data/src/core/lib/surface/version.cc +1 -1
  84. data/src/core/lib/transport/bdp_estimator.cc +3 -3
  85. data/src/core/lib/transport/bdp_estimator.h +2 -2
  86. data/src/core/lib/transport/connectivity_state.cc +6 -7
  87. data/src/core/tsi/ssl/session_cache/ssl_session_cache.h +4 -0
  88. data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +14 -0
  89. data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +21 -0
  90. data/src/ruby/lib/grpc/version.rb +1 -1
  91. data/src/ruby/pb/generate_proto_ruby.sh +7 -1
  92. data/src/ruby/spec/pb/package_with_underscore/checker_spec.rb +2 -5
  93. data/third_party/address_sorting/address_sorting.c +10 -9
  94. metadata +27 -28
  95. data/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc +0 -253
@@ -326,7 +326,7 @@ static void http_connect_handshaker_do_handshake(
326
326
 
327
327
  static const grpc_handshaker_vtable http_connect_handshaker_vtable = {
328
328
  http_connect_handshaker_destroy, http_connect_handshaker_shutdown,
329
- http_connect_handshaker_do_handshake};
329
+ http_connect_handshaker_do_handshake, "http_connect"};
330
330
 
331
331
  static grpc_handshaker* grpc_http_connect_handshaker_create() {
332
332
  http_connect_handshaker* handshaker =
@@ -44,13 +44,13 @@ void LoadBalancingPolicy::TryReresolutionLocked(
44
44
  GRPC_CLOSURE_SCHED(request_reresolution_, error);
45
45
  request_reresolution_ = nullptr;
46
46
  if (grpc_lb_trace->enabled()) {
47
- gpr_log(GPR_DEBUG,
47
+ gpr_log(GPR_INFO,
48
48
  "%s %p: scheduling re-resolution closure with error=%s.",
49
49
  grpc_lb_trace->name(), this, grpc_error_string(error));
50
50
  }
51
51
  } else {
52
52
  if (grpc_lb_trace->enabled()) {
53
- gpr_log(GPR_DEBUG, "%s %p: no available re-resolution closure.",
53
+ gpr_log(GPR_INFO, "%s %p: no available re-resolution closure.",
54
54
  grpc_lb_trace->name(), this);
55
55
  }
56
56
  }
@@ -162,6 +162,10 @@ class LoadBalancingPolicy
162
162
  GRPC_ABSTRACT_BASE_CLASS
163
163
 
164
164
  protected:
165
+ // So Delete() can access our protected dtor.
166
+ template <typename T>
167
+ friend void Delete(T*);
168
+
165
169
  explicit LoadBalancingPolicy(const Args& args);
166
170
  virtual ~LoadBalancingPolicy();
167
171
 
@@ -189,6 +189,10 @@ class GrpcLb : public LoadBalancingPolicy {
189
189
  bool seen_initial_response() const { return seen_initial_response_; }
190
190
 
191
191
  private:
192
+ // So Delete() can access our private dtor.
193
+ template <typename T>
194
+ friend void grpc_core::Delete(T*);
195
+
192
196
  ~BalancerCallState();
193
197
 
194
198
  GrpcLb* grpclb_policy() const {
@@ -1243,7 +1247,7 @@ bool GrpcLb::PickLocked(PickState* pick) {
1243
1247
  }
1244
1248
  } else { // rr_policy_ == NULL
1245
1249
  if (grpc_lb_glb_trace.enabled()) {
1246
- gpr_log(GPR_DEBUG,
1250
+ gpr_log(GPR_INFO,
1247
1251
  "[grpclb %p] No RR policy. Adding to grpclb's pending picks",
1248
1252
  this);
1249
1253
  }
@@ -1409,14 +1413,13 @@ void GrpcLb::OnFallbackTimerLocked(void* arg, grpc_error* error) {
1409
1413
  void GrpcLb::StartBalancerCallRetryTimerLocked() {
1410
1414
  grpc_millis next_try = lb_call_backoff_.NextAttemptTime();
1411
1415
  if (grpc_lb_glb_trace.enabled()) {
1412
- gpr_log(GPR_DEBUG, "[grpclb %p] Connection to LB server lost...", this);
1416
+ gpr_log(GPR_INFO, "[grpclb %p] Connection to LB server lost...", this);
1413
1417
  grpc_millis timeout = next_try - ExecCtx::Get()->Now();
1414
1418
  if (timeout > 0) {
1415
- gpr_log(GPR_DEBUG,
1416
- "[grpclb %p] ... retry_timer_active in %" PRIuPTR "ms.", this,
1417
- timeout);
1419
+ gpr_log(GPR_INFO, "[grpclb %p] ... retry_timer_active in %" PRIuPTR "ms.",
1420
+ this, timeout);
1418
1421
  } else {
1419
- gpr_log(GPR_DEBUG, "[grpclb %p] ... retry_timer_active immediately.",
1422
+ gpr_log(GPR_INFO, "[grpclb %p] ... retry_timer_active immediately.",
1420
1423
  this);
1421
1424
  }
1422
1425
  }
@@ -1724,7 +1727,7 @@ void GrpcLb::CreateOrUpdateRoundRobinPolicyLocked() {
1724
1727
  GPR_ASSERT(args != nullptr);
1725
1728
  if (rr_policy_ != nullptr) {
1726
1729
  if (grpc_lb_glb_trace.enabled()) {
1727
- gpr_log(GPR_DEBUG, "[grpclb %p] Updating RR policy %p", this,
1730
+ gpr_log(GPR_INFO, "[grpclb %p] Updating RR policy %p", this,
1728
1731
  rr_policy_.get());
1729
1732
  }
1730
1733
  rr_policy_->UpdateLocked(*args);
@@ -1735,7 +1738,7 @@ void GrpcLb::CreateOrUpdateRoundRobinPolicyLocked() {
1735
1738
  lb_policy_args.args = args;
1736
1739
  CreateRoundRobinPolicyLocked(lb_policy_args);
1737
1740
  if (grpc_lb_glb_trace.enabled()) {
1738
- gpr_log(GPR_DEBUG, "[grpclb %p] Created new RR policy %p", this,
1741
+ gpr_log(GPR_INFO, "[grpclb %p] Created new RR policy %p", this,
1739
1742
  rr_policy_.get());
1740
1743
  }
1741
1744
  }
@@ -1751,7 +1754,7 @@ void GrpcLb::OnRoundRobinRequestReresolutionLocked(void* arg,
1751
1754
  }
1752
1755
  if (grpc_lb_glb_trace.enabled()) {
1753
1756
  gpr_log(
1754
- GPR_DEBUG,
1757
+ GPR_INFO,
1755
1758
  "[grpclb %p] Re-resolution requested from the internal RR policy (%p).",
1756
1759
  grpclb_policy, grpclb_policy->rr_policy_.get());
1757
1760
  }
@@ -62,31 +62,65 @@ class PickFirst : public LoadBalancingPolicy {
62
62
  private:
63
63
  ~PickFirst();
64
64
 
65
+ class PickFirstSubchannelList;
66
+
67
+ class PickFirstSubchannelData
68
+ : public SubchannelData<PickFirstSubchannelList,
69
+ PickFirstSubchannelData> {
70
+ public:
71
+ PickFirstSubchannelData(PickFirstSubchannelList* subchannel_list,
72
+ const grpc_lb_user_data_vtable* user_data_vtable,
73
+ const grpc_lb_address& address,
74
+ grpc_subchannel* subchannel,
75
+ grpc_combiner* combiner)
76
+ : SubchannelData(subchannel_list, user_data_vtable, address, subchannel,
77
+ combiner) {}
78
+
79
+ void ProcessConnectivityChangeLocked(
80
+ grpc_connectivity_state connectivity_state, grpc_error* error) override;
81
+ };
82
+
83
+ class PickFirstSubchannelList
84
+ : public SubchannelList<PickFirstSubchannelList,
85
+ PickFirstSubchannelData> {
86
+ public:
87
+ PickFirstSubchannelList(PickFirst* policy, TraceFlag* tracer,
88
+ const grpc_lb_addresses* addresses,
89
+ grpc_combiner* combiner,
90
+ grpc_client_channel_factory* client_channel_factory,
91
+ const grpc_channel_args& args)
92
+ : SubchannelList(policy, tracer, addresses, combiner,
93
+ client_channel_factory, args) {
94
+ // Need to maintain a ref to the LB policy as long as we maintain
95
+ // any references to subchannels, since the subchannels'
96
+ // pollset_sets will include the LB policy's pollset_set.
97
+ policy->Ref(DEBUG_LOCATION, "subchannel_list").release();
98
+ }
99
+
100
+ ~PickFirstSubchannelList() {
101
+ PickFirst* p = static_cast<PickFirst*>(policy());
102
+ p->Unref(DEBUG_LOCATION, "subchannel_list");
103
+ }
104
+ };
105
+
65
106
  void ShutdownLocked() override;
66
107
 
67
108
  void StartPickingLocked();
68
109
  void DestroyUnselectedSubchannelsLocked();
69
110
 
70
- static void OnConnectivityChangedLocked(void* arg, grpc_error* error);
71
-
72
- void SubchannelListRefForConnectivityWatch(
73
- grpc_lb_subchannel_list* subchannel_list, const char* reason);
74
- void SubchannelListUnrefForConnectivityWatch(
75
- grpc_lb_subchannel_list* subchannel_list, const char* reason);
76
-
77
- /** all our subchannels */
78
- grpc_lb_subchannel_list* subchannel_list_ = nullptr;
79
- /** latest pending subchannel list */
80
- grpc_lb_subchannel_list* latest_pending_subchannel_list_ = nullptr;
81
- /** selected subchannel in \a subchannel_list */
82
- grpc_lb_subchannel_data* selected_ = nullptr;
83
- /** have we started picking? */
111
+ // All our subchannels.
112
+ OrphanablePtr<PickFirstSubchannelList> subchannel_list_;
113
+ // Latest pending subchannel list.
114
+ OrphanablePtr<PickFirstSubchannelList> latest_pending_subchannel_list_;
115
+ // Selected subchannel in \a subchannel_list_.
116
+ PickFirstSubchannelData* selected_ = nullptr;
117
+ // Have we started picking?
84
118
  bool started_picking_ = false;
85
- /** are we shut down? */
119
+ // Are we shut down?
86
120
  bool shutdown_ = false;
87
- /** list of picks that are waiting on connectivity */
121
+ // List of picks that are waiting on connectivity.
88
122
  PickState* pending_picks_ = nullptr;
89
- /** our connectivity state tracker */
123
+ // Our connectivity state tracker.
90
124
  grpc_connectivity_state_tracker state_tracker_;
91
125
  };
92
126
 
@@ -95,7 +129,7 @@ PickFirst::PickFirst(const Args& args) : LoadBalancingPolicy(args) {
95
129
  grpc_connectivity_state_init(&state_tracker_, GRPC_CHANNEL_IDLE,
96
130
  "pick_first");
97
131
  if (grpc_lb_pick_first_trace.enabled()) {
98
- gpr_log(GPR_DEBUG, "Pick First %p created.", this);
132
+ gpr_log(GPR_INFO, "Pick First %p created.", this);
99
133
  }
100
134
  UpdateLocked(*args.args);
101
135
  grpc_subchannel_index_ref();
@@ -103,7 +137,7 @@ PickFirst::PickFirst(const Args& args) : LoadBalancingPolicy(args) {
103
137
 
104
138
  PickFirst::~PickFirst() {
105
139
  if (grpc_lb_pick_first_trace.enabled()) {
106
- gpr_log(GPR_DEBUG, "Destroying Pick First %p", this);
140
+ gpr_log(GPR_INFO, "Destroying Pick First %p", this);
107
141
  }
108
142
  GPR_ASSERT(subchannel_list_ == nullptr);
109
143
  GPR_ASSERT(latest_pending_subchannel_list_ == nullptr);
@@ -126,7 +160,7 @@ void PickFirst::HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) {
126
160
  void PickFirst::ShutdownLocked() {
127
161
  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel shutdown");
128
162
  if (grpc_lb_pick_first_trace.enabled()) {
129
- gpr_log(GPR_DEBUG, "Pick First %p Shutting down", this);
163
+ gpr_log(GPR_INFO, "Pick First %p Shutting down", this);
130
164
  }
131
165
  shutdown_ = true;
132
166
  PickState* pick;
@@ -137,15 +171,8 @@ void PickFirst::ShutdownLocked() {
137
171
  }
138
172
  grpc_connectivity_state_set(&state_tracker_, GRPC_CHANNEL_SHUTDOWN,
139
173
  GRPC_ERROR_REF(error), "shutdown");
140
- if (subchannel_list_ != nullptr) {
141
- grpc_lb_subchannel_list_shutdown_and_unref(subchannel_list_, "pf_shutdown");
142
- subchannel_list_ = nullptr;
143
- }
144
- if (latest_pending_subchannel_list_ != nullptr) {
145
- grpc_lb_subchannel_list_shutdown_and_unref(latest_pending_subchannel_list_,
146
- "pf_shutdown");
147
- latest_pending_subchannel_list_ = nullptr;
148
- }
174
+ subchannel_list_.reset();
175
+ latest_pending_subchannel_list_.reset();
149
176
  TryReresolutionLocked(&grpc_lb_pick_first_trace, GRPC_ERROR_CANCELLED);
150
177
  GRPC_ERROR_UNREF(error);
151
178
  }
@@ -192,14 +219,10 @@ void PickFirst::CancelMatchingPicksLocked(uint32_t initial_metadata_flags_mask,
192
219
 
193
220
  void PickFirst::StartPickingLocked() {
194
221
  started_picking_ = true;
195
- if (subchannel_list_ != nullptr && subchannel_list_->num_subchannels > 0) {
196
- subchannel_list_->checking_subchannel = 0;
197
- for (size_t i = 0; i < subchannel_list_->num_subchannels; ++i) {
198
- if (subchannel_list_->subchannels[i].subchannel != nullptr) {
199
- SubchannelListRefForConnectivityWatch(
200
- subchannel_list_, "connectivity_watch+start_picking");
201
- grpc_lb_subchannel_data_start_connectivity_watch(
202
- &subchannel_list_->subchannels[i]);
222
+ if (subchannel_list_ != nullptr) {
223
+ for (size_t i = 0; i < subchannel_list_->num_subchannels(); ++i) {
224
+ if (subchannel_list_->subchannel(i)->subchannel() != nullptr) {
225
+ subchannel_list_->subchannel(i)->StartConnectivityWatchLocked();
203
226
  break;
204
227
  }
205
228
  }
@@ -215,7 +238,7 @@ void PickFirst::ExitIdleLocked() {
215
238
  bool PickFirst::PickLocked(PickState* pick) {
216
239
  // If we have a selected subchannel already, return synchronously.
217
240
  if (selected_ != nullptr) {
218
- pick->connected_subchannel = selected_->connected_subchannel;
241
+ pick->connected_subchannel = selected_->connected_subchannel()->Ref();
219
242
  return true;
220
243
  }
221
244
  // No subchannel selected yet, so handle asynchronously.
@@ -228,11 +251,10 @@ bool PickFirst::PickLocked(PickState* pick) {
228
251
  }
229
252
 
230
253
  void PickFirst::DestroyUnselectedSubchannelsLocked() {
231
- for (size_t i = 0; i < subchannel_list_->num_subchannels; ++i) {
232
- grpc_lb_subchannel_data* sd = &subchannel_list_->subchannels[i];
254
+ for (size_t i = 0; i < subchannel_list_->num_subchannels(); ++i) {
255
+ PickFirstSubchannelData* sd = subchannel_list_->subchannel(i);
233
256
  if (selected_ != sd) {
234
- grpc_lb_subchannel_data_unref_subchannel(sd,
235
- "selected_different_subchannel");
257
+ sd->UnrefSubchannelLocked("selected_different_subchannel");
236
258
  }
237
259
  }
238
260
  }
@@ -249,7 +271,7 @@ void PickFirst::NotifyOnStateChangeLocked(grpc_connectivity_state* current,
249
271
 
250
272
  void PickFirst::PingOneLocked(grpc_closure* on_initiate, grpc_closure* on_ack) {
251
273
  if (selected_ != nullptr) {
252
- selected_->connected_subchannel->Ping(on_initiate, on_ack);
274
+ selected_->connected_subchannel()->Ping(on_initiate, on_ack);
253
275
  } else {
254
276
  GRPC_CLOSURE_SCHED(on_initiate,
255
277
  GRPC_ERROR_CREATE_FROM_STATIC_STRING("Not connected"));
@@ -258,24 +280,6 @@ void PickFirst::PingOneLocked(grpc_closure* on_initiate, grpc_closure* on_ack) {
258
280
  }
259
281
  }
260
282
 
261
- void PickFirst::SubchannelListRefForConnectivityWatch(
262
- grpc_lb_subchannel_list* subchannel_list, const char* reason) {
263
- // TODO(roth): We currently track this ref manually. Once the new
264
- // ClosureRef API is ready and the subchannel_list code has been
265
- // converted to a C++ API, find a way to hold the RefCountedPtr<>
266
- // somewhere (maybe in the subchannel_data object) instead of doing
267
- // this manually.
268
- auto self = Ref(DEBUG_LOCATION, reason);
269
- self.release();
270
- grpc_lb_subchannel_list_ref(subchannel_list, reason);
271
- }
272
-
273
- void PickFirst::SubchannelListUnrefForConnectivityWatch(
274
- grpc_lb_subchannel_list* subchannel_list, const char* reason) {
275
- Unref(DEBUG_LOCATION, reason);
276
- grpc_lb_subchannel_list_unref(subchannel_list, reason);
277
- }
278
-
279
283
  void PickFirst::UpdateLocked(const grpc_channel_args& args) {
280
284
  const grpc_arg* arg = grpc_channel_args_find(&args, GRPC_ARG_LB_ADDRESSES);
281
285
  if (arg == nullptr || arg->type != GRPC_ARG_POINTER) {
@@ -295,75 +299,67 @@ void PickFirst::UpdateLocked(const grpc_channel_args& args) {
295
299
  return;
296
300
  }
297
301
  const grpc_lb_addresses* addresses =
298
- (const grpc_lb_addresses*)arg->value.pointer.p;
302
+ static_cast<const grpc_lb_addresses*>(arg->value.pointer.p);
299
303
  if (grpc_lb_pick_first_trace.enabled()) {
300
304
  gpr_log(GPR_INFO,
301
305
  "Pick First %p received update with %" PRIuPTR " addresses", this,
302
306
  addresses->num_addresses);
303
307
  }
304
- grpc_lb_subchannel_list* subchannel_list = grpc_lb_subchannel_list_create(
308
+ auto subchannel_list = MakeOrphanable<PickFirstSubchannelList>(
305
309
  this, &grpc_lb_pick_first_trace, addresses, combiner(),
306
- client_channel_factory(), args, &PickFirst::OnConnectivityChangedLocked);
307
- if (subchannel_list->num_subchannels == 0) {
310
+ client_channel_factory(), args);
311
+ if (subchannel_list->num_subchannels() == 0) {
308
312
  // Empty update or no valid subchannels. Unsubscribe from all current
309
313
  // subchannels and put the channel in TRANSIENT_FAILURE.
310
314
  grpc_connectivity_state_set(
311
315
  &state_tracker_, GRPC_CHANNEL_TRANSIENT_FAILURE,
312
316
  GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty update"),
313
317
  "pf_update_empty");
314
- if (subchannel_list_ != nullptr) {
315
- grpc_lb_subchannel_list_shutdown_and_unref(subchannel_list_,
316
- "sl_shutdown_empty_update");
317
- }
318
- subchannel_list_ = subchannel_list; // Empty list.
318
+ subchannel_list_ = std::move(subchannel_list); // Empty list.
319
319
  selected_ = nullptr;
320
320
  return;
321
321
  }
322
322
  if (selected_ == nullptr) {
323
323
  // We don't yet have a selected subchannel, so replace the current
324
324
  // subchannel list immediately.
325
- if (subchannel_list_ != nullptr) {
326
- grpc_lb_subchannel_list_shutdown_and_unref(subchannel_list_,
327
- "pf_update_before_selected");
325
+ subchannel_list_ = std::move(subchannel_list);
326
+ // If we've started picking, start trying to connect to the first
327
+ // subchannel in the new list.
328
+ if (started_picking_) {
329
+ subchannel_list_->subchannel(0)->StartConnectivityWatchLocked();
328
330
  }
329
- subchannel_list_ = subchannel_list;
330
331
  } else {
331
332
  // We do have a selected subchannel.
332
333
  // Check if it's present in the new list. If so, we're done.
333
- for (size_t i = 0; i < subchannel_list->num_subchannels; ++i) {
334
- grpc_lb_subchannel_data* sd = &subchannel_list->subchannels[i];
335
- if (sd->subchannel == selected_->subchannel) {
334
+ for (size_t i = 0; i < subchannel_list->num_subchannels(); ++i) {
335
+ PickFirstSubchannelData* sd = subchannel_list->subchannel(i);
336
+ if (sd->subchannel() == selected_->subchannel()) {
336
337
  // The currently selected subchannel is in the update: we are done.
337
338
  if (grpc_lb_pick_first_trace.enabled()) {
338
339
  gpr_log(GPR_INFO,
339
340
  "Pick First %p found already selected subchannel %p "
340
341
  "at update index %" PRIuPTR " of %" PRIuPTR "; update done",
341
- this, selected_->subchannel, i,
342
- subchannel_list->num_subchannels);
343
- }
344
- if (selected_->connected_subchannel != nullptr) {
345
- sd->connected_subchannel = selected_->connected_subchannel;
342
+ this, selected_->subchannel(), i,
343
+ subchannel_list->num_subchannels());
346
344
  }
347
- selected_ = sd;
348
- if (subchannel_list_ != nullptr) {
349
- grpc_lb_subchannel_list_shutdown_and_unref(
350
- subchannel_list_, "pf_update_includes_selected");
345
+ // Make sure it's in state READY. It might not be if we grabbed
346
+ // the combiner while a connectivity state notification
347
+ // informing us otherwise is pending.
348
+ // Note that CheckConnectivityStateLocked() also takes a ref to
349
+ // the connected subchannel.
350
+ grpc_error* error = GRPC_ERROR_NONE;
351
+ if (sd->CheckConnectivityStateLocked(&error) == GRPC_CHANNEL_READY) {
352
+ selected_ = sd;
353
+ subchannel_list_ = std::move(subchannel_list);
354
+ DestroyUnselectedSubchannelsLocked();
355
+ sd->StartConnectivityWatchLocked();
356
+ // If there was a previously pending update (which may or may
357
+ // not have contained the currently selected subchannel), drop
358
+ // it, so that it doesn't override what we've done here.
359
+ latest_pending_subchannel_list_.reset();
360
+ return;
351
361
  }
352
- subchannel_list_ = subchannel_list;
353
- DestroyUnselectedSubchannelsLocked();
354
- SubchannelListRefForConnectivityWatch(
355
- subchannel_list, "connectivity_watch+replace_selected");
356
- grpc_lb_subchannel_data_start_connectivity_watch(sd);
357
- // If there was a previously pending update (which may or may
358
- // not have contained the currently selected subchannel), drop
359
- // it, so that it doesn't override what we've done here.
360
- if (latest_pending_subchannel_list_ != nullptr) {
361
- grpc_lb_subchannel_list_shutdown_and_unref(
362
- latest_pending_subchannel_list_,
363
- "pf_update_includes_selected+outdated");
364
- latest_pending_subchannel_list_ = nullptr;
365
- }
366
- return;
362
+ GRPC_ERROR_UNREF(error);
367
363
  }
368
364
  }
369
365
  // Not keeping the previous selected subchannel, so set the latest
@@ -372,88 +368,66 @@ void PickFirst::UpdateLocked(const grpc_channel_args& args) {
372
368
  // subchannel list.
373
369
  if (latest_pending_subchannel_list_ != nullptr) {
374
370
  if (grpc_lb_pick_first_trace.enabled()) {
375
- gpr_log(GPR_DEBUG,
371
+ gpr_log(GPR_INFO,
376
372
  "Pick First %p Shutting down latest pending subchannel list "
377
373
  "%p, about to be replaced by newer latest %p",
378
- this, latest_pending_subchannel_list_, subchannel_list);
374
+ this, latest_pending_subchannel_list_.get(),
375
+ subchannel_list.get());
379
376
  }
380
- grpc_lb_subchannel_list_shutdown_and_unref(
381
- latest_pending_subchannel_list_, "sl_outdated_dont_smash");
382
377
  }
383
- latest_pending_subchannel_list_ = subchannel_list;
384
- }
385
- // If we've started picking, start trying to connect to the first
386
- // subchannel in the new list.
387
- if (started_picking_) {
388
- SubchannelListRefForConnectivityWatch(subchannel_list,
389
- "connectivity_watch+update");
390
- grpc_lb_subchannel_data_start_connectivity_watch(
391
- &subchannel_list->subchannels[0]);
378
+ latest_pending_subchannel_list_ = std::move(subchannel_list);
379
+ // If we've started picking, start trying to connect to the first
380
+ // subchannel in the new list.
381
+ if (started_picking_) {
382
+ latest_pending_subchannel_list_->subchannel(0)
383
+ ->StartConnectivityWatchLocked();
384
+ }
392
385
  }
393
386
  }
394
387
 
395
- void PickFirst::OnConnectivityChangedLocked(void* arg, grpc_error* error) {
396
- grpc_lb_subchannel_data* sd = static_cast<grpc_lb_subchannel_data*>(arg);
397
- PickFirst* p = static_cast<PickFirst*>(sd->subchannel_list->policy);
398
- if (grpc_lb_pick_first_trace.enabled()) {
399
- gpr_log(GPR_DEBUG,
400
- "Pick First %p connectivity changed for subchannel %p (%" PRIuPTR
401
- " of %" PRIuPTR
402
- "), subchannel_list %p: state=%s p->shutdown_=%d "
403
- "sd->subchannel_list->shutting_down=%d error=%s",
404
- p, sd->subchannel, sd->subchannel_list->checking_subchannel,
405
- sd->subchannel_list->num_subchannels, sd->subchannel_list,
406
- grpc_connectivity_state_name(sd->pending_connectivity_state_unsafe),
407
- p->shutdown_, sd->subchannel_list->shutting_down,
408
- grpc_error_string(error));
409
- }
410
- // If the policy is shutting down, unref and return.
411
- if (p->shutdown_) {
412
- grpc_lb_subchannel_data_stop_connectivity_watch(sd);
413
- grpc_lb_subchannel_data_unref_subchannel(sd, "pf_shutdown");
414
- p->SubchannelListUnrefForConnectivityWatch(sd->subchannel_list,
415
- "pf_shutdown");
416
- return;
417
- }
418
- // If the subchannel list is shutting down, stop watching.
419
- if (sd->subchannel_list->shutting_down || error == GRPC_ERROR_CANCELLED) {
420
- grpc_lb_subchannel_data_stop_connectivity_watch(sd);
421
- grpc_lb_subchannel_data_unref_subchannel(sd, "pf_sl_shutdown");
422
- p->SubchannelListUnrefForConnectivityWatch(sd->subchannel_list,
423
- "pf_sl_shutdown");
424
- return;
425
- }
426
- // If we're still here, the notification must be for a subchannel in
427
- // either the current or latest pending subchannel lists.
428
- GPR_ASSERT(sd->subchannel_list == p->subchannel_list_ ||
429
- sd->subchannel_list == p->latest_pending_subchannel_list_);
430
- // Update state.
431
- sd->curr_connectivity_state = sd->pending_connectivity_state_unsafe;
388
+ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
389
+ grpc_connectivity_state connectivity_state, grpc_error* error) {
390
+ PickFirst* p = static_cast<PickFirst*>(subchannel_list()->policy());
391
+ // The notification must be for a subchannel in either the current or
392
+ // latest pending subchannel lists.
393
+ GPR_ASSERT(subchannel_list() == p->subchannel_list_.get() ||
394
+ subchannel_list() == p->latest_pending_subchannel_list_.get());
432
395
  // Handle updates for the currently selected subchannel.
433
- if (p->selected_ == sd) {
396
+ if (p->selected_ == this) {
397
+ if (grpc_lb_pick_first_trace.enabled()) {
398
+ gpr_log(GPR_INFO,
399
+ "Pick First %p connectivity changed for selected subchannel", p);
400
+ }
434
401
  // If the new state is anything other than READY and there is a
435
402
  // pending update, switch to the pending update.
436
- if (sd->curr_connectivity_state != GRPC_CHANNEL_READY &&
403
+ if (connectivity_state != GRPC_CHANNEL_READY &&
437
404
  p->latest_pending_subchannel_list_ != nullptr) {
405
+ if (grpc_lb_pick_first_trace.enabled()) {
406
+ gpr_log(GPR_INFO,
407
+ "Pick First %p promoting pending subchannel list %p to "
408
+ "replace %p",
409
+ p, p->latest_pending_subchannel_list_.get(),
410
+ p->subchannel_list_.get());
411
+ }
438
412
  p->selected_ = nullptr;
439
- grpc_lb_subchannel_data_stop_connectivity_watch(sd);
440
- p->SubchannelListUnrefForConnectivityWatch(
441
- sd->subchannel_list, "selected_not_ready+switch_to_update");
442
- grpc_lb_subchannel_list_shutdown_and_unref(
443
- p->subchannel_list_, "selected_not_ready+switch_to_update");
444
- p->subchannel_list_ = p->latest_pending_subchannel_list_;
445
- p->latest_pending_subchannel_list_ = nullptr;
413
+ StopConnectivityWatchLocked();
414
+ p->subchannel_list_ = std::move(p->latest_pending_subchannel_list_);
446
415
  grpc_connectivity_state_set(
447
416
  &p->state_tracker_, GRPC_CHANNEL_TRANSIENT_FAILURE,
448
- GRPC_ERROR_REF(error), "selected_not_ready+switch_to_update");
417
+ error != GRPC_ERROR_NONE
418
+ ? GRPC_ERROR_REF(error)
419
+ : GRPC_ERROR_CREATE_FROM_STATIC_STRING(
420
+ "selected subchannel not ready; switching to pending "
421
+ "update"),
422
+ "selected_not_ready+switch_to_update");
449
423
  } else {
450
424
  // TODO(juanlishen): we re-resolve when the selected subchannel goes to
451
425
  // TRANSIENT_FAILURE because we used to shut down in this case before
452
426
  // re-resolution is introduced. But we need to investigate whether we
453
427
  // really want to take any action instead of waiting for the selected
454
428
  // subchannel reconnecting.
455
- GPR_ASSERT(sd->curr_connectivity_state != GRPC_CHANNEL_SHUTDOWN);
456
- if (sd->curr_connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
429
+ GPR_ASSERT(connectivity_state != GRPC_CHANNEL_SHUTDOWN);
430
+ if (connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
457
431
  // If the selected channel goes bad, request a re-resolution.
458
432
  grpc_connectivity_state_set(&p->state_tracker_, GRPC_CHANNEL_IDLE,
459
433
  GRPC_ERROR_NONE,
@@ -462,19 +436,16 @@ void PickFirst::OnConnectivityChangedLocked(void* arg, grpc_error* error) {
462
436
  p->TryReresolutionLocked(&grpc_lb_pick_first_trace, GRPC_ERROR_NONE);
463
437
  // In transient failure. Rely on re-resolution to recover.
464
438
  p->selected_ = nullptr;
465
- grpc_lb_subchannel_data_stop_connectivity_watch(sd);
466
- p->SubchannelListUnrefForConnectivityWatch(sd->subchannel_list,
467
- "pf_selected_shutdown");
468
- grpc_lb_subchannel_data_unref_subchannel(
469
- sd, "pf_selected_shutdown"); // Unrefs connected subchannel
439
+ UnrefSubchannelLocked("pf_selected_shutdown");
440
+ StopConnectivityWatchLocked();
470
441
  } else {
471
- grpc_connectivity_state_set(&p->state_tracker_,
472
- sd->curr_connectivity_state,
442
+ grpc_connectivity_state_set(&p->state_tracker_, connectivity_state,
473
443
  GRPC_ERROR_REF(error), "selected_changed");
474
444
  // Renew notification.
475
- grpc_lb_subchannel_data_start_connectivity_watch(sd);
445
+ RenewConnectivityWatchLocked();
476
446
  }
477
447
  }
448
+ GRPC_ERROR_UNREF(error);
478
449
  return;
479
450
  }
480
451
  // If we get here, there are two possible cases:
@@ -486,26 +457,27 @@ void PickFirst::OnConnectivityChangedLocked(void* arg, grpc_error* error) {
486
457
  // for a subchannel in p->latest_pending_subchannel_list_. The
487
458
  // goal here is to find a subchannel from the update that we can
488
459
  // select in place of the current one.
489
- switch (sd->curr_connectivity_state) {
460
+ switch (connectivity_state) {
490
461
  case GRPC_CHANNEL_READY: {
491
462
  // Case 2. Promote p->latest_pending_subchannel_list_ to
492
463
  // p->subchannel_list_.
493
- sd->connected_subchannel =
494
- grpc_subchannel_get_connected_subchannel(sd->subchannel);
495
- if (sd->subchannel_list == p->latest_pending_subchannel_list_) {
496
- GPR_ASSERT(p->subchannel_list_ != nullptr);
497
- grpc_lb_subchannel_list_shutdown_and_unref(p->subchannel_list_,
498
- "finish_update");
499
- p->subchannel_list_ = p->latest_pending_subchannel_list_;
500
- p->latest_pending_subchannel_list_ = nullptr;
464
+ if (subchannel_list() == p->latest_pending_subchannel_list_.get()) {
465
+ if (grpc_lb_pick_first_trace.enabled()) {
466
+ gpr_log(GPR_INFO,
467
+ "Pick First %p promoting pending subchannel list %p to "
468
+ "replace %p",
469
+ p, p->latest_pending_subchannel_list_.get(),
470
+ p->subchannel_list_.get());
471
+ }
472
+ p->subchannel_list_ = std::move(p->latest_pending_subchannel_list_);
501
473
  }
502
474
  // Cases 1 and 2.
503
475
  grpc_connectivity_state_set(&p->state_tracker_, GRPC_CHANNEL_READY,
504
476
  GRPC_ERROR_NONE, "connecting_ready");
505
- p->selected_ = sd;
477
+ p->selected_ = this;
506
478
  if (grpc_lb_pick_first_trace.enabled()) {
507
479
  gpr_log(GPR_INFO, "Pick First %p selected subchannel %p", p,
508
- sd->subchannel);
480
+ subchannel());
509
481
  }
510
482
  // Drop all other subchannels, since we are now connected.
511
483
  p->DestroyUnselectedSubchannelsLocked();
@@ -513,7 +485,8 @@ void PickFirst::OnConnectivityChangedLocked(void* arg, grpc_error* error) {
513
485
  PickState* pick;
514
486
  while ((pick = p->pending_picks_)) {
515
487
  p->pending_picks_ = pick->next;
516
- pick->connected_subchannel = p->selected_->connected_subchannel;
488
+ pick->connected_subchannel =
489
+ p->selected_->connected_subchannel()->Ref();
517
490
  if (grpc_lb_pick_first_trace.enabled()) {
518
491
  gpr_log(GPR_INFO,
519
492
  "Servicing pending pick with selected subchannel %p",
@@ -522,45 +495,43 @@ void PickFirst::OnConnectivityChangedLocked(void* arg, grpc_error* error) {
522
495
  GRPC_CLOSURE_SCHED(pick->on_complete, GRPC_ERROR_NONE);
523
496
  }
524
497
  // Renew notification.
525
- grpc_lb_subchannel_data_start_connectivity_watch(sd);
498
+ RenewConnectivityWatchLocked();
526
499
  break;
527
500
  }
528
501
  case GRPC_CHANNEL_TRANSIENT_FAILURE: {
529
- grpc_lb_subchannel_data_stop_connectivity_watch(sd);
502
+ StopConnectivityWatchLocked();
503
+ PickFirstSubchannelData* sd = this;
530
504
  do {
531
- sd->subchannel_list->checking_subchannel =
532
- (sd->subchannel_list->checking_subchannel + 1) %
533
- sd->subchannel_list->num_subchannels;
534
- sd = &sd->subchannel_list
535
- ->subchannels[sd->subchannel_list->checking_subchannel];
536
- } while (sd->subchannel == nullptr);
505
+ size_t next_index =
506
+ (sd->Index() + 1) % subchannel_list()->num_subchannels();
507
+ sd = subchannel_list()->subchannel(next_index);
508
+ } while (sd->subchannel() == nullptr);
537
509
  // Case 1: Only set state to TRANSIENT_FAILURE if we've tried
538
510
  // all subchannels.
539
- if (sd->subchannel_list->checking_subchannel == 0 &&
540
- sd->subchannel_list == p->subchannel_list_) {
511
+ if (sd->Index() == 0 && subchannel_list() == p->subchannel_list_.get()) {
541
512
  grpc_connectivity_state_set(
542
513
  &p->state_tracker_, GRPC_CHANNEL_TRANSIENT_FAILURE,
543
514
  GRPC_ERROR_REF(error), "connecting_transient_failure");
544
515
  }
545
- // Reuses the connectivity refs from the previous watch.
546
- grpc_lb_subchannel_data_start_connectivity_watch(sd);
516
+ sd->StartConnectivityWatchLocked();
547
517
  break;
548
518
  }
549
519
  case GRPC_CHANNEL_CONNECTING:
550
520
  case GRPC_CHANNEL_IDLE: {
551
521
  // Only update connectivity state in case 1.
552
- if (sd->subchannel_list == p->subchannel_list_) {
522
+ if (subchannel_list() == p->subchannel_list_.get()) {
553
523
  grpc_connectivity_state_set(&p->state_tracker_, GRPC_CHANNEL_CONNECTING,
554
524
  GRPC_ERROR_REF(error),
555
525
  "connecting_changed");
556
526
  }
557
527
  // Renew notification.
558
- grpc_lb_subchannel_data_start_connectivity_watch(sd);
528
+ RenewConnectivityWatchLocked();
559
529
  break;
560
530
  }
561
531
  case GRPC_CHANNEL_SHUTDOWN:
562
532
  GPR_UNREACHABLE_CODE(break);
563
533
  }
534
+ GRPC_ERROR_UNREF(error);
564
535
  }
565
536
 
566
537
  //