grpc 1.14.2 → 1.15.0.pre1

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 (113) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +307 -12
  3. data/etc/roots.pem +40 -163
  4. data/include/grpc/grpc.h +49 -0
  5. data/include/grpc/grpc_security.h +0 -6
  6. data/include/grpc/grpc_security_constants.h +6 -0
  7. data/include/grpc/impl/codegen/grpc_types.h +17 -2
  8. data/include/grpc/impl/codegen/port_platform.h +41 -4
  9. data/include/grpc/support/sync.h +0 -16
  10. data/src/{cpp → core}/ext/filters/census/grpc_context.cc +0 -0
  11. data/src/core/ext/filters/client_channel/client_channel.cc +40 -11
  12. data/src/core/ext/filters/client_channel/client_channel_channelz.cc +11 -9
  13. data/src/core/ext/filters/client_channel/client_channel_channelz.h +4 -2
  14. data/src/core/ext/filters/client_channel/lb_policy.h +14 -11
  15. data/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc +67 -90
  16. data/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc +108 -91
  17. data/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc +79 -25
  18. data/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h +40 -0
  19. data/src/core/ext/filters/client_channel/resolver.h +8 -0
  20. data/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc +11 -3
  21. data/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc +13 -10
  22. data/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h +18 -4
  23. data/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc +13 -5
  24. data/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc +537 -0
  25. data/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc +6 -5
  26. data/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h +11 -0
  27. data/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc +29 -0
  28. data/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc +29 -0
  29. data/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc +9 -0
  30. data/src/core/ext/filters/client_channel/subchannel.cc +21 -8
  31. data/src/core/ext/filters/client_channel/subchannel.h +7 -0
  32. data/src/core/ext/filters/http/client_authority_filter.cc +1 -1
  33. data/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +24 -0
  34. data/src/core/ext/transport/chttp2/transport/flow_control.cc +10 -7
  35. data/src/core/lib/channel/channel_stack.h +1 -1
  36. data/src/core/lib/channel/channel_trace.cc +1 -1
  37. data/src/core/lib/channel/channel_trace.h +1 -1
  38. data/src/core/lib/channel/channelz.cc +37 -27
  39. data/src/core/lib/channel/channelz.h +13 -4
  40. data/src/core/lib/channel/channelz_registry.cc +89 -4
  41. data/src/core/lib/channel/channelz_registry.h +56 -39
  42. data/src/core/lib/gpr/arena.cc +33 -40
  43. data/src/core/lib/gprpp/fork.cc +41 -33
  44. data/src/core/lib/gprpp/fork.h +13 -4
  45. data/src/core/lib/gprpp/mutex_lock.h +42 -0
  46. data/src/core/lib/gprpp/orphanable.h +4 -2
  47. data/src/core/lib/gprpp/ref_counted.h +4 -2
  48. data/src/core/lib/gprpp/ref_counted_ptr.h +65 -13
  49. data/src/core/lib/iomgr/call_combiner.h +4 -1
  50. data/src/core/lib/iomgr/ev_epoll1_linux.cc +77 -17
  51. data/src/core/lib/iomgr/ev_epollex_linux.cc +8 -26
  52. data/src/core/lib/iomgr/ev_epollsig_linux.cc +10 -28
  53. data/src/core/lib/iomgr/ev_poll_posix.cc +144 -35
  54. data/src/core/lib/iomgr/ev_posix.cc +58 -9
  55. data/src/core/lib/iomgr/ev_posix.h +22 -8
  56. data/src/core/lib/iomgr/exec_ctx.cc +6 -0
  57. data/src/core/lib/iomgr/exec_ctx.h +2 -0
  58. data/src/core/lib/iomgr/executor.cc +148 -72
  59. data/src/core/lib/iomgr/executor.h +39 -6
  60. data/src/core/lib/iomgr/fork_posix.cc +12 -1
  61. data/src/core/lib/iomgr/iocp_windows.cc +9 -4
  62. data/src/core/lib/iomgr/lockfree_event.cc +5 -1
  63. data/src/core/lib/iomgr/port.h +15 -2
  64. data/src/core/lib/iomgr/resolve_address_posix.cc +3 -2
  65. data/src/core/lib/iomgr/resolve_address_windows.cc +3 -2
  66. data/src/core/lib/iomgr/resource_quota.cc +78 -0
  67. data/src/core/lib/iomgr/resource_quota.h +16 -0
  68. data/src/core/lib/iomgr/socket_mutator.cc +1 -1
  69. data/src/core/lib/iomgr/socket_mutator.h +1 -1
  70. data/src/core/lib/iomgr/socket_windows.cc +33 -0
  71. data/src/core/lib/iomgr/socket_windows.h +6 -0
  72. data/src/core/lib/iomgr/tcp_windows.cc +2 -2
  73. data/src/core/lib/iomgr/tcp_windows.h +2 -0
  74. data/src/core/lib/iomgr/timer.h +3 -2
  75. data/src/core/lib/json/json.cc +2 -1
  76. data/src/core/lib/security/credentials/jwt/json_token.h +2 -0
  77. data/src/core/lib/security/credentials/jwt/jwt_verifier.cc +2 -0
  78. data/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc +1 -1
  79. data/src/core/lib/security/security_connector/load_system_roots.h +29 -0
  80. data/src/core/lib/security/security_connector/load_system_roots_fallback.cc +32 -0
  81. data/src/core/lib/security/security_connector/load_system_roots_linux.cc +165 -0
  82. data/src/core/lib/security/security_connector/load_system_roots_linux.h +44 -0
  83. data/src/core/lib/security/security_connector/security_connector.cc +23 -4
  84. data/src/core/lib/security/transport/client_auth_filter.cc +0 -4
  85. data/src/core/lib/security/transport/server_auth_filter.cc +0 -2
  86. data/src/core/lib/surface/call.cc +7 -3
  87. data/src/core/lib/surface/channel.cc +18 -2
  88. data/src/core/lib/surface/completion_queue.cc +152 -15
  89. data/src/core/lib/surface/completion_queue.h +20 -1
  90. data/src/core/lib/surface/completion_queue_factory.cc +13 -4
  91. data/src/core/lib/surface/init.cc +2 -2
  92. data/src/core/lib/surface/init.h +0 -1
  93. data/src/core/lib/surface/version.cc +2 -2
  94. data/src/core/lib/transport/service_config.cc +2 -2
  95. data/src/core/lib/transport/service_config.h +3 -3
  96. data/src/core/lib/transport/transport.h +2 -0
  97. data/src/core/tsi/alts/crypt/aes_gcm.cc +2 -0
  98. data/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc +8 -0
  99. data/src/core/tsi/grpc_shadow_boringssl.h +3006 -0
  100. data/src/core/tsi/ssl/session_cache/ssl_session.h +2 -0
  101. data/src/core/tsi/ssl/session_cache/ssl_session_cache.cc +5 -5
  102. data/src/core/tsi/ssl/session_cache/ssl_session_cache.h +2 -0
  103. data/src/core/tsi/ssl_transport_security.cc +5 -3
  104. data/src/core/tsi/ssl_types.h +2 -0
  105. data/src/ruby/ext/grpc/extconf.rb +1 -26
  106. data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +12 -0
  107. data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +18 -0
  108. data/src/ruby/lib/grpc/version.rb +1 -1
  109. data/src/ruby/spec/generic/client_stub_spec.rb +3 -3
  110. data/third_party/address_sorting/address_sorting.c +7 -2
  111. data/third_party/address_sorting/address_sorting_windows.c +43 -3
  112. data/third_party/address_sorting/include/address_sorting/address_sorting.h +3 -0
  113. metadata +40 -31
