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
@@ -21,116 +21,516 @@
21
21
 
22
22
  #include <grpc/support/port_platform.h>
23
23
 
24
+ #include <string.h>
25
+
26
+ #include <grpc/support/alloc.h>
27
+
24
28
  #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
25
29
  #include "src/core/ext/filters/client_channel/subchannel.h"
30
+ #include "src/core/lib/channel/channel_args.h"
26
31
  #include "src/core/lib/debug/trace.h"
32
+ #include "src/core/lib/gprpp/abstract.h"
33
+ #include "src/core/lib/gprpp/inlined_vector.h"
34
+ #include "src/core/lib/gprpp/orphanable.h"
35
+ #include "src/core/lib/gprpp/ref_counted.h"
27
36
  #include "src/core/lib/gprpp/ref_counted_ptr.h"
37
+ #include "src/core/lib/iomgr/closure.h"
38
+ #include "src/core/lib/iomgr/combiner.h"
39
+ #include "src/core/lib/iomgr/sockaddr_utils.h"
28
40
  #include "src/core/lib/transport/connectivity_state.h"
29
41
 
30
- // TODO(roth): This code is intended to be shared between pick_first and
31
- // round_robin. However, the interface needs more work to provide clean
32
- // encapsulation. For example, the structs here have some fields that are
33
- // only used in one of the two (e.g., the state counters in
34
- // grpc_lb_subchannel_list and the prev_connectivity_state field in
35
- // grpc_lb_subchannel_data are only used in round_robin, and the
36
- // checking_subchannel field in grpc_lb_subchannel_list is only used by
37
- // pick_first). Also, there is probably some code duplication between the
38
- // connectivity state notification callback code in both pick_first and
39
- // round_robin that could be refactored and moved here. In a future PR,
40
- // need to clean this up.
41
-
42
- typedef struct grpc_lb_subchannel_list grpc_lb_subchannel_list;
43
-
44
- typedef struct {
45
- /** backpointer to owning subchannel list */
46
- grpc_lb_subchannel_list* subchannel_list;
47
- /** subchannel itself */
48
- grpc_subchannel* subchannel;
49
- grpc_core::RefCountedPtr<grpc_core::ConnectedSubchannel> connected_subchannel;
50
- /** Is a connectivity notification pending? */
51
- bool connectivity_notification_pending;
52
- /** notification that connectivity has changed on subchannel */
53
- grpc_closure connectivity_changed_closure;
54
- /** previous and current connectivity states. Updated by \a
55
- * \a connectivity_changed_closure based on
56
- * \a pending_connectivity_state_unsafe. */
57
- grpc_connectivity_state prev_connectivity_state;
58
- grpc_connectivity_state curr_connectivity_state;
59
- /** connectivity state to be updated by
60
- * grpc_subchannel_notify_on_state_change(), not guarded by
61
- * the combiner. To be copied to \a curr_connectivity_state by
62
- * \a connectivity_changed_closure. */
63
- grpc_connectivity_state pending_connectivity_state_unsafe;
64
- /** the subchannel's target user data */
65
- void* user_data;
66
- /** vtable to operate over \a user_data */
67
- const grpc_lb_user_data_vtable* user_data_vtable;
68
- } grpc_lb_subchannel_data;
69
-
70
- /// Unrefs the subchannel contained in sd.
71
- void grpc_lb_subchannel_data_unref_subchannel(grpc_lb_subchannel_data* sd,
72
- const char* reason);
73
-
74
- /// Starts watching the connectivity state of the subchannel.
75
- /// The connectivity_changed_cb callback must invoke either
76
- /// grpc_lb_subchannel_data_stop_connectivity_watch() or again call
77
- /// grpc_lb_subchannel_data_start_connectivity_watch().
78
- void grpc_lb_subchannel_data_start_connectivity_watch(
79
- grpc_lb_subchannel_data* sd);
80
-
81
- /// Stops watching the connectivity state of the subchannel.
82
- void grpc_lb_subchannel_data_stop_connectivity_watch(
83
- grpc_lb_subchannel_data* sd);
84
-
85
- struct grpc_lb_subchannel_list {
86
- /** backpointer to owning policy */
87
- grpc_core::LoadBalancingPolicy* policy;
88
-
89
- grpc_core::TraceFlag* tracer;
90
-
91
- /** all our subchannels */
92
- size_t num_subchannels;
93
- grpc_lb_subchannel_data* subchannels;
94
-
95
- /** Index into subchannels of the one we're currently checking.
96
- * Used when connecting to subchannels serially instead of in parallel. */
97
- // TODO(roth): When we have time, we can probably make this go away
98
- // and compute the index dynamically by subtracting
99
- // subchannel_list->subchannels from the subchannel_data pointer.
100
- size_t checking_subchannel;
101
-
102
- /** how many subchannels are in state READY */
103
- size_t num_ready;
104
- /** how many subchannels are in state TRANSIENT_FAILURE */
105
- size_t num_transient_failures;
106
- /** how many subchannels are in state IDLE */
107
- size_t num_idle;
108
-
109
- /** There will be one ref for each entry in subchannels for which there is a
110
- * pending connectivity state watcher callback. */
111
- gpr_refcount refcount;
112
-
113
- /** Is this list shutting down? This may be true due to the shutdown of the
114
- * policy itself or because a newer update has arrived while this one hadn't
115
- * finished processing. */
116
- bool shutting_down;
42
+ // Code for maintaining a list of subchannels within an LB policy.
43
+ //
44
+ // To use this, callers must create their own subclasses, like so:
45
+ /*
46
+
47
+ class MySubchannelList; // Forward declaration.
48
+
49
+ class MySubchannelData
50
+ : public SubchannelData<MySubchannelList, MySubchannelData> {
51
+ public:
52
+ void ProcessConnectivityChangeLocked(
53
+ grpc_connectivity_state connectivity_state, grpc_error* error) override {
54
+ // ...code to handle connectivity changes...
55
+ }
56
+ };
57
+
58
+ class MySubchannelList
59
+ : public SubchannelList<MySubchannelList, MySubchannelData> {
117
60
  };
118
61
 
119
- grpc_lb_subchannel_list* grpc_lb_subchannel_list_create(
120
- grpc_core::LoadBalancingPolicy* p, grpc_core::TraceFlag* tracer,
62
+ */
63
+ // All methods with a Locked() suffix must be called from within the
64
+ // client_channel combiner.
65
+
66
+ namespace grpc_core {
67
+
68
+ // Stores data for a particular subchannel in a subchannel list.
69
+ // Callers must create a subclass that implements the
70
+ // ProcessConnectivityChangeLocked() method.
71
+ template <typename SubchannelListType, typename SubchannelDataType>
72
+ class SubchannelData {
73
+ public:
74
+ // Returns a pointer to the subchannel list containing this object.
75
+ SubchannelListType* subchannel_list() const { return subchannel_list_; }
76
+
77
+ // Returns the index into the subchannel list of this object.
78
+ size_t Index() const {
79
+ return static_cast<size_t>(static_cast<const SubchannelDataType*>(this) -
80
+ subchannel_list_->subchannel(0));
81
+ }
82
+
83
+ // Returns a pointer to the subchannel.
84
+ grpc_subchannel* subchannel() const { return subchannel_; }
85
+
86
+ // Returns the connected subchannel. Will be null if the subchannel
87
+ // is not connected.
88
+ ConnectedSubchannel* connected_subchannel() const {
89
+ return connected_subchannel_.get();
90
+ }
91
+
92
+ // Synchronously checks the subchannel's connectivity state.
93
+ // Must not be called while there is a connectivity notification
94
+ // pending (i.e., between calling StartConnectivityWatchLocked() or
95
+ // RenewConnectivityWatchLocked() and the resulting invocation of
96
+ // ProcessConnectivityChangeLocked()).
97
+ grpc_connectivity_state CheckConnectivityStateLocked(grpc_error** error) {
98
+ GPR_ASSERT(!connectivity_notification_pending_);
99
+ pending_connectivity_state_unsafe_ =
100
+ grpc_subchannel_check_connectivity(subchannel(), error);
101
+ UpdateConnectedSubchannelLocked();
102
+ return pending_connectivity_state_unsafe_;
103
+ }
104
+
105
+ // Unrefs the subchannel. May be used if an individual subchannel is
106
+ // no longer needed even though the subchannel list as a whole is not
107
+ // being unreffed.
108
+ virtual void UnrefSubchannelLocked(const char* reason);
109
+
110
+ // Starts watching the connectivity state of the subchannel.
111
+ // ProcessConnectivityChangeLocked() will be called when the
112
+ // connectivity state changes.
113
+ void StartConnectivityWatchLocked();
114
+
115
+ // Renews watching the connectivity state of the subchannel.
116
+ void RenewConnectivityWatchLocked();
117
+
118
+ // Stops watching the connectivity state of the subchannel.
119
+ void StopConnectivityWatchLocked();
120
+
121
+ // Cancels watching the connectivity state of the subchannel.
122
+ // Must be called only while there is a connectivity notification
123
+ // pending (i.e., between calling StartConnectivityWatchLocked() or
124
+ // RenewConnectivityWatchLocked() and the resulting invocation of
125
+ // ProcessConnectivityChangeLocked()).
126
+ // From within ProcessConnectivityChangeLocked(), use
127
+ // StopConnectivityWatchLocked() instead.
128
+ void CancelConnectivityWatchLocked(const char* reason);
129
+
130
+ // Cancels any pending connectivity watch and unrefs the subchannel.
131
+ void ShutdownLocked();
132
+
133
+ GRPC_ABSTRACT_BASE_CLASS
134
+
135
+ protected:
136
+ SubchannelData(SubchannelListType* subchannel_list,
137
+ const grpc_lb_user_data_vtable* user_data_vtable,
138
+ const grpc_lb_address& address, grpc_subchannel* subchannel,
139
+ grpc_combiner* combiner);
140
+
141
+ virtual ~SubchannelData();
142
+
143
+ // After StartConnectivityWatchLocked() or RenewConnectivityWatchLocked()
144
+ // is called, this method will be invoked when the subchannel's connectivity
145
+ // state changes.
146
+ // Implementations must invoke either RenewConnectivityWatchLocked() or
147
+ // StopConnectivityWatchLocked() before returning.
148
+ virtual void ProcessConnectivityChangeLocked(
149
+ grpc_connectivity_state connectivity_state,
150
+ grpc_error* error) GRPC_ABSTRACT;
151
+
152
+ private:
153
+ // Updates connected_subchannel_ based on pending_connectivity_state_unsafe_.
154
+ // Returns true if the connectivity state should be reported.
155
+ bool UpdateConnectedSubchannelLocked();
156
+
157
+ static void OnConnectivityChangedLocked(void* arg, grpc_error* error);
158
+
159
+ // Backpointer to owning subchannel list. Not owned.
160
+ SubchannelListType* subchannel_list_;
161
+
162
+ // The subchannel and connected subchannel.
163
+ grpc_subchannel* subchannel_;
164
+ RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
165
+
166
+ // Notification that connectivity has changed on subchannel.
167
+ grpc_closure connectivity_changed_closure_;
168
+ // Is a connectivity notification pending?
169
+ bool connectivity_notification_pending_ = false;
170
+ // Connectivity state to be updated by
171
+ // grpc_subchannel_notify_on_state_change(), not guarded by
172
+ // the combiner.
173
+ grpc_connectivity_state pending_connectivity_state_unsafe_;
174
+ };
175
+
176
+ // A list of subchannels.
177
+ template <typename SubchannelListType, typename SubchannelDataType>
178
+ class SubchannelList
179
+ : public InternallyRefCountedWithTracing<SubchannelListType> {
180
+ public:
181
+ typedef InlinedVector<SubchannelDataType, 10> SubchannelVector;
182
+
183
+ // The number of subchannels in the list.
184
+ size_t num_subchannels() const { return subchannels_.size(); }
185
+
186
+ // The data for the subchannel at a particular index.
187
+ SubchannelDataType* subchannel(size_t index) { return &subchannels_[index]; }
188
+
189
+ // Returns true if the subchannel list is shutting down.
190
+ bool shutting_down() const { return shutting_down_; }
191
+
192
+ // Accessors.
193
+ LoadBalancingPolicy* policy() const { return policy_; }
194
+ TraceFlag* tracer() const { return tracer_; }
195
+
196
+ // Note: Caller must ensure that this is invoked inside of the combiner.
197
+ void Orphan() override {
198
+ ShutdownLocked();
199
+ InternallyRefCountedWithTracing<SubchannelListType>::Unref(DEBUG_LOCATION,
200
+ "shutdown");
201
+ }
202
+
203
+ GRPC_ABSTRACT_BASE_CLASS
204
+
205
+ protected:
206
+ SubchannelList(LoadBalancingPolicy* policy, TraceFlag* tracer,
207
+ const grpc_lb_addresses* addresses, grpc_combiner* combiner,
208
+ grpc_client_channel_factory* client_channel_factory,
209
+ const grpc_channel_args& args);
210
+
211
+ virtual ~SubchannelList();
212
+
213
+ private:
214
+ // So New() can call our private ctor.
215
+ template <typename T, typename... Args>
216
+ friend T* New(Args&&... args);
217
+
218
+ // For accessing Ref() and Unref().
219
+ friend class SubchannelData<SubchannelListType, SubchannelDataType>;
220
+
221
+ void ShutdownLocked();
222
+
223
+ // Backpointer to owning policy.
224
+ LoadBalancingPolicy* policy_;
225
+
226
+ TraceFlag* tracer_;
227
+
228
+ grpc_combiner* combiner_;
229
+
230
+ // The list of subchannels.
231
+ SubchannelVector subchannels_;
232
+
233
+ // Is this list shutting down? This may be true due to the shutdown of the
234
+ // policy itself or because a newer update has arrived while this one hadn't
235
+ // finished processing.
236
+ bool shutting_down_ = false;
237
+ };
238
+
239
+ //
240
+ // implementation -- no user-servicable parts below
241
+ //
242
+
243
+ //
244
+ // SubchannelData
245
+ //
246
+
247
+ template <typename SubchannelListType, typename SubchannelDataType>
248
+ SubchannelData<SubchannelListType, SubchannelDataType>::SubchannelData(
249
+ SubchannelListType* subchannel_list,
250
+ const grpc_lb_user_data_vtable* user_data_vtable,
251
+ const grpc_lb_address& address, grpc_subchannel* subchannel,
252
+ grpc_combiner* combiner)
253
+ : subchannel_list_(subchannel_list),
254
+ subchannel_(subchannel),
255
+ // We assume that the current state is IDLE. If not, we'll get a
256
+ // callback telling us that.
257
+ pending_connectivity_state_unsafe_(GRPC_CHANNEL_IDLE) {
258
+ GRPC_CLOSURE_INIT(
259
+ &connectivity_changed_closure_,
260
+ (&SubchannelData<SubchannelListType,
261
+ SubchannelDataType>::OnConnectivityChangedLocked),
262
+ this, grpc_combiner_scheduler(combiner));
263
+ }
264
+
265
+ template <typename SubchannelListType, typename SubchannelDataType>
266
+ SubchannelData<SubchannelListType, SubchannelDataType>::~SubchannelData() {
267
+ UnrefSubchannelLocked("subchannel_data_destroy");
268
+ }
269
+
270
+ template <typename SubchannelListType, typename SubchannelDataType>
271
+ void SubchannelData<SubchannelListType, SubchannelDataType>::
272
+ UnrefSubchannelLocked(const char* reason) {
273
+ if (subchannel_ != nullptr) {
274
+ if (subchannel_list_->tracer()->enabled()) {
275
+ gpr_log(GPR_INFO,
276
+ "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR
277
+ " (subchannel %p): unreffing subchannel",
278
+ subchannel_list_->tracer()->name(), subchannel_list_->policy(),
279
+ subchannel_list_, Index(), subchannel_list_->num_subchannels(),
280
+ subchannel_);
281
+ }
282
+ GRPC_SUBCHANNEL_UNREF(subchannel_, reason);
283
+ subchannel_ = nullptr;
284
+ connected_subchannel_.reset();
285
+ }
286
+ }
287
+
288
+ template <typename SubchannelListType, typename SubchannelDataType>
289
+ void SubchannelData<SubchannelListType,
290
+ SubchannelDataType>::StartConnectivityWatchLocked() {
291
+ if (subchannel_list_->tracer()->enabled()) {
292
+ gpr_log(GPR_INFO,
293
+ "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR
294
+ " (subchannel %p): starting watch: requesting connectivity change "
295
+ "notification (from %s)",
296
+ subchannel_list_->tracer()->name(), subchannel_list_->policy(),
297
+ subchannel_list_, Index(), subchannel_list_->num_subchannels(),
298
+ subchannel_,
299
+ grpc_connectivity_state_name(pending_connectivity_state_unsafe_));
300
+ }
301
+ GPR_ASSERT(!connectivity_notification_pending_);
302
+ connectivity_notification_pending_ = true;
303
+ subchannel_list()->Ref(DEBUG_LOCATION, "connectivity_watch").release();
304
+ grpc_subchannel_notify_on_state_change(
305
+ subchannel_, subchannel_list_->policy()->interested_parties(),
306
+ &pending_connectivity_state_unsafe_, &connectivity_changed_closure_);
307
+ }
308
+
309
+ template <typename SubchannelListType, typename SubchannelDataType>
310
+ void SubchannelData<SubchannelListType,
311
+ SubchannelDataType>::RenewConnectivityWatchLocked() {
312
+ if (subchannel_list_->tracer()->enabled()) {
313
+ gpr_log(GPR_INFO,
314
+ "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR
315
+ " (subchannel %p): renewing watch: requesting connectivity change "
316
+ "notification (from %s)",
317
+ subchannel_list_->tracer()->name(), subchannel_list_->policy(),
318
+ subchannel_list_, Index(), subchannel_list_->num_subchannels(),
319
+ subchannel_,
320
+ grpc_connectivity_state_name(pending_connectivity_state_unsafe_));
321
+ }
322
+ GPR_ASSERT(connectivity_notification_pending_);
323
+ grpc_subchannel_notify_on_state_change(
324
+ subchannel_, subchannel_list_->policy()->interested_parties(),
325
+ &pending_connectivity_state_unsafe_, &connectivity_changed_closure_);
326
+ }
327
+
328
+ template <typename SubchannelListType, typename SubchannelDataType>
329
+ void SubchannelData<SubchannelListType,
330
+ SubchannelDataType>::StopConnectivityWatchLocked() {
331
+ if (subchannel_list_->tracer()->enabled()) {
332
+ gpr_log(GPR_INFO,
333
+ "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR
334
+ " (subchannel %p): stopping connectivity watch",
335
+ subchannel_list_->tracer()->name(), subchannel_list_->policy(),
336
+ subchannel_list_, Index(), subchannel_list_->num_subchannels(),
337
+ subchannel_);
338
+ }
339
+ GPR_ASSERT(connectivity_notification_pending_);
340
+ connectivity_notification_pending_ = false;
341
+ subchannel_list()->Unref(DEBUG_LOCATION, "connectivity_watch");
342
+ }
343
+
344
+ template <typename SubchannelListType, typename SubchannelDataType>
345
+ void SubchannelData<SubchannelListType, SubchannelDataType>::
346
+ CancelConnectivityWatchLocked(const char* reason) {
347
+ if (subchannel_list_->tracer()->enabled()) {
348
+ gpr_log(GPR_INFO,
349
+ "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR
350
+ " (subchannel %p): canceling connectivity watch (%s)",
351
+ subchannel_list_->tracer()->name(), subchannel_list_->policy(),
352
+ subchannel_list_, Index(), subchannel_list_->num_subchannels(),
353
+ subchannel_, reason);
354
+ }
355
+ GPR_ASSERT(connectivity_notification_pending_);
356
+ grpc_subchannel_notify_on_state_change(subchannel_, nullptr, nullptr,
357
+ &connectivity_changed_closure_);
358
+ }
359
+
360
+ template <typename SubchannelListType, typename SubchannelDataType>
361
+ bool SubchannelData<SubchannelListType,
362
+ SubchannelDataType>::UpdateConnectedSubchannelLocked() {
363
+ // If the subchannel is READY, take a ref to the connected subchannel.
364
+ if (pending_connectivity_state_unsafe_ == GRPC_CHANNEL_READY) {
365
+ connected_subchannel_ =
366
+ grpc_subchannel_get_connected_subchannel(subchannel_);
367
+ // If the subchannel became disconnected between the time that READY
368
+ // was reported and the time we got here (e.g., between when a
369
+ // notification callback is scheduled and when it was actually run in
370
+ // the combiner), then the connected subchannel may have disappeared out
371
+ // from under us. In that case, we don't actually want to consider the
372
+ // subchannel to be in state READY. Instead, we use IDLE as the
373
+ // basis for any future connectivity watch; this is the one state that
374
+ // the subchannel will never transition back into, so this ensures
375
+ // that we will get a notification for the next state, even if that state
376
+ // is READY again (e.g., if the subchannel has transitioned back to
377
+ // READY before the next watch gets requested).
378
+ if (connected_subchannel_ == nullptr) {
379
+ if (subchannel_list_->tracer()->enabled()) {
380
+ gpr_log(GPR_INFO,
381
+ "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR
382
+ " (subchannel %p): state is READY but connected subchannel is "
383
+ "null; moving to state IDLE",
384
+ subchannel_list_->tracer()->name(), subchannel_list_->policy(),
385
+ subchannel_list_, Index(), subchannel_list_->num_subchannels(),
386
+ subchannel_);
387
+ }
388
+ pending_connectivity_state_unsafe_ = GRPC_CHANNEL_IDLE;
389
+ return false;
390
+ }
391
+ } else {
392
+ // For any state other than READY, unref the connected subchannel.
393
+ connected_subchannel_.reset();
394
+ }
395
+ return true;
396
+ }
397
+
398
+ template <typename SubchannelListType, typename SubchannelDataType>
399
+ void SubchannelData<SubchannelListType, SubchannelDataType>::
400
+ OnConnectivityChangedLocked(void* arg, grpc_error* error) {
401
+ SubchannelData* sd = static_cast<SubchannelData*>(arg);
402
+ if (sd->subchannel_list_->tracer()->enabled()) {
403
+ gpr_log(
404
+ GPR_INFO,
405
+ "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR
406
+ " (subchannel %p): connectivity changed: state=%s, error=%s, "
407
+ "shutting_down=%d",
408
+ sd->subchannel_list_->tracer()->name(), sd->subchannel_list_->policy(),
409
+ sd->subchannel_list_, sd->Index(),
410
+ sd->subchannel_list_->num_subchannels(), sd->subchannel_,
411
+ grpc_connectivity_state_name(sd->pending_connectivity_state_unsafe_),
412
+ grpc_error_string(error), sd->subchannel_list_->shutting_down());
413
+ }
414
+ // If shutting down, unref subchannel and stop watching.
415
+ if (sd->subchannel_list_->shutting_down() || error == GRPC_ERROR_CANCELLED) {
416
+ sd->UnrefSubchannelLocked("connectivity_shutdown");
417
+ sd->StopConnectivityWatchLocked();
418
+ return;
419
+ }
420
+ // Get or release ref to connected subchannel.
421
+ if (!sd->UpdateConnectedSubchannelLocked()) {
422
+ // We don't want to report this connectivity state, so renew the watch.
423
+ sd->RenewConnectivityWatchLocked();
424
+ return;
425
+ }
426
+ // Call the subclass's ProcessConnectivityChangeLocked() method.
427
+ sd->ProcessConnectivityChangeLocked(sd->pending_connectivity_state_unsafe_,
428
+ GRPC_ERROR_REF(error));
429
+ }
430
+
431
+ template <typename SubchannelListType, typename SubchannelDataType>
432
+ void SubchannelData<SubchannelListType, SubchannelDataType>::ShutdownLocked() {
433
+ // If there's a pending notification for this subchannel, cancel it;
434
+ // the callback is responsible for unreffing the subchannel.
435
+ // Otherwise, unref the subchannel directly.
436
+ if (connectivity_notification_pending_) {
437
+ CancelConnectivityWatchLocked("shutdown");
438
+ } else if (subchannel_ != nullptr) {
439
+ UnrefSubchannelLocked("shutdown");
440
+ }
441
+ }
442
+
443
+ //
444
+ // SubchannelList
445
+ //
446
+
447
+ template <typename SubchannelListType, typename SubchannelDataType>
448
+ SubchannelList<SubchannelListType, SubchannelDataType>::SubchannelList(
449
+ LoadBalancingPolicy* policy, TraceFlag* tracer,
121
450
  const grpc_lb_addresses* addresses, grpc_combiner* combiner,
122
451
  grpc_client_channel_factory* client_channel_factory,
123
- const grpc_channel_args& args, grpc_iomgr_cb_func connectivity_changed_cb);
452
+ const grpc_channel_args& args)
453
+ : InternallyRefCountedWithTracing<SubchannelListType>(tracer),
454
+ policy_(policy),
455
+ tracer_(tracer),
456
+ combiner_(GRPC_COMBINER_REF(combiner, "subchannel_list")) {
457
+ if (tracer_->enabled()) {
458
+ gpr_log(GPR_INFO,
459
+ "[%s %p] Creating subchannel list %p for %" PRIuPTR " subchannels",
460
+ tracer_->name(), policy, this, addresses->num_addresses);
461
+ }
462
+ subchannels_.reserve(addresses->num_addresses);
463
+ // We need to remove the LB addresses in order to be able to compare the
464
+ // subchannel keys of subchannels from a different batch of addresses.
465
+ static const char* keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS,
466
+ GRPC_ARG_LB_ADDRESSES};
467
+ // Create a subchannel for each address.
468
+ grpc_subchannel_args sc_args;
469
+ for (size_t i = 0; i < addresses->num_addresses; i++) {
470
+ // If there were any balancer, we would have chosen grpclb policy instead.
471
+ GPR_ASSERT(!addresses->addresses[i].is_balancer);
472
+ memset(&sc_args, 0, sizeof(grpc_subchannel_args));
473
+ grpc_arg addr_arg =
474
+ grpc_create_subchannel_address_arg(&addresses->addresses[i].address);
475
+ grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove(
476
+ &args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &addr_arg, 1);
477
+ gpr_free(addr_arg.value.string);
478
+ sc_args.args = new_args;
479
+ grpc_subchannel* subchannel = grpc_client_channel_factory_create_subchannel(
480
+ client_channel_factory, &sc_args);
481
+ grpc_channel_args_destroy(new_args);
482
+ if (subchannel == nullptr) {
483
+ // Subchannel could not be created.
484
+ if (tracer_->enabled()) {
485
+ char* address_uri =
486
+ grpc_sockaddr_to_uri(&addresses->addresses[i].address);
487
+ gpr_log(GPR_INFO,
488
+ "[%s %p] could not create subchannel for address uri %s, "
489
+ "ignoring",
490
+ tracer_->name(), policy_, address_uri);
491
+ gpr_free(address_uri);
492
+ }
493
+ continue;
494
+ }
495
+ if (tracer_->enabled()) {
496
+ char* address_uri =
497
+ grpc_sockaddr_to_uri(&addresses->addresses[i].address);
498
+ gpr_log(GPR_INFO,
499
+ "[%s %p] subchannel list %p index %" PRIuPTR
500
+ ": Created subchannel %p for address uri %s",
501
+ tracer_->name(), policy_, this, subchannels_.size(), subchannel,
502
+ address_uri);
503
+ gpr_free(address_uri);
504
+ }
505
+ subchannels_.emplace_back(static_cast<SubchannelListType*>(this),
506
+ addresses->user_data_vtable,
507
+ addresses->addresses[i], subchannel, combiner);
508
+ }
509
+ }
124
510
 
