outlier_detection.cc
Go to the documentation of this file.
1 //
2 // Copyright 2022 gRPC authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
18 
20 
21 #include <stddef.h>
22 
23 #include <algorithm>
24 #include <atomic>
25 #include <cmath>
26 #include <cstdint>
27 #include <map>
28 #include <memory>
29 #include <set>
30 #include <string>
31 #include <utility>
32 #include <vector>
33 
34 #include "absl/memory/memory.h"
35 #include "absl/random/random.h"
36 #include "absl/status/status.h"
37 #include "absl/status/statusor.h"
38 #include "absl/strings/string_view.h"
39 #include "absl/types/variant.h"
40 
43 #include <grpc/support/alloc.h>
44 #include <grpc/support/log.h>
45 
54 #include "src/core/lib/gpr/env.h"
67 #include "src/core/lib/json/json.h"
71 
72 namespace grpc_core {
73 
74 TraceFlag grpc_outlier_detection_lb_trace(false, "outlier_detection_lb");
75 
76 // TODO(donnadionne): Remove once outlier detection is no longer experimental
78  char* value = gpr_getenv("GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION");
79  bool parsed_value;
80  bool parse_succeeded = gpr_parse_bool_value(value, &parsed_value);
81  gpr_free(value);
82  return parse_succeeded && parsed_value;
83 }
84 
85 namespace {
86 
87 constexpr char kOutlierDetection[] = "outlier_detection_experimental";
88 
89 // Config for xDS Cluster Impl LB policy.
90 class OutlierDetectionLbConfig : public LoadBalancingPolicy::Config {
91  public:
92  OutlierDetectionLbConfig(
93  OutlierDetectionConfig outlier_detection_config,
94  RefCountedPtr<LoadBalancingPolicy::Config> child_policy)
95  : outlier_detection_config_(outlier_detection_config),
96  child_policy_(std::move(child_policy)) {}
97 
98  const char* name() const override { return kOutlierDetection; }
99 
100  bool CountingEnabled() const {
101  return (
103  (outlier_detection_config_.success_rate_ejection.has_value() ||
104  outlier_detection_config_.failure_percentage_ejection.has_value()));
105  }
106 
107  const OutlierDetectionConfig& outlier_detection_config() const {
109  }
110 
111  RefCountedPtr<LoadBalancingPolicy::Config> child_policy() const {
112  return child_policy_;
113  }
114 
115  private:
116  OutlierDetectionConfig outlier_detection_config_;
117  RefCountedPtr<LoadBalancingPolicy::Config> child_policy_;
118 };
119 
120 // xDS Cluster Impl LB policy.
121 class OutlierDetectionLb : public LoadBalancingPolicy {
122  public:
123  explicit OutlierDetectionLb(Args args);
124 
125  const char* name() const override { return kOutlierDetection; }
126 
127  void UpdateLocked(UpdateArgs args) override;
128  void ExitIdleLocked() override;
129  void ResetBackoffLocked() override;
130 
131  private:
132  class SubchannelState;
133  class SubchannelWrapper : public DelegatingSubchannel {
134  public:
135  SubchannelWrapper(RefCountedPtr<SubchannelState> subchannel_state,
136  RefCountedPtr<SubchannelInterface> subchannel)
137  : DelegatingSubchannel(std::move(subchannel)),
138  subchannel_state_(std::move(subchannel_state)) {
139  if (subchannel_state_ != nullptr) {
140  subchannel_state_->AddSubchannel(this);
141  if (subchannel_state_->ejection_time().has_value()) {
142  ejected_ = true;
143  }
144  }
145  }
146 
147  ~SubchannelWrapper() override {
148  if (subchannel_state_ != nullptr) {
149  subchannel_state_->RemoveSubchannel(this);
150  }
151  }
152 
153  void Eject();
154 
155  void Uneject();
156 
157  void WatchConnectivityState(
158  std::unique_ptr<ConnectivityStateWatcherInterface> watcher) override;
159 
160  void CancelConnectivityStateWatch(
161  ConnectivityStateWatcherInterface* watcher) override;
162 
163  RefCountedPtr<SubchannelState> subchannel_state() const {
164  return subchannel_state_;
165  }
166 
167  private:
168  class WatcherWrapper
169  : public SubchannelInterface::ConnectivityStateWatcherInterface {
170  public:
171  WatcherWrapper(std::unique_ptr<
172  SubchannelInterface::ConnectivityStateWatcherInterface>
173  watcher,
174  bool ejected)
175  : watcher_(std::move(watcher)), ejected_(ejected) {}
176 
177  void Eject() {
178  ejected_ = true;
179  if (last_seen_state_.has_value()) {
180  watcher_->OnConnectivityStateChange(
183  "subchannel ejected by outlier detection"));
184  }
185  }
186 
187  void Uneject() {
188  ejected_ = false;
189  if (last_seen_state_.has_value()) {
190  watcher_->OnConnectivityStateChange(*last_seen_state_,
192  }
193  }
194 
195  void OnConnectivityStateChange(grpc_connectivity_state new_state,
196  absl::Status status) override {
197  const bool send_update = !last_seen_state_.has_value() || !ejected_;
198  last_seen_state_ = new_state;
200  if (send_update) {
201  if (ejected_) {
202  new_state = GRPC_CHANNEL_TRANSIENT_FAILURE;
204  "subchannel ejected by outlier detection");
205  }
206  watcher_->OnConnectivityStateChange(new_state, status);
207  }
208  }
209 
210  grpc_pollset_set* interested_parties() override {
211  return watcher_->interested_parties();
212  }
213 
214  private:
215  std::unique_ptr<SubchannelInterface::ConnectivityStateWatcherInterface>
219  bool ejected_;
220  };
221 
222  RefCountedPtr<SubchannelState> subchannel_state_;
223  bool ejected_ = false;
224  std::map<SubchannelInterface::ConnectivityStateWatcherInterface*,
225  WatcherWrapper*>
227  };
228 
229  class SubchannelState : public RefCounted<SubchannelState> {
230  public:
231  struct Bucket {
232  std::atomic<uint64_t> successes;
233  std::atomic<uint64_t> failures;
234  };
235 
236  void RotateBucket() {
237  backup_bucket_->successes = 0;
238  backup_bucket_->failures = 0;
240  active_bucket_.store(current_bucket_.get());
241  }
242 
243  absl::optional<std::pair<double, uint64_t>> GetSuccessRateAndVolume() {
244  uint64_t total_request =
245  backup_bucket_->successes + backup_bucket_->failures;
246  if (total_request == 0) {
247  return absl::nullopt;
248  }
249  double success_rate =
250  backup_bucket_->successes * 100.0 /
251  (backup_bucket_->successes + backup_bucket_->failures);
252  return {
253  {success_rate, backup_bucket_->successes + backup_bucket_->failures}};
254  }
255 
256  void AddSubchannel(SubchannelWrapper* wrapper) {
257  subchannels_.insert(wrapper);
258  }
259 
260  void RemoveSubchannel(SubchannelWrapper* wrapper) {
261  subchannels_.erase(wrapper);
262  }
263 
264  void AddSuccessCount() { active_bucket_.load()->successes.fetch_add(1); }
265 
266  void AddFailureCount() { active_bucket_.load()->failures.fetch_add(1); }
267 
268  absl::optional<Timestamp> ejection_time() const { return ejection_time_; }
269 
270  void Eject(const Timestamp& time) {
271  ejection_time_ = time;
272  ++multiplier_;
273  for (auto& subchannel : subchannels_) {
274  subchannel->Eject();
275  }
276  }
277 
278  void Uneject() {
279  ejection_time_.reset();
280  for (auto& subchannel : subchannels_) {
281  subchannel->Uneject();
282  }
283  }
284 
285  void MaybeUneject(uint64_t base_ejection_time_in_millis,
286  uint64_t max_ejection_time_in_millis) {
287  if (!ejection_time_.has_value()) {
288  if (multiplier_ > 0) {
289  --multiplier_;
290  }
291  } else {
292  GPR_ASSERT(ejection_time_.has_value());
293  auto change_time = ejection_time_.value() +
295  base_ejection_time_in_millis * multiplier_,
296  std::max(base_ejection_time_in_millis,
297  max_ejection_time_in_millis)));
298  if (change_time < ExecCtx::Get()->Now()) {
299  Uneject();
300  }
301  }
302  }
303 
304  private:
305  std::unique_ptr<Bucket> current_bucket_ = absl::make_unique<Bucket>();
306  std::unique_ptr<Bucket> backup_bucket_ = absl::make_unique<Bucket>();
307  // The bucket used to update call counts.
308  // Points to either current_bucket or active_bucket.
309  std::atomic<Bucket*> active_bucket_{current_bucket_.get()};
312  std::set<SubchannelWrapper*> subchannels_;
313  };
314 
315  // A simple wrapper for ref-counting a picker from the child policy.
316  class RefCountedPicker : public RefCounted<RefCountedPicker> {
317  public:
318  explicit RefCountedPicker(std::unique_ptr<SubchannelPicker> picker)
319  : picker_(std::move(picker)) {}
320  PickResult Pick(PickArgs args) { return picker_->Pick(args); }
321 
322  private:
323  std::unique_ptr<SubchannelPicker> picker_;
324  };
325 
326  // A picker that wraps the picker from the child to perform outlier detection.
327  class Picker : public SubchannelPicker {
328  public:
329  Picker(OutlierDetectionLb* outlier_detection_lb,
330  RefCountedPtr<RefCountedPicker> picker, bool counting_enabled);
331 
332  PickResult Pick(PickArgs args) override;
333 
334  private:
335  class SubchannelCallTracker;
336  RefCountedPtr<RefCountedPicker> picker_;
338  };
339 
340  class Helper : public ChannelControlHelper {
341  public:
342  explicit Helper(RefCountedPtr<OutlierDetectionLb> outlier_detection_policy)
343  : outlier_detection_policy_(std::move(outlier_detection_policy)) {}
344 
345  ~Helper() override {
346  outlier_detection_policy_.reset(DEBUG_LOCATION, "Helper");
347  }
348 
349  RefCountedPtr<SubchannelInterface> CreateSubchannel(
350  ServerAddress address, const grpc_channel_args& args) override;
351  void UpdateState(grpc_connectivity_state state, const absl::Status& status,
352  std::unique_ptr<SubchannelPicker> picker) override;
353  void RequestReresolution() override;
354  absl::string_view GetAuthority() override;
355  void AddTraceEvent(TraceSeverity severity,
356  absl::string_view message) override;
357 
358  private:
359  RefCountedPtr<OutlierDetectionLb> outlier_detection_policy_;
360  };
361 
362  class EjectionTimer : public InternallyRefCounted<EjectionTimer> {
363  public:
364  EjectionTimer(RefCountedPtr<OutlierDetectionLb> parent,
366 
367  void Orphan() override;
368 
369  Timestamp StartTime() const { return start_time_; }
370 
371  private:
372  static void OnTimer(void* arg, grpc_error_handle error);
373  void OnTimerLocked(grpc_error_handle);
374 
375  RefCountedPtr<OutlierDetectionLb> parent_;
378  bool timer_pending_ = true;
381  };
382 
383  ~OutlierDetectionLb() override;
384 
385  static std::string MakeKeyForAddress(const ServerAddress& address);
386 
387  void ShutdownLocked() override;
388 
389  OrphanablePtr<LoadBalancingPolicy> CreateChildPolicyLocked(
390  const grpc_channel_args* args);
391 
392  void MaybeUpdatePickerLocked();
393 
394  // Current config from the resolver.
395  RefCountedPtr<OutlierDetectionLbConfig> config_;
396 
397  // Internal state.
398  bool shutting_down_ = false;
399 
400  OrphanablePtr<LoadBalancingPolicy> child_policy_;
401 
402  // Latest state and picker reported by the child policy.
405  RefCountedPtr<RefCountedPicker> picker_;
406  std::map<std::string, RefCountedPtr<SubchannelState>> subchannel_state_map_;
407  OrphanablePtr<EjectionTimer> ejection_timer_;
408 };
409 
410 //
411 // OutlierDetectionLb::SubchannelWrapper
412 //
413 
414 void OutlierDetectionLb::SubchannelWrapper::Eject() {
415  ejected_ = true;
416  for (auto& watcher : watchers_) {
417  watcher.second->Eject();
418  }
419 }
420 
421 void OutlierDetectionLb::SubchannelWrapper::Uneject() {
422  ejected_ = false;
423  for (auto& watcher : watchers_) {
424  watcher.second->Uneject();
425  }
426 }
427 
428 void OutlierDetectionLb::SubchannelWrapper::WatchConnectivityState(
429  std::unique_ptr<ConnectivityStateWatcherInterface> watcher) {
430  ConnectivityStateWatcherInterface* watcher_ptr = watcher.get();
431  auto watcher_wrapper =
432  absl::make_unique<WatcherWrapper>(std::move(watcher), ejected_);
433  watchers_.emplace(watcher_ptr, watcher_wrapper.get());
434  wrapped_subchannel()->WatchConnectivityState(std::move(watcher_wrapper));
435 }
436 
437 void OutlierDetectionLb::SubchannelWrapper::CancelConnectivityStateWatch(
438  ConnectivityStateWatcherInterface* watcher) {
439  auto it = watchers_.find(watcher);
440  if (it == watchers_.end()) return;
441  wrapped_subchannel()->CancelConnectivityStateWatch(it->second);
442  watchers_.erase(it);
443 }
444 
445 //
446 // OutlierDetectionLb::Picker::SubchannelCallTracker
447 //
448 
449 class OutlierDetectionLb::Picker::SubchannelCallTracker
450  : public LoadBalancingPolicy::SubchannelCallTrackerInterface {
451  public:
452  SubchannelCallTracker(
453  std::unique_ptr<LoadBalancingPolicy::SubchannelCallTrackerInterface>
454  original_subchannel_call_tracker,
455  RefCountedPtr<SubchannelState> subchannel_state)
457  std::move(original_subchannel_call_tracker)),
458  subchannel_state_(std::move(subchannel_state)) {}
459 
460  ~SubchannelCallTracker() override {
461  subchannel_state_.reset(DEBUG_LOCATION, "SubchannelCallTracker");
462  }
463 
464  void Start() override {
465  // This tracker does not care about started calls only finished calls.
466  // Delegate if needed.
467  if (original_subchannel_call_tracker_ != nullptr) {
469  }
470  }
471 
472  void Finish(FinishArgs args) override {
473  // Delegate if needed.
474  if (original_subchannel_call_tracker_ != nullptr) {
476  }
477  // Record call completion based on status for outlier detection
478  // calculations.
479  if (subchannel_state_ != nullptr) {
480  if (args.status.ok()) {
481  subchannel_state_->AddSuccessCount();
482  } else {
483  subchannel_state_->AddFailureCount();
484  }
485  }
486  }
487 
488  private:
489  std::unique_ptr<LoadBalancingPolicy::SubchannelCallTrackerInterface>
491  RefCountedPtr<SubchannelState> subchannel_state_;
492 };
493 
494 //
495 // OutlierDetectionLb::Picker
496 //
497 
498 OutlierDetectionLb::Picker::Picker(OutlierDetectionLb* outlier_detection_lb,
499  RefCountedPtr<RefCountedPicker> picker,
500  bool counting_enabled)
501  : picker_(std::move(picker)), counting_enabled_(counting_enabled) {
504  "[outlier_detection_lb %p] constructed new picker %p and counting "
505  "is %s",
506  outlier_detection_lb, this,
507  (counting_enabled ? "enabled" : "disabled"));
508  }
509 }
510 
511 LoadBalancingPolicy::PickResult OutlierDetectionLb::Picker::Pick(
512  LoadBalancingPolicy::PickArgs args) {
513  if (picker_ == nullptr) { // Should never happen.
515  "outlier_detection picker not given any child picker"));
516  }
517  // Delegate to child picker
518  PickResult result = picker_->Pick(args);
519  auto* complete_pick = absl::get_if<PickResult::Complete>(&result.result);
520  if (complete_pick != nullptr) {
521  // Unwrap subchannel to pass back up the stack.
522  auto* subchannel_wrapper =
523  static_cast<SubchannelWrapper*>(complete_pick->subchannel.get());
524  // Inject subchannel call tracker to record call completion as long as
525  // not both success_rate_ejection and failure_percentage_ejection are unset.
526  if (counting_enabled_) {
527  complete_pick->subchannel_call_tracker =
528  absl::make_unique<SubchannelCallTracker>(
529  std::move(complete_pick->subchannel_call_tracker),
530  subchannel_wrapper->subchannel_state());
531  }
532  complete_pick->subchannel = subchannel_wrapper->wrapped_subchannel();
533  }
534  return result;
535 }
536 
537 //
538 // OutlierDetectionLb
539 //
540 
541 OutlierDetectionLb::OutlierDetectionLb(Args args)
542  : LoadBalancingPolicy(std::move(args)) {
544  gpr_log(GPR_INFO, "[outlier_detection_lb %p] created", this);
545  }
546 }
547 
548 OutlierDetectionLb::~OutlierDetectionLb() {
551  "[outlier_detection_lb %p] destroying outlier_detection LB policy",
552  this);
553  }
554 }
555 
556 std::string OutlierDetectionLb::MakeKeyForAddress(
557  const ServerAddress& address) {
558  // Use only the address, not the attributes.
559  auto addr_str = grpc_sockaddr_to_string(&address.address(), false);
560  return addr_str.ok() ? addr_str.value() : addr_str.status().ToString();
561 }
562 
563 void OutlierDetectionLb::ShutdownLocked() {
565  gpr_log(GPR_INFO, "[outlier_detection_lb %p] shutting down", this);
566  }
567  ejection_timer_.reset();
568  shutting_down_ = true;
569  // Remove the child policy's interested_parties pollset_set from the
570  // xDS policy.
571  if (child_policy_ != nullptr) {
572  grpc_pollset_set_del_pollset_set(child_policy_->interested_parties(),
573  interested_parties());
574  child_policy_.reset();
575  }
576  // Drop our ref to the child's picker, in case it's holding a ref to
577  // the child.
578  picker_.reset();
579 }
580 
582  if (child_policy_ != nullptr) child_policy_->ExitIdleLocked();
583 }
584 
585 void OutlierDetectionLb::ResetBackoffLocked() {
586  if (child_policy_ != nullptr) child_policy_->ResetBackoffLocked();
587 }
588 
589 void OutlierDetectionLb::UpdateLocked(UpdateArgs args) {
591  gpr_log(GPR_INFO, "[outlier_detection_lb %p] Received update", this);
592  }
593  auto old_config = std::move(config_);
594  // Update config.
595  config_ = std::move(args.config);
596  // Update outlier detection timer.
597  if (!config_->CountingEnabled()) {
598  // No need for timer. Cancel the current timer, if any.
599  ejection_timer_.reset();
600  } else if (ejection_timer_ == nullptr) {
601  // No timer running. Start it now.
603  MakeOrphanable<EjectionTimer>(Ref(), ExecCtx::Get()->Now());
604  for (const auto& p : subchannel_state_map_) {
605  p.second->RotateBucket(); // Reset call counters.
606  }
607  } else if (old_config->outlier_detection_config().interval !=
608  config_->outlier_detection_config().interval) {
609  // Timer interval changed. Cancel the current timer and start a new one
610  // with the same start time.
611  // Note that if the new deadline is in the past, the timer will fire
612  // immediately.
614  MakeOrphanable<EjectionTimer>(Ref(), ejection_timer_->StartTime());
615  }
616  // Create policy if needed.
617  if (child_policy_ == nullptr) {
618  child_policy_ = CreateChildPolicyLocked(args.args);
619  }
620  if (args.addresses.ok()) {
621  std::set<std::string> current_addresses;
622  for (const ServerAddress& address : *args.addresses) {
623  std::string address_key = MakeKeyForAddress(address);
624  auto& subchannel_state = subchannel_state_map_[address_key];
625  if (subchannel_state == nullptr) {
626  subchannel_state = MakeRefCounted<SubchannelState>();
627  }
628  current_addresses.emplace(address_key);
629  }
630  for (auto it = subchannel_state_map_.begin();
631  it != subchannel_state_map_.end();) {
632  if (current_addresses.find(it->first) == current_addresses.end()) {
633  // remove each map entry for a subchannel address not in the updated
634  // address list.
635  it = subchannel_state_map_.erase(it);
636  } else {
637  ++it;
638  }
639  }
640  }
641  // Construct update args.
642  UpdateArgs update_args;
643  update_args.addresses = std::move(args.addresses);
644  update_args.config = config_->child_policy();
645  update_args.args = grpc_channel_args_copy(args.args);
646  // Update the policy.
649  "[outlier_detection_lb %p] Updating child policy handler %p", this,
650  child_policy_.get());
651  }
652  child_policy_->UpdateLocked(std::move(update_args));
653 }
654 
655 void OutlierDetectionLb::MaybeUpdatePickerLocked() {
656  if (picker_ != nullptr) {
657  auto outlier_detection_picker =
658  absl::make_unique<Picker>(this, picker_, config_->CountingEnabled());
661  "[outlier_detection_lb %p] updating connectivity: state=%s "
662  "status=(%s) picker=%p",
663  this, ConnectivityStateName(state_), status_.ToString().c_str(),
664  outlier_detection_picker.get());
665  }
666  channel_control_helper()->UpdateState(state_, status_,
667  std::move(outlier_detection_picker));
668  }
669 }
670 
671 OrphanablePtr<LoadBalancingPolicy> OutlierDetectionLb::CreateChildPolicyLocked(
672  const grpc_channel_args* args) {
673  LoadBalancingPolicy::Args lb_policy_args;
674  lb_policy_args.work_serializer = work_serializer();
675  lb_policy_args.args = args;
676  lb_policy_args.channel_control_helper =
677  absl::make_unique<Helper>(Ref(DEBUG_LOCATION, "Helper"));
678  OrphanablePtr<LoadBalancingPolicy> lb_policy =
679  MakeOrphanable<ChildPolicyHandler>(std::move(lb_policy_args),
683  "[outlier_detection_lb %p] Created new child policy handler %p",
684  this, lb_policy.get());
685  }
686  // Add our interested_parties pollset_set to that of the newly created
687  // child policy. This will make the child policy progress upon activity on
688  // this policy, which in turn is tied to the application's call.
689  grpc_pollset_set_add_pollset_set(lb_policy->interested_parties(),
690  interested_parties());
691  return lb_policy;
692 }
693 
694 //
695 // OutlierDetectionLb::Helper
696 //
697 
698 RefCountedPtr<SubchannelInterface> OutlierDetectionLb::Helper::CreateSubchannel(
699  ServerAddress address, const grpc_channel_args& args) {
700  if (outlier_detection_policy_->shutting_down_) return nullptr;
701  std::string key = MakeKeyForAddress(address);
702  RefCountedPtr<SubchannelState> subchannel_state;
703  auto it = outlier_detection_policy_->subchannel_state_map_.find(key);
704  if (it != outlier_detection_policy_->subchannel_state_map_.end()) {
705  subchannel_state = it->second->Ref();
706  }
707  auto subchannel = MakeRefCounted<SubchannelWrapper>(
708  subchannel_state,
709  outlier_detection_policy_->channel_control_helper()->CreateSubchannel(
710  std::move(address), args));
711  if (subchannel_state != nullptr) {
712  subchannel_state->AddSubchannel(subchannel.get());
713  }
714  return subchannel;
715 }
716 
717 void OutlierDetectionLb::Helper::UpdateState(
719  std::unique_ptr<SubchannelPicker> picker) {
720  if (outlier_detection_policy_->shutting_down_) return;
723  "[outlier_detection_lb %p] child connectivity state update: "
724  "state=%s (%s) "
725  "picker=%p",
727  status.ToString().c_str(), picker.get());
728  }
729  // Save the state and picker.
732  outlier_detection_policy_->picker_ =
733  MakeRefCounted<RefCountedPicker>(std::move(picker));
734  // Wrap the picker and return it to the channel.
735  outlier_detection_policy_->MaybeUpdatePickerLocked();
736 }
737 
738 void OutlierDetectionLb::Helper::RequestReresolution() {
739  if (outlier_detection_policy_->shutting_down_) return;
740  outlier_detection_policy_->channel_control_helper()->RequestReresolution();
741 }
742 
743 absl::string_view OutlierDetectionLb::Helper::GetAuthority() {
744  return outlier_detection_policy_->channel_control_helper()->GetAuthority();
745 }
746 
747 void OutlierDetectionLb::Helper::AddTraceEvent(TraceSeverity severity,
749  if (outlier_detection_policy_->shutting_down_) return;
750  outlier_detection_policy_->channel_control_helper()->AddTraceEvent(severity,
751  message);
752 }
753 
754 //
755 // OutlierDetectionLb::EjectionTimer
756 //
757 
758 OutlierDetectionLb::EjectionTimer::EjectionTimer(
759  RefCountedPtr<OutlierDetectionLb> parent, Timestamp start_time)
760  : parent_(std::move(parent)), start_time_(start_time) {
761  GRPC_CLOSURE_INIT(&on_timer_, OnTimer, this, nullptr);
762  Ref().release();
764  &timer_,
765  start_time_ + parent_->config_->outlier_detection_config().interval,
766  &on_timer_);
767 }
768 
769 void OutlierDetectionLb::EjectionTimer::Orphan() {
770  if (timer_pending_) {
771  timer_pending_ = false;
773  }
774  Unref();
775 }
776 
777 void OutlierDetectionLb::EjectionTimer::OnTimer(void* arg,
779  auto* self = static_cast<EjectionTimer*>(arg);
780  (void)GRPC_ERROR_REF(error); // ref owned by lambda
781  self->parent_->work_serializer()->Run(
782  [self, error]() { self->OnTimerLocked(error); }, DEBUG_LOCATION);
783 }
784 
785 void OutlierDetectionLb::EjectionTimer::OnTimerLocked(grpc_error_handle error) {
787  std::map<SubchannelState*, double> success_rate_ejection_candidates;
788  std::map<SubchannelState*, double> failure_percentage_ejection_candidates;
789  size_t ejected_host_count = 0;
790  double success_rate_sum = 0;
791  auto time_now = ExecCtx::Get()->Now();
792  auto& config = parent_->config_->outlier_detection_config();
793  for (auto& state : parent_->subchannel_state_map_) {
794  auto* subchannel_state = state.second.get();
795  // For each address, swap the call counter's buckets in that address's
796  // map entry.
797  subchannel_state->RotateBucket();
798  // Gather data to run success rate algorithm or failure percentage
799  // algorithm.
800  if (subchannel_state->ejection_time().has_value()) {
801  ++ejected_host_count;
802  }
803  absl::optional<std::pair<double, uint64_t>> host_success_rate_and_volume =
804  subchannel_state->GetSuccessRateAndVolume();
805  if (!host_success_rate_and_volume.has_value()) {
806  continue;
807  }
808  double success_rate = host_success_rate_and_volume->first;
809  uint64_t request_volume = host_success_rate_and_volume->second;
810  if (config.success_rate_ejection.has_value()) {
811  if (request_volume >= config.success_rate_ejection->request_volume) {
812  success_rate_ejection_candidates[subchannel_state] = success_rate;
813  success_rate_sum += success_rate;
814  }
815  }
816  if (config.failure_percentage_ejection.has_value()) {
817  if (request_volume >=
818  config.failure_percentage_ejection->request_volume) {
819  failure_percentage_ejection_candidates[subchannel_state] =
820  success_rate;
821  }
822  }
823  }
824  // success rate algorithm
825  if (!success_rate_ejection_candidates.empty() &&
826  success_rate_ejection_candidates.size() >=
827  config.success_rate_ejection->minimum_hosts) {
828  // calculate ejection threshold: (mean - stdev *
829  // (success_rate_ejection.stdev_factor / 1000))
830  double mean = success_rate_sum / success_rate_ejection_candidates.size();
831  double variance = 0;
832  std::for_each(success_rate_ejection_candidates.begin(),
833  success_rate_ejection_candidates.end(),
834  [&variance, mean](std::pair<SubchannelState*, double> v) {
835  variance += std::pow(v.second - mean, 2);
836  });
837  variance /= success_rate_ejection_candidates.size();
838  double stdev = std::sqrt(variance);
839  const double success_rate_stdev_factor =
840  static_cast<double>(config.success_rate_ejection->stdev_factor) /
841  1000;
842  double ejection_threshold = mean - stdev * success_rate_stdev_factor;
843  for (auto& candidate : success_rate_ejection_candidates) {
844  if (candidate.second < ejection_threshold) {
845  uint32_t random_key = absl::Uniform(bit_gen_, 1, 100);
846  double current_percent = 100.0 * ejected_host_count /
847  parent_->subchannel_state_map_.size();
848  if (random_key <
849  config.success_rate_ejection->enforcement_percentage &&
850  (ejected_host_count == 0 ||
851  (current_percent < config.max_ejection_percent))) {
852  // Eject and record the timestamp for use when ejecting addresses in
853  // this iteration.
854  candidate.first->Eject(time_now);
855  ++ejected_host_count;
856  }
857  }
858  }
859  }
860  // failure percentage algorithm
861  if (!failure_percentage_ejection_candidates.empty() &&
862  failure_percentage_ejection_candidates.size() >=
863  config.failure_percentage_ejection->minimum_hosts) {
864  for (auto& candidate : failure_percentage_ejection_candidates) {
865  // Extra check to make sure success rate algorithm didn't already
866  // eject this backend.
867  if (candidate.first->ejection_time().has_value()) continue;
868  if ((100.0 - candidate.second) >
869  config.failure_percentage_ejection->threshold) {
870  uint32_t random_key = absl::Uniform(bit_gen_, 1, 100);
871  double current_percent = 100.0 * ejected_host_count /
872  parent_->subchannel_state_map_.size();
873  if (random_key <
874  config.failure_percentage_ejection->enforcement_percentage &&
875  (ejected_host_count == 0 ||
876  (current_percent < config.max_ejection_percent))) {
877  // Eject and record the timestamp for use when ejecting addresses in
878  // this iteration.
879  candidate.first->Eject(time_now);
880  ++ejected_host_count;
881  }
882  }
883  }
884  }
885  // For each address in the map:
886  // If the address is not ejected and the multiplier is greater than 0,
887  // decrease the multiplier by 1. If the address is ejected, and the
888  // current time is after ejection_timestamp + min(base_ejection_time *
889  // multiplier, max(base_ejection_time, max_ejection_time)), un-eject the
890  // address.
891  for (auto& state : parent_->subchannel_state_map_) {
892  auto* subchannel_state = state.second.get();
893  subchannel_state->MaybeUneject(config.base_ejection_time.millis(),
894  config.max_ejection_time.millis());
895  }
896  timer_pending_ = false;
897  parent_->ejection_timer_ =
898  MakeOrphanable<EjectionTimer>(parent_, ExecCtx::Get()->Now());
899  }
900  Unref(DEBUG_LOCATION, "Timer");
902 }
903 
904 //
905 // factory
906 //
907 
908 class OutlierDetectionLbFactory : public LoadBalancingPolicyFactory {
909  public:
910  OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
911  LoadBalancingPolicy::Args args) const override {
912  return MakeOrphanable<OutlierDetectionLb>(std::move(args));
913  }
914 
915  const char* name() const override { return kOutlierDetection; }
916 
917  RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
918  const Json& json, grpc_error_handle* error) const override {
920  if (json.type() == Json::Type::JSON_NULL) {
921  // This policy was configured in the deprecated loadBalancingPolicy
922  // field or in the client API.
924  "field:loadBalancingPolicy error:outlier_detection policy requires "
925  "configuration. Please use loadBalancingConfig field of service "
926  "config instead.");
927  return nullptr;
928  }
929  std::vector<grpc_error_handle> error_list;
930  // Outlier detection config
931  OutlierDetectionConfig outlier_detection_config;
932  auto it = json.object_value().find("successRateEjection");
933  if (it != json.object_value().end()) {
934  if (it->second.type() != Json::Type::OBJECT) {
935  error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
936  "field:successRateEjection error:type must be object"));
937  } else {
938  OutlierDetectionConfig::SuccessRateEjection success_config;
939  const Json::Object& object = it->second.object_value();
940  ParseJsonObjectField(object, "stdevFactor",
941  &success_config.stdev_factor, &error_list,
942  /*required=*/false);
943  ParseJsonObjectField(object, "enforcementPercentage",
944  &success_config.enforcement_percentage,
945  &error_list, /*required=*/false);
946  ParseJsonObjectField(object, "minimumHosts",
947  &success_config.minimum_hosts, &error_list,
948  /*required=*/false);
949  ParseJsonObjectField(object, "requestVolume",
950  &success_config.request_volume, &error_list,
951  /*required=*/false);
952  outlier_detection_config.success_rate_ejection = success_config;
953  }
954  }
955  it = json.object_value().find("failurePercentageEjection");
956  if (it != json.object_value().end()) {
957  if (it->second.type() != Json::Type::OBJECT) {
958  error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
959  "field:successRateEjection error:type must be object"));
960  } else {
961  OutlierDetectionConfig::FailurePercentageEjection failure_config;
962  const Json::Object& object = it->second.object_value();
963  ParseJsonObjectField(object, "threshold", &failure_config.threshold,
964  &error_list, /*required=*/false);
965  ParseJsonObjectField(object, "enforcementPercentage",
966  &failure_config.enforcement_percentage,
967  &error_list, /*required=*/false);
968  ParseJsonObjectField(object, "minimumHosts",
969  &failure_config.minimum_hosts, &error_list,
970  /*required=*/false);
971  ParseJsonObjectField(object, "requestVolume",
972  &failure_config.request_volume, &error_list,
973  /*required=*/false);
974  outlier_detection_config.failure_percentage_ejection = failure_config;
975  }
976  }
977  ParseJsonObjectFieldAsDuration(json.object_value(), "interval",
978  &outlier_detection_config.interval,
979  &error_list);
980  ParseJsonObjectFieldAsDuration(json.object_value(), "baseEjectionTime",
981  &outlier_detection_config.base_ejection_time,
982  &error_list, /*required=*/false);
984  json.object_value(), "maxEjectionTime",
985  &outlier_detection_config.max_ejection_time, &error_list,
986  /*required=*/false)) {
987  outlier_detection_config.max_ejection_time = std::max(
988  outlier_detection_config.base_ejection_time, Duration::Seconds(300));
989  }
990  ParseJsonObjectField(json.object_value(), "maxEjectionPercent",
991  &outlier_detection_config.max_ejection_percent,
992  &error_list, /*required=*/false);
993  RefCountedPtr<LoadBalancingPolicy::Config> child_policy;
994  it = json.object_value().find("childPolicy");
995  if (it == json.object_value().end()) {
996  error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
997  "field:childPolicy error:required field missing"));
998  } else {
1000  child_policy = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
1001  it->second, &parse_error);
1002  if (child_policy == nullptr) {
1004  std::vector<grpc_error_handle> child_errors;
1005  child_errors.push_back(parse_error);
1006  error_list.push_back(
1007  GRPC_ERROR_CREATE_FROM_VECTOR("field:childPolicy", &child_errors));
1008  }
1009  }
1010  if (!error_list.empty()) {
1012  "outlier_detection_experimental LB policy config", &error_list);
1013  return nullptr;
1014  }
1015  return MakeRefCounted<OutlierDetectionLbConfig>(outlier_detection_config,
1016  std::move(child_policy));
1017  }
1018 };
1019 
1020 } // namespace
1021 
1022 } // namespace grpc_core
1023 
1024 //
1025 // Plugin registration
1026 //
1027 
1032  absl::make_unique<grpc_core::OutlierDetectionLbFactory>());
1033  }
1034 }
1035 
GRPC_CLOSURE_INIT
#define GRPC_CLOSURE_INIT(closure, cb, cb_arg, scheduler)
Definition: closure.h:115
trace.h
_gevent_test_main.result
result
Definition: _gevent_test_main.py:96
grpc_core::grpc_outlier_detection_lb_trace
TraceFlag grpc_outlier_detection_lb_trace(false, "outlier_detection_lb")
GPR_INFO
#define GPR_INFO
Definition: include/grpc/impl/codegen/log.h:56
regen-readme.it
it
Definition: regen-readme.py:15
grpc_core::LoadBalancingPolicyRegistry::Builder::RegisterLoadBalancingPolicyFactory
static void RegisterLoadBalancingPolicyFactory(std::unique_ptr< LoadBalancingPolicyFactory > factory)
Definition: lb_policy_registry.cc:87
orphanable.h
GRPC_ERROR_NONE
#define GRPC_ERROR_NONE
Definition: error.h:234
log.h
timer_
grpc_timer timer_
Definition: outlier_detection.cc:376
outlier_detection_config_
OutlierDetectionConfig outlier_detection_config_
Definition: outlier_detection.cc:116
bloat_diff.severity
def severity
Definition: bloat_diff.py:143
state_
grpc_connectivity_state state_
Definition: outlier_detection.cc:403
sockaddr_utils.h
absl::Status::ToString
std::string ToString(StatusToStringMode mode=StatusToStringMode::kDefault) const
Definition: third_party/abseil-cpp/absl/status/status.h:821
connectivity_state.h
GPR_DEBUG_ASSERT
#define GPR_DEBUG_ASSERT(x)
Definition: include/grpc/impl/codegen/log.h:103
Timestamp
Definition: bloaty/third_party/protobuf/src/google/protobuf/timestamp.pb.h:69
grpc_core
Definition: call_metric_recorder.h:31
grpc_pollset_set
struct grpc_pollset_set grpc_pollset_set
Definition: iomgr_fwd.h:23
string.h
ExitIdleLocked
void StartUpdate() ABSL_EXCLUSIVE_LOCKS_REQUIRED(&RlsLb void MaybeFinishUpdate() ABSL_LOCKS_EXCLUDED(&RlsLb void ExitIdleLocked()
Definition: rls.cc:299
absl::string_view
Definition: abseil-cpp/absl/strings/string_view.h:167
gpr_free
GPRAPI void gpr_free(void *ptr)
Definition: alloc.cc:51
subchannel
RingHashSubchannelData * subchannel
Definition: ring_hash.cc:285
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
error
grpc_error_handle error
Definition: retry_filter.cc:499
lb_policy.h
time_now
static uint64_t time_now()
Definition: speed.cc:134
lb_policy_factory.h
GRPC_CHANNEL_TRANSIENT_FAILURE
@ GRPC_CHANNEL_TRANSIENT_FAILURE
Definition: include/grpc/impl/codegen/connectivity_state.h:38
closure.h
shutting_down_
bool shutting_down_
Definition: outlier_detection.cc:398
status
absl::Status status
Definition: rls.cc:251
grpc_core::XdsOutlierDetectionEnabled
bool XdsOutlierDetectionEnabled()
Definition: outlier_detection.cc:77
setup.name
name
Definition: setup.py:542
env.h
absl::InternalError
Status InternalError(absl::string_view message)
Definition: third_party/abseil-cpp/absl/status/status.cc:347
on_timer_
grpc_closure on_timer_
Definition: outlier_detection.cc:377
xds_manager.p
p
Definition: xds_manager.py:60
start_time
static int64_t start_time
Definition: benchmark-getaddrinfo.c:37
subchannel_state_
RefCountedPtr< SubchannelState > subchannel_state_
Definition: outlier_detection.cc:222
grpc_timer
Definition: iomgr/timer.h:33
grpc_sockaddr_to_string
absl::StatusOr< std::string > grpc_sockaddr_to_string(const grpc_resolved_address *resolved_addr, bool normalize)
Definition: sockaddr_utils.cc:194
active_bucket_
std::atomic< Bucket * > active_bucket_
Definition: outlier_detection.cc:309
grpc_pollset_set_del_pollset_set
void grpc_pollset_set_del_pollset_set(grpc_pollset_set *bag, grpc_pollset_set *item)
Definition: pollset_set.cc:52
map
zval * map
Definition: php/ext/google/protobuf/encode_decode.c:480
grpc_channel_args
Definition: grpc_types.h:132
GRPC_TRACE_FLAG_ENABLED
#define GRPC_TRACE_FLAG_ENABLED(f)
Definition: debug/trace.h:114
subchannel_interface.h
message
char * message
Definition: libuv/docs/code/tty-gravity/main.c:12
failures
std::atomic< uint64_t > failures
Definition: outlier_detection.cc:233
grpc_connectivity_state
grpc_connectivity_state
Definition: include/grpc/impl/codegen/connectivity_state.h:30
gpr_parse_bool_value
bool gpr_parse_bool_value(const char *value, bool *dst)
Definition: string.cc:325
GRPC_ERROR_CREATE_FROM_VECTOR
#define GRPC_ERROR_CREATE_FROM_VECTOR(desc, error_list)
Definition: error.h:314
watcher_
std::unique_ptr< SubchannelInterface::ConnectivityStateWatcherInterface > watcher_
Definition: outlier_detection.cc:216
grpc_types.h
absl::synchronization_internal::Get
static GraphId Get(const IdMap &id, int num)
Definition: abseil-cpp/absl/synchronization/internal/graphcycles_test.cc:44
uint32_t
unsigned int uint32_t
Definition: stdint-msvc2008.h:80
DEBUG_LOCATION
#define DEBUG_LOCATION
Definition: debug_location.h:41
start_time_
Timestamp start_time_
Definition: outlier_detection.cc:379
ejection_timer_
OrphanablePtr< EjectionTimer > ejection_timer_
Definition: outlier_detection.cc:407
asyncio_get_stats.args
args
Definition: asyncio_get_stats.py:40
gpr_getenv
char * gpr_getenv(const char *name)
absl::move
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: abseil-cpp/absl/utility/utility.h:221
GPR_ASSERT
#define GPR_ASSERT(x)
Definition: include/grpc/impl/codegen/log.h:94
hpack_encoder_fixtures::Args
Args({0, 16384})
absl::optional::has_value
constexpr bool has_value() const noexcept
Definition: abseil-cpp/absl/types/optional.h:461
max
int max
Definition: bloaty/third_party/zlib/examples/enough.c:170
Json
JSON (JavaScript Object Notation).
Definition: third_party/bloaty/third_party/protobuf/conformance/third_party/jsoncpp/json.h:227
successes
std::atomic< uint64_t > successes
Definition: outlier_detection.cc:232
gpr_log
GPRAPI void gpr_log(const char *file, int line, gpr_log_severity severity, const char *format,...) GPR_PRINT_FORMAT_CHECK(4
setup.v
v
Definition: third_party/bloaty/third_party/capstone/bindings/python/setup.py:42
watchers_
std::map< SubchannelInterface::ConnectivityStateWatcherInterface *, WatcherWrapper * > watchers_
Definition: outlier_detection.cc:226
work_serializer.h
connectivity_state.h
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
json_util.h
absl::optional< grpc_connectivity_state >
pollset_set.h
GRPC_CHANNEL_IDLE
@ GRPC_CHANNEL_IDLE
Definition: include/grpc/impl/codegen/connectivity_state.h:32
arg
Definition: cmdline.cc:40
server_address.h
grpc_channel_args_copy
grpc_channel_args * grpc_channel_args_copy(const grpc_channel_args *src)
Definition: channel_args.cc:285
status_
absl::Status status_
Definition: outlier_detection.cc:404
error.h
last_seen_status_
absl::Status last_seen_status_
Definition: outlier_detection.cc:218
wrapper
grpc_channel_wrapper * wrapper
Definition: src/php/ext/grpc/channel.h:48
json.h
min
#define min(a, b)
Definition: qsort.h:83
timer_pending_
bool timer_pending_
Definition: outlier_detection.cc:378
bit_gen_
absl::BitGen bit_gen_
Definition: outlier_detection.cc:380
GRPC_ERROR_CREATE_FROM_STATIC_STRING
#define GRPC_ERROR_CREATE_FROM_STATIC_STRING(desc)
Definition: error.h:291
config_
RefCountedPtr< OutlierDetectionLbConfig > config_
Definition: outlier_detection.cc:395
ejected_
bool ejected_
Definition: outlier_detection.cc:219
child_policy_handler.h
value
const char * value
Definition: hpack_parser_table.cc:165
absl::Seconds
constexpr Duration Seconds(T n)
Definition: third_party/abseil-cpp/absl/time/time.h:419
grpc_timer_cancel
void grpc_timer_cancel(grpc_timer *timer)
Definition: iomgr/timer.cc:36
grpc_core::Duration::Milliseconds
static constexpr Duration Milliseconds(int64_t millis)
Definition: src/core/lib/gprpp/time.h:155
absl::Now
ABSL_NAMESPACE_BEGIN Time Now()
Definition: abseil-cpp/absl/time/clock.cc:39
picker_
std::unique_ptr< SubchannelPicker > picker_
Definition: outlier_detection.cc:323
grpc_core::ConnectivityStateName
const char * ConnectivityStateName(grpc_connectivity_state state)
Definition: connectivity_state.cc:38
GRPC_ERROR_REF
#define GRPC_ERROR_REF(err)
Definition: error.h:261
debug_location.h
key
const char * key
Definition: hpack_parser_table.cc:164
backup_bucket_
std::unique_ptr< Bucket > backup_bucket_
Definition: outlier_detection.cc:306
lb_policy_registry.h
ref_counted.h
benchmark::internal::Finish
double Finish(Counter const &c, IterationCount iterations, double cpu_time, double num_threads)
Definition: benchmark/src/counter.cc:20
absl::Status
Definition: third_party/abseil-cpp/absl/status/status.h:424
grpc_lb_policy_outlier_detection_shutdown
void grpc_lb_policy_outlier_detection_shutdown()
Definition: outlier_detection.cc:1036
alloc.h
subchannel_state_map_
std::map< std::string, RefCountedPtr< SubchannelState > > subchannel_state_map_
Definition: outlier_detection.cc:406
subchannels_
std::set< SubchannelWrapper * > subchannels_
Definition: outlier_detection.cc:312
std
Definition: grpcpp/impl/codegen/async_unary_call.h:407
absl::random_internal::NonsecureURBGBase< random_internal::randen_engine< uint64_t > >
grpc_pollset_set_add_pollset_set
void grpc_pollset_set_add_pollset_set(grpc_pollset_set *bag, grpc_pollset_set *item)
Definition: pollset_set.cc:47
counting_enabled_
bool counting_enabled_
Definition: outlier_detection.cc:337
arg
struct arg arg
state
Definition: bloaty/third_party/zlib/contrib/blast/blast.c:41
exec_ctx.h
grpc_timer_init
void grpc_timer_init(grpc_timer *timer, grpc_core::Timestamp deadline, grpc_closure *closure)
Definition: iomgr/timer.cc:31
absl::UnavailableError
Status UnavailableError(absl::string_view message)
Definition: third_party/abseil-cpp/absl/status/status.cc:375
GRPC_ERROR_UNREF
#define GRPC_ERROR_UNREF(err)
Definition: error.h:262
ref_counted_ptr.h
last_seen_state_
absl::optional< grpc_connectivity_state > last_seen_state_
Definition: outlier_detection.cc:217
config_s
Definition: bloaty/third_party/zlib/deflate.c:120
watcher
ClusterWatcher * watcher
Definition: cds.cc:148
ejection_time_
absl::optional< Timestamp > ejection_time_
Definition: outlier_detection.cc:311
channel_args.h
timer.h
check_redundant_namespace_qualifiers.Config
Config
Definition: check_redundant_namespace_qualifiers.py:142
outlier_detection_policy_
RefCountedPtr< OutlierDetectionLb > outlier_detection_policy_
Definition: outlier_detection.cc:359
Fail
void Fail(const char *msg)
Definition: bloaty/third_party/googletest/googletest/test/gtest_assert_by_exception_test.cc:52
parent_
RefCountedPtr< OutlierDetectionLb > parent_
Definition: outlier_detection.cc:375
grpc_core::ParseJsonObjectFieldAsDuration
bool ParseJsonObjectFieldAsDuration(const Json::Object &object, absl::string_view field_name, Duration *output, std::vector< grpc_error_handle > *error_list, bool required)
Definition: src/core/lib/json/json_util.cc:107
iomgr_fwd.h
multiplier_
uint32_t multiplier_
Definition: outlier_detection.cc:310
grpc_error
Definition: error_internal.h:42
original_subchannel_call_tracker_
std::unique_ptr< LoadBalancingPolicy::SubchannelCallTrackerInterface > original_subchannel_call_tracker_
Definition: outlier_detection.cc:490
testing::Ref
internal::RefMatcher< T & > Ref(T &x)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:8628
child_policy_
RefCountedPtr< LoadBalancingPolicy::Config > child_policy_
Definition: outlier_detection.cc:117
grpc_closure
Definition: closure.h:56
current_bucket_
std::unique_ptr< Bucket > current_bucket_
Definition: outlier_detection.cc:305
grpc_core::ExecCtx::Get
static ExecCtx * Get()
Definition: exec_ctx.h:205
grpc_core::ParseJsonObjectField
bool ParseJsonObjectField(const Json::Object &object, absl::string_view field_name, T *output, std::vector< grpc_error_handle > *error_list, bool required=true)
Definition: src/core/lib/json/json_util.h:136
grpc_core::Duration::Infinity
static constexpr Duration Infinity()
Definition: src/core/lib/gprpp/time.h:139
state
static struct rpc_state state
Definition: bad_server_response_test.cc:87
outlier_detection.h
GRPC_ERROR_IS_NONE
#define GRPC_ERROR_IS_NONE(err)
Definition: error.h:241
parse_error
@ parse_error
Definition: pem_info.c:88
grpc_lb_policy_outlier_detection_init
void grpc_lb_policy_outlier_detection_init()
Definition: outlier_detection.cc:1028
port_platform.h
absl::Uniform
absl::enable_if_t<!std::is_same< R, void >::value, R > Uniform(TagType tag, URBG &&urbg, R lo, R hi)
Definition: abseil-cpp/absl/random/distributions.h:123


grpc
Author(s):
autogenerated on Fri May 16 2025 02:59:36