@@ -27,6 +27,7 @@
27
27
  #include "src/core/ext/filters/client_channel/subchannel.h"
28
28
  #include "src/core/ext/filters/client_channel/subchannel_index.h"
29
29
  #include "src/core/lib/channel/channel_args.h"
30
+ #include "src/core/lib/gprpp/mutex_lock.h"
30
31
  #include "src/core/lib/iomgr/combiner.h"
31
32
  #include "src/core/lib/iomgr/sockaddr_utils.h"
32
33
  #include "src/core/lib/transport/connectivity_state.h"
@@ -46,7 +47,7 @@ class PickFirst : public LoadBalancingPolicy {
46
47
  explicit PickFirst(const Args& args);
47
48
 
48
49
  void UpdateLocked(const grpc_channel_args& args) override;
49
- bool PickLocked(PickState* pick) override;
50
+ bool PickLocked(PickState* pick, grpc_error** error) override;
50
51
  void CancelPickLocked(PickState* pick, grpc_error* error) override;
51
52
  void CancelMatchingPicksLocked(uint32_t initial_metadata_flags_mask,
52
53
  uint32_t initial_metadata_flags_eq,
@@ -56,10 +57,10 @@ class PickFirst : public LoadBalancingPolicy {
56
57
  grpc_connectivity_state CheckConnectivityLocked(
57
58
  grpc_error** connectivity_error) override;
58
59
  void HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) override;
59
- void PingOneLocked(grpc_closure* on_initiate, grpc_closure* on_ack) override;
60
60
  void ExitIdleLocked() override;
61
+ void ResetBackoffLocked() override;
61
62
  void FillChildRefsForChannelz(ChildRefsList* child_subchannels,
62
- ChildRefsList* child_channels) override;
63
+ ChildRefsList* ignored) override;
63
64
 
64
65
  private:
65
66
  ~PickFirst();
@@ -80,6 +81,11 @@ class PickFirst : public LoadBalancingPolicy {
80
81
 
81
82
  void ProcessConnectivityChangeLocked(
82
83
  grpc_connectivity_state connectivity_state, grpc_error* error) override;
84
+
85
+ // Processes the connectivity change to READY for an unselected subchannel.
86
+ void ProcessUnselectedReadyLocked();
87
+
88
+ void CheckConnectivityStateAndStartWatchingLocked();
83
89
  };
84
90
 
85
91
  class PickFirstSubchannelList
@@ -173,15 +179,16 @@ void PickFirst::HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) {
173
179
  PickState* pick;
174
180
  while ((pick = pending_picks_) != nullptr) {
175
181
  pending_picks_ = pick->next;
176
- if (new_policy->PickLocked(pick)) {
182
+ grpc_error* error = GRPC_ERROR_NONE;
183
+ if (new_policy->PickLocked(pick, &error)) {
177
184
  // Synchronous return, schedule closure.
178
- GRPC_CLOSURE_SCHED(pick->on_complete, GRPC_ERROR_NONE);
185
+ GRPC_CLOSURE_SCHED(pick->on_complete, error);
179
186
  }
180
187
  }
181
188
  }
182
189
 
183
190
  void PickFirst::ShutdownLocked() {
184
- AutoChildRefsUpdater(this);
191
+ AutoChildRefsUpdater guard(this);
185
192
  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel shutdown");
186
193
  if (grpc_lb_pick_first_trace.enabled()) {
187
194
  gpr_log(GPR_INFO, "Pick First %p Shutting down", this);
@@ -246,7 +253,8 @@ void PickFirst::StartPickingLocked() {
246
253
  if (subchannel_list_ != nullptr) {
247
254
  for (size_t i = 0; i < subchannel_list_->num_subchannels(); ++i) {
248
255
  if (subchannel_list_->subchannel(i)->subchannel() != nullptr) {
249
- subchannel_list_->subchannel(i)->StartConnectivityWatchLocked();
256
+ subchannel_list_->subchannel(i)
257
+ ->CheckConnectivityStateAndStartWatchingLocked();
250
258
  break;
251
259
  }
252
260
  }
@@ -259,18 +267,30 @@ void PickFirst::ExitIdleLocked() {
259
267
  }
260
268
  }
261
269
 
262
- bool PickFirst::PickLocked(PickState* pick) {
270
+ void PickFirst::ResetBackoffLocked() {
271
+ subchannel_list_->ResetBackoffLocked();
272
+ if (latest_pending_subchannel_list_ != nullptr) {
273
+ latest_pending_subchannel_list_->ResetBackoffLocked();
274
+ }
275
+ }
276
+
277
+ bool PickFirst::PickLocked(PickState* pick, grpc_error** error) {
263
278
  // If we have a selected subchannel already, return synchronously.
264
279
  if (selected_ != nullptr) {
265
280
  pick->connected_subchannel = selected_->connected_subchannel()->Ref();
266
281
  return true;
267
282
  }
268
283
  // No subchannel selected yet, so handle asynchronously.
269
- if (!started_picking_) {
270
- StartPickingLocked();
284
+ if (pick->on_complete == nullptr) {
285
+ *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
286
+ "No pick result available but synchronous result required.");
287
+ return true;
271
288
  }
272
289
  pick->next = pending_picks_;
273
290
  pending_picks_ = pick;
291
+ if (!started_picking_) {
292
+ StartPickingLocked();
293
+ }
274
294
  return false;
275
295
  }
276
296
 
@@ -293,20 +313,9 @@ void PickFirst::NotifyOnStateChangeLocked(grpc_connectivity_state* current,
293
313
  notify);
294
314
  }
295
315
 
296
- void PickFirst::PingOneLocked(grpc_closure* on_initiate, grpc_closure* on_ack) {
297
- if (selected_ != nullptr) {
298
- selected_->connected_subchannel()->Ping(on_initiate, on_ack);
299
- } else {
300
- GRPC_CLOSURE_SCHED(on_initiate,
301
- GRPC_ERROR_CREATE_FROM_STATIC_STRING("Not connected"));
302
- GRPC_CLOSURE_SCHED(on_ack,
303
- GRPC_ERROR_CREATE_FROM_STATIC_STRING("Not connected"));
304
- }
305
- }
306
-
307
316
  void PickFirst::FillChildRefsForChannelz(
308
317
  ChildRefsList* child_subchannels_to_fill, ChildRefsList* ignored) {
309
- mu_guard guard(&child_refs_mu_);
318
+ MutexLock lock(&child_refs_mu_);
310
319
  for (size_t i = 0; i < child_subchannels_.size(); ++i) {
311
320
  // TODO(ncteisen): implement a de dup loop that is not O(n^2). Might
312
321
  // have to implement lightweight set. For now, we don't care about
@@ -327,33 +336,13 @@ void PickFirst::FillChildRefsForChannelz(
327
336
  void PickFirst::UpdateChildRefsLocked() {
328
337
  ChildRefsList cs;
329
338
  if (subchannel_list_ != nullptr) {
330
- for (size_t i = 0; i < subchannel_list_->num_subchannels(); ++i) {
331
- if (subchannel_list_->subchannel(i)->subchannel() != nullptr) {
332
- grpc_core::channelz::SubchannelNode* subchannel_node =
333
- grpc_subchannel_get_channelz_node(
334
- subchannel_list_->subchannel(i)->subchannel());
335
- if (subchannel_node != nullptr) {
336
- cs.push_back(subchannel_node->subchannel_uuid());
337
- }
338
- }
339
- }
339
+ subchannel_list_->PopulateChildRefsList(&cs);
340
340
  }
341
341
  if (latest_pending_subchannel_list_ != nullptr) {
342
- for (size_t i = 0; i < latest_pending_subchannel_list_->num_subchannels();
343
- ++i) {
344
- if (latest_pending_subchannel_list_->subchannel(i)->subchannel() !=
345
- nullptr) {
346
- grpc_core::channelz::SubchannelNode* subchannel_node =
347
- grpc_subchannel_get_channelz_node(
348
- latest_pending_subchannel_list_->subchannel(i)->subchannel());
349
- if (subchannel_node != nullptr) {
350
- cs.push_back(subchannel_node->subchannel_uuid());
351
- }
352
- }
353
- }
342
+ latest_pending_subchannel_list_->PopulateChildRefsList(&cs);
354
343
  }
355
344
  // atomically update the data that channelz will actually be looking at.
356
- mu_guard guard(&child_refs_mu_);
345
+ MutexLock lock(&child_refs_mu_);
357
346
  child_subchannels_ = std::move(cs);
358
347
  }
359
348
 
@@ -404,7 +393,8 @@ void PickFirst::UpdateLocked(const grpc_channel_args& args) {
404
393
  // If we've started picking, start trying to connect to the first
405
394
  // subchannel in the new list.
406
395
  if (started_picking_) {
407
- subchannel_list_->subchannel(0)->StartConnectivityWatchLocked();
396
+ subchannel_list_->subchannel(0)
397
+ ->CheckConnectivityStateAndStartWatchingLocked();
408
398
  }
409
399
  } else {
410
400
  // We do have a selected subchannel.
@@ -458,7 +448,7 @@ void PickFirst::UpdateLocked(const grpc_channel_args& args) {
458
448
  // subchannel in the new list.
459
449
  if (started_picking_) {
460
450
  latest_pending_subchannel_list_->subchannel(0)
461
- ->StartConnectivityWatchLocked();
451
+ ->CheckConnectivityStateAndStartWatchingLocked();
462
452
  }
463
453
  }
464
454
  }
@@ -471,6 +461,7 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
471
461
  // latest pending subchannel lists.
472
462
  GPR_ASSERT(subchannel_list() == p->subchannel_list_.get() ||
473
463
  subchannel_list() == p->latest_pending_subchannel_list_.get());
464
+ GPR_ASSERT(connectivity_state != GRPC_CHANNEL_SHUTDOWN);
474
465
  // Handle updates for the currently selected subchannel.
475
466
  if (p->selected_ == this) {
476
467
  if (grpc_lb_pick_first_trace.enabled()) {
@@ -500,14 +491,12 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
500
491
  "update"),
501
492
  "selected_not_ready+switch_to_update");
502
493
  } else {
503
- // TODO(juanlishen): we re-resolve when the selected subchannel goes to
504
- // TRANSIENT_FAILURE because we used to shut down in this case before
505
- // re-resolution is introduced. But we need to investigate whether we
506
- // really want to take any action instead of waiting for the selected
507
- // subchannel reconnecting.
508
- GPR_ASSERT(connectivity_state != GRPC_CHANNEL_SHUTDOWN);
509
494
  if (connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
510
- // If the selected channel goes bad, request a re-resolution.
495
+ // If the selected subchannel goes bad, request a re-resolution. We also
496
+ // set the channel state to IDLE and reset started_picking_. The reason
497
+ // is that if the new state is TRANSIENT_FAILURE due to a GOAWAY
498
+ // reception we don't want to connect to the re-resolved backends until
499
+ // we leave the IDLE state.
511
500
  grpc_connectivity_state_set(&p->state_tracker_, GRPC_CHANNEL_IDLE,
512
501
  GRPC_ERROR_NONE,
513
502
  "selected_changed+reresolve");
@@ -538,41 +527,7 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
538
527
  // select in place of the current one.
539
528
  switch (connectivity_state) {
540
529
  case GRPC_CHANNEL_READY: {
541
- // Case 2. Promote p->latest_pending_subchannel_list_ to
542
- // p->subchannel_list_.
543
- if (subchannel_list() == p->latest_pending_subchannel_list_.get()) {
544
- if (grpc_lb_pick_first_trace.enabled()) {
545
- gpr_log(GPR_INFO,
546
- "Pick First %p promoting pending subchannel list %p to "
547
- "replace %p",
548
- p, p->latest_pending_subchannel_list_.get(),
549
- p->subchannel_list_.get());
550
- }
551
- p->subchannel_list_ = std::move(p->latest_pending_subchannel_list_);
552
- }
553
- // Cases 1 and 2.
554
- grpc_connectivity_state_set(&p->state_tracker_, GRPC_CHANNEL_READY,
555
- GRPC_ERROR_NONE, "connecting_ready");
556
- p->selected_ = this;
557
- if (grpc_lb_pick_first_trace.enabled()) {
558
- gpr_log(GPR_INFO, "Pick First %p selected subchannel %p", p,
559
- subchannel());
560
- }
561
- // Drop all other subchannels, since we are now connected.
562
- p->DestroyUnselectedSubchannelsLocked();
563
- // Update any calls that were waiting for a pick.
564
- PickState* pick;
565
- while ((pick = p->pending_picks_)) {
566
- p->pending_picks_ = pick->next;
567
- pick->connected_subchannel =
568
- p->selected_->connected_subchannel()->Ref();
569
- if (grpc_lb_pick_first_trace.enabled()) {
570
- gpr_log(GPR_INFO,
571
- "Servicing pending pick with selected subchannel %p",
572
- p->selected_->subchannel());
573
- }
574
- GRPC_CLOSURE_SCHED(pick->on_complete, GRPC_ERROR_NONE);
575
- }
530
+ ProcessUnselectedReadyLocked();
576
531
  // Renew notification.
577
532
  RenewConnectivityWatchLocked();
578
533
  break;
@@ -588,11 +543,12 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
588
543
  // Case 1: Only set state to TRANSIENT_FAILURE if we've tried
589
544
  // all subchannels.
590
545
  if (sd->Index() == 0 && subchannel_list() == p->subchannel_list_.get()) {
546
+ p->TryReresolutionLocked(&grpc_lb_pick_first_trace, GRPC_ERROR_NONE);
591
547
  grpc_connectivity_state_set(
592
548
  &p->state_tracker_, GRPC_CHANNEL_TRANSIENT_FAILURE,
593
- GRPC_ERROR_REF(error), "connecting_transient_failure");
549
+ GRPC_ERROR_REF(error), "exhausted_subchannels");
594
550
  }
595
- sd->StartConnectivityWatchLocked();
551
+ sd->CheckConnectivityStateAndStartWatchingLocked();
596
552
  break;
597
553
  }
598
554
  case GRPC_CHANNEL_CONNECTING:
@@ -613,6 +569,67 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
613
569
  GRPC_ERROR_UNREF(error);
614
570
  }
615
571
 
572
+ void PickFirst::PickFirstSubchannelData::ProcessUnselectedReadyLocked() {
573
+ PickFirst* p = static_cast<PickFirst*>(subchannel_list()->policy());
574
+ // If we get here, there are two possible cases:
575
+ // 1. We do not currently have a selected subchannel, and the update is
576
+ // for a subchannel in p->subchannel_list_ that we're trying to
577
+ // connect to. The goal here is to find a subchannel that we can
578
+ // select.
579
+ // 2. We do currently have a selected subchannel, and the update is
580
+ // for a subchannel in p->latest_pending_subchannel_list_. The
581
+ // goal here is to find a subchannel from the update that we can
582
+ // select in place of the current one.
583
+ GPR_ASSERT(subchannel_list() == p->subchannel_list_.get() ||
584
+ subchannel_list() == p->latest_pending_subchannel_list_.get());
585
+ // Case 2. Promote p->latest_pending_subchannel_list_ to p->subchannel_list_.
586
+ if (subchannel_list() == p->latest_pending_subchannel_list_.get()) {
587
+ if (grpc_lb_pick_first_trace.enabled()) {
588
+ gpr_log(GPR_INFO,
589
+ "Pick First %p promoting pending subchannel list %p to "
590
+ "replace %p",
591
+ p, p->latest_pending_subchannel_list_.get(),
592
+ p->subchannel_list_.get());
593
+ }
594
+ p->subchannel_list_ = std::move(p->latest_pending_subchannel_list_);
595
+ }
596
+ // Cases 1 and 2.
597
+ grpc_connectivity_state_set(&p->state_tracker_, GRPC_CHANNEL_READY,
598
+ GRPC_ERROR_NONE, "subchannel_ready");
599
+ p->selected_ = this;
600
+ if (grpc_lb_pick_first_trace.enabled()) {
601
+ gpr_log(GPR_INFO, "Pick First %p selected subchannel %p", p, subchannel());
602
+ }
603
+ // Drop all other subchannels, since we are now connected.
604
+ p->DestroyUnselectedSubchannelsLocked();
605
+ // Update any calls that were waiting for a pick.
606
+ PickState* pick;
607
+ while ((pick = p->pending_picks_)) {
608
+ p->pending_picks_ = pick->next;
609
+ pick->connected_subchannel = p->selected_->connected_subchannel()->Ref();
610
+ if (grpc_lb_pick_first_trace.enabled()) {
611
+ gpr_log(GPR_INFO, "Servicing pending pick with selected subchannel %p",
612
+ p->selected_->subchannel());
613
+ }
614
+ GRPC_CLOSURE_SCHED(pick->on_complete, GRPC_ERROR_NONE);
615
+ }
616
+ }
617
+
618
+ void PickFirst::PickFirstSubchannelData::
619
+ CheckConnectivityStateAndStartWatchingLocked() {
620
+ PickFirst* p = static_cast<PickFirst*>(subchannel_list()->policy());
621
+ grpc_error* error = GRPC_ERROR_NONE;
622
+ if (p->selected_ != this &&
623
+ CheckConnectivityStateLocked(&error) == GRPC_CHANNEL_READY) {
624
+ // We must process the READY subchannel before we start watching it.
625
+ // Otherwise, we won't know it's READY because we will be waiting for its
626
+ // connectivity state to change from READY.
627
+ ProcessUnselectedReadyLocked();
628
+ }
629
+ GRPC_ERROR_UNREF(error);
630
+ StartConnectivityWatchLocked();
631
+ }
632
+
616
633
  //
617
634
  // factory
618
635
  //
@@ -36,6 +36,7 @@
36
36
  #include "src/core/ext/filters/client_channel/subchannel_index.h"
37
37
  #include "src/core/lib/channel/channel_args.h"
38
38
  #include "src/core/lib/debug/trace.h"
39
+ #include "src/core/lib/gprpp/mutex_lock.h"
39
40
  #include "src/core/lib/gprpp/ref_counted_ptr.h"
40
41
  #include "src/core/lib/iomgr/combiner.h"
41
42
  #include "src/core/lib/iomgr/sockaddr_utils.h"
@@ -57,7 +58,7 @@ class RoundRobin : public LoadBalancingPolicy {
57
58
  explicit RoundRobin(const Args& args);
58
59
 
59
60
  void UpdateLocked(const grpc_channel_args& args) override;
60
- bool PickLocked(PickState* pick) override;
61
+ bool PickLocked(PickState* pick, grpc_error** error) override;
61
62
  void CancelPickLocked(PickState* pick, grpc_error* error) override;
62
63
  void CancelMatchingPicksLocked(uint32_t initial_metadata_flags_mask,
63
64
  uint32_t initial_metadata_flags_eq,
@@ -67,11 +68,10 @@ class RoundRobin : public LoadBalancingPolicy {
67
68
  grpc_connectivity_state CheckConnectivityLocked(
68
69
  grpc_error** connectivity_error) override;
69
70
  void HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) override;
70
- void PingOneLocked(grpc_closure* on_initiate, grpc_closure* on_ack) override;
71
71
  void ExitIdleLocked() override;
72
- // TODO(ncteisen): implement this in a follow up PR
72
+ void ResetBackoffLocked() override;
73
73
  void FillChildRefsForChannelz(ChildRefsList* child_subchannels,
74
- ChildRefsList* child_channels) override {}
74
+ ChildRefsList* ignored) override;
75
75
 
76
76
  private:
77
77
  ~RoundRobin();
@@ -139,7 +139,8 @@ class RoundRobin : public LoadBalancingPolicy {
139
139
  grpc_client_channel_factory* client_channel_factory,
140
140
  const grpc_channel_args& args)
141
141
  : SubchannelList(policy, tracer, addresses, combiner,
142
- client_channel_factory, args) {
142
+ client_channel_factory, args),
143
+ last_ready_index_(num_subchannels() - 1) {
143
144
  // Need to maintain a ref to the LB policy as long as we maintain
144
145
  // any references to subchannels, since the subchannels'
145
146
  // pollset_sets will include the LB policy's pollset_set.
@@ -180,7 +181,19 @@ class RoundRobin : public LoadBalancingPolicy {
180
181
  size_t num_connecting_ = 0;
181
182
  size_t num_transient_failure_ = 0;
182
183
  grpc_error* last_transient_failure_error_ = GRPC_ERROR_NONE;
183
- size_t last_ready_index_ = -1; // Index into list of last pick.
184
+ size_t last_ready_index_; // Index into list of last pick.
185
+ };
186
+
187
+ // Helper class to ensure that any function that modifies the child refs
188
+ // data structures will update the channelz snapshot data structures before
189
+ // returning.
190
+ class AutoChildRefsUpdater {
191
+ public:
192
+ explicit AutoChildRefsUpdater(RoundRobin* rr) : rr_(rr) {}
193
+ ~AutoChildRefsUpdater() { rr_->UpdateChildRefsLocked(); }
194
+
195
+ private:
196
+ RoundRobin* rr_;
184
197
  };
185
198
 
186
199
  void ShutdownLocked() override;
@@ -188,6 +201,7 @@ class RoundRobin : public LoadBalancingPolicy {
188
201
  void StartPickingLocked();
189
202
  bool DoPickLocked(PickState* pick);
190
203
  void DrainPendingPicksLocked();
204
+ void UpdateChildRefsLocked();
191
205
 
192
206
  /** list of subchannels */
193
207
  OrphanablePtr<RoundRobinSubchannelList> subchannel_list_;
@@ -205,10 +219,16 @@ class RoundRobin : public LoadBalancingPolicy {
205
219
  PickState* pending_picks_ = nullptr;
206
220
  /** our connectivity state tracker */
207
221
  grpc_connectivity_state_tracker state_tracker_;
222
+ /// Lock and data used to capture snapshots of this channel's child
223
+ /// channels and subchannels. This data is consumed by channelz.
224
+ gpr_mu child_refs_mu_;
225
+ ChildRefsList child_subchannels_;
226
+ ChildRefsList child_channels_;
208
227
  };
209
228
 
210
229
  RoundRobin::RoundRobin(const Args& args) : LoadBalancingPolicy(args) {
211
230
  GPR_ASSERT(args.client_channel_factory != nullptr);
231
+ gpr_mu_init(&child_refs_mu_);
212
232
  grpc_connectivity_state_init(&state_tracker_, GRPC_CHANNEL_IDLE,
213
233
  "round_robin");
214
234
  UpdateLocked(*args.args);
@@ -223,6 +243,7 @@ RoundRobin::~RoundRobin() {
223
243
  if (grpc_lb_round_robin_trace.enabled()) {
224
244
  gpr_log(GPR_INFO, "[RR %p] Destroying Round Robin policy", this);
225
245
  }
246
+ gpr_mu_destroy(&child_refs_mu_);
226
247
  GPR_ASSERT(subchannel_list_ == nullptr);
227
248
  GPR_ASSERT(latest_pending_subchannel_list_ == nullptr);
228
249
  GPR_ASSERT(pending_picks_ == nullptr);
@@ -234,14 +255,16 @@ void RoundRobin::HandOffPendingPicksLocked(LoadBalancingPolicy* new_policy) {
234
255
  PickState* pick;
235
256
  while ((pick = pending_picks_) != nullptr) {
236
257
  pending_picks_ = pick->next;
237
- if (new_policy->PickLocked(pick)) {
258
+ grpc_error* error = GRPC_ERROR_NONE;
259
+ if (new_policy->PickLocked(pick, &error)) {
238
260
  // Synchronous return, schedule closure.
239
- GRPC_CLOSURE_SCHED(pick->on_complete, GRPC_ERROR_NONE);
261
+ GRPC_CLOSURE_SCHED(pick->on_complete, error);
240
262
  }
241
263
  }
242
264
  }
243
265
 
244
266
  void RoundRobin::ShutdownLocked() {
267
+ AutoChildRefsUpdater guard(this);
245
268
  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel shutdown");
246
269
  if (grpc_lb_round_robin_trace.enabled()) {
247
270
  gpr_log(GPR_INFO, "[RR %p] Shutting down", this);
@@ -313,6 +336,13 @@ void RoundRobin::ExitIdleLocked() {
313
336
  }
314
337
  }
315
338
 
339
+ void RoundRobin::ResetBackoffLocked() {
340
+ subchannel_list_->ResetBackoffLocked();
341
+ if (latest_pending_subchannel_list_ != nullptr) {
342
+ latest_pending_subchannel_list_->ResetBackoffLocked();
343
+ }
344
+ }
345
+
316
346
  bool RoundRobin::DoPickLocked(PickState* pick) {
317
347
  const size_t next_ready_index =
318
348
  subchannel_list_->GetNextReadySubchannelIndexLocked();
@@ -348,7 +378,7 @@ void RoundRobin::DrainPendingPicksLocked() {
348
378
  }
349
379
  }
350
380
 
351
- bool RoundRobin::PickLocked(PickState* pick) {
381
+ bool RoundRobin::PickLocked(PickState* pick, grpc_error** error) {
352
382
  if (grpc_lb_round_robin_trace.enabled()) {
353
383
  gpr_log(GPR_INFO, "[RR %p] Trying to pick (shutdown: %d)", this, shutdown_);
354
384
  }
@@ -356,6 +386,11 @@ bool RoundRobin::PickLocked(PickState* pick) {
356
386
  if (subchannel_list_ != nullptr) {
357
387
  if (DoPickLocked(pick)) return true;
358
388
  }
389
+ if (pick->on_complete == nullptr) {
390
+ *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
391
+ "No pick result available but synchronous result required.");
392
+ return true;
393
+ }
359
394
  /* no pick currently available. Save for later in list of pending picks */
360
395
  pick->next = pending_picks_;
361
396
  pending_picks_ = pick;
@@ -365,6 +400,39 @@ bool RoundRobin::PickLocked(PickState* pick) {
365
400
  return false;
366
401
  }
367
402
 
403
+ void RoundRobin::FillChildRefsForChannelz(
404
+ ChildRefsList* child_subchannels_to_fill, ChildRefsList* ignored) {
405
+ MutexLock lock(&child_refs_mu_);
406
+ for (size_t i = 0; i < child_subchannels_.size(); ++i) {
407
+ // TODO(ncteisen): implement a de dup loop that is not O(n^2). Might
408
+ // have to implement lightweight set. For now, we don't care about
409
+ // performance when channelz requests are made.
410
+ bool found = false;
411
+ for (size_t j = 0; j < child_subchannels_to_fill->size(); ++j) {
412
+ if ((*child_subchannels_to_fill)[j] == child_subchannels_[i]) {
413
+ found = true;
414
+ break;
415
+ }
416
+ }
417
+ if (!found) {
418
+ child_subchannels_to_fill->push_back(child_subchannels_[i]);
419
+ }
420
+ }
421
+ }
422
+
423
+ void RoundRobin::UpdateChildRefsLocked() {
424
+ ChildRefsList cs;
425
+ if (subchannel_list_ != nullptr) {
426
+ subchannel_list_->PopulateChildRefsList(&cs);
427
+ }
428
+ if (latest_pending_subchannel_list_ != nullptr) {
429
+ latest_pending_subchannel_list_->PopulateChildRefsList(&cs);
430
+ }
431
+ // atomically update the data that channelz will actually be looking at.
432
+ MutexLock lock(&child_refs_mu_);
433
+ child_subchannels_ = std::move(cs);
434
+ }
435
+
368
436
  void RoundRobin::RoundRobinSubchannelList::StartWatchingLocked() {
369
437
  if (num_subchannels() == 0) return;
370
438
  // Check current state of each subchannel synchronously, since any
@@ -455,6 +523,7 @@ void RoundRobin::RoundRobinSubchannelList::
455
523
  void RoundRobin::RoundRobinSubchannelList::
456
524
  UpdateRoundRobinStateFromSubchannelStateCountsLocked() {
457
525
  RoundRobin* p = static_cast<RoundRobin*>(policy());
526
+ AutoChildRefsUpdater guard(p);
458
527
  if (num_ready_ > 0) {
459
528
  if (p->subchannel_list_.get() != this) {
460
529
  // Promote this list to p->subchannel_list_.
@@ -593,24 +662,9 @@ void RoundRobin::NotifyOnStateChangeLocked(grpc_connectivity_state* current,
593
662
  notify);
594
663
  }
595
664
 
596
- void RoundRobin::PingOneLocked(grpc_closure* on_initiate,
597
- grpc_closure* on_ack) {
598
- const size_t next_ready_index =
599
- subchannel_list_->GetNextReadySubchannelIndexLocked();
600
- if (next_ready_index < subchannel_list_->num_subchannels()) {
601
- RoundRobinSubchannelData* selected =
602
- subchannel_list_->subchannel(next_ready_index);
603
- selected->connected_subchannel()->Ping(on_initiate, on_ack);
604
- } else {
605
- GRPC_CLOSURE_SCHED(on_initiate, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
606
- "Round Robin not connected"));
607
- GRPC_CLOSURE_SCHED(on_ack, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
608
- "Round Robin not connected"));
609
- }
610
- }
611
-
612
665
  void RoundRobin::UpdateLocked(const grpc_channel_args& args) {
613
666
  const grpc_arg* arg = grpc_channel_args_find(&args, GRPC_ARG_LB_ADDRESSES);
667
+ AutoChildRefsUpdater guard(this);
614
668
  if (GPR_UNLIKELY(arg == nullptr || arg->type != GRPC_ARG_POINTER)) {
615
669
  gpr_log(GPR_ERROR, "[RR %p] update provided no addresses; ignoring", this);
616
670
  // If we don't have a current subchannel list, go into TRANSIENT_FAILURE.