125
- void grpc_lb_subchannel_list_ref(grpc_lb_subchannel_list* subchannel_list,
126
- const char* reason);
511
+ template <typename SubchannelListType, typename SubchannelDataType>
512
+ SubchannelList<SubchannelListType, SubchannelDataType>::~SubchannelList() {
513
+ if (tracer_->enabled()) {
514
+ gpr_log(GPR_INFO, "[%s %p] Destroying subchannel_list %p", tracer_->name(),
515
+ policy_, this);
516
+ }
517
+ GRPC_COMBINER_UNREF(combiner_, "subchannel_list");
518
+ }
127
519
 
128
- void grpc_lb_subchannel_list_unref(grpc_lb_subchannel_list* subchannel_list,
129
- const char* reason);
520
+ template <typename SubchannelListType, typename SubchannelDataType>
521
+ void SubchannelList<SubchannelListType, SubchannelDataType>::ShutdownLocked() {
522
+ if (tracer_->enabled()) {
523
+ gpr_log(GPR_INFO, "[%s %p] Shutting down subchannel_list %p",
524
+ tracer_->name(), policy_, this);
525
+ }
526
+ GPR_ASSERT(!shutting_down_);
527
+ shutting_down_ = true;
528
+ for (size_t i = 0; i < subchannels_.size(); i++) {
529
+ SubchannelDataType* sd = &subchannels_[i];
530
+ sd->ShutdownLocked();
531
+ }
532
+ }
130
533
 
131
- /// Mark subchannel_list as discarded. Unsubscribes all its subchannels. The
132
- /// connectivity state notification callback will ultimately unref it.
133
- void grpc_lb_subchannel_list_shutdown_and_unref(
134
- grpc_lb_subchannel_list* subchannel_list, const char* reason);
534
+ } // namespace grpc_core
135
535
 
136
536
  #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_SUBCHANNEL_LIST_H */