child_policy_handler.cc
Go to the documentation of this file.
1 //
2 // Copyright 2018 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 <cstring>
22 #include <memory>
23 #include <string>
24 
25 #include "absl/status/status.h"
26 #include "absl/strings/str_cat.h"
27 #include "absl/strings/string_view.h"
28 
30 #include <grpc/support/log.h>
31 
38 
39 namespace grpc_core {
40 
41 //
42 // ChildPolicyHandler::Helper
43 //
44 
47  public:
49  : parent_(std::move(parent)) {}
50 
51  ~Helper() override { parent_.reset(DEBUG_LOCATION, "Helper"); }
52 
54  ServerAddress address, const grpc_channel_args& args) override {
55  if (parent_->shutting_down_) return nullptr;
56  if (!CalledByCurrentChild() && !CalledByPendingChild()) return nullptr;
57  return parent_->channel_control_helper()->CreateSubchannel(
58  std::move(address), args);
59  }
60 
62  std::unique_ptr<SubchannelPicker> picker) override {
63  if (parent_->shutting_down_) return;
64  // If this request is from the pending child policy, ignore it until
65  // it reports something other than CONNECTING, at which point we swap it
66  // into place.
67  if (CalledByPendingChild()) {
68  if (GRPC_TRACE_FLAG_ENABLED(*(parent_->tracer_))) {
70  "[child_policy_handler %p] helper %p: pending child policy %p "
71  "reports state=%s (%s)",
73  status.ToString().c_str());
74  }
75  if (state == GRPC_CHANNEL_CONNECTING) return;
77  parent_->child_policy_->interested_parties(),
78  parent_->interested_parties());
79  parent_->child_policy_ = std::move(parent_->pending_child_policy_);
80  } else if (!CalledByCurrentChild()) {
81  // This request is from an outdated child, so ignore it.
82  return;
83  }
84  parent_->channel_control_helper()->UpdateState(state, status,
85  std::move(picker));
86  }
87 
88  void RequestReresolution() override {
89  if (parent_->shutting_down_) return;
90  // Only forward re-resolution requests from the most recent child,
91  // since that's the one that will be receiving any update we receive
92  // from the resolver.
93  const LoadBalancingPolicy* latest_child_policy =
94  parent_->pending_child_policy_ != nullptr
95  ? parent_->pending_child_policy_.get()
96  : parent_->child_policy_.get();
97  if (child_ != latest_child_policy) return;
98  if (GRPC_TRACE_FLAG_ENABLED(*(parent_->tracer_))) {
99  gpr_log(GPR_INFO, "[child_policy_handler %p] started name re-resolving",
100  parent_.get());
101  }
102  parent_->channel_control_helper()->RequestReresolution();
103  }
104 
106  return parent_->channel_control_helper()->GetAuthority();
107  }
108 
110  absl::string_view message) override {
111  if (parent_->shutting_down_) return;
112  if (!CalledByPendingChild() && !CalledByCurrentChild()) return;
113  parent_->channel_control_helper()->AddTraceEvent(severity, message);
114  }
115 
117 
118  private:
119  bool CalledByPendingChild() const {
120  GPR_ASSERT(child_ != nullptr);
121  return child_ == parent_->pending_child_policy_.get();
122  }
123 
124  bool CalledByCurrentChild() const {
125  GPR_ASSERT(child_ != nullptr);
126  return child_ == parent_->child_policy_.get();
127  };
128 
131 };
132 
133 //
134 // ChildPolicyHandler
135 //
136 
139  gpr_log(GPR_INFO, "[child_policy_handler %p] shutting down", this);
140  }
141  shutting_down_ = true;
142  if (child_policy_ != nullptr) {
144  gpr_log(GPR_INFO, "[child_policy_handler %p] shutting down lb_policy %p",
145  this, child_policy_.get());
146  }
147  grpc_pollset_set_del_pollset_set(child_policy_->interested_parties(),
149  child_policy_.reset();
150  }
151  if (pending_child_policy_ != nullptr) {
154  "[child_policy_handler %p] shutting down pending lb_policy %p",
155  this, pending_child_policy_.get());
156  }
158  pending_child_policy_->interested_parties(), interested_parties());
159  pending_child_policy_.reset();
160  }
161 }
162 
164  // If the child policy name changes, we need to create a new child
165  // policy. When this happens, we leave child_policy_ as-is and store
166  // the new child policy in pending_child_policy_. Once the new child
167  // policy transitions into state READY, we swap it into child_policy_,
168  // replacing the original child policy. So pending_child_policy_ is
169  // non-null only between when we apply an update that changes the child
170  // policy name and when the new child reports state READY.
171  //
172  // Updates can arrive at any point during this transition. We always
173  // apply updates relative to the most recently created child policy,
174  // even if the most recent one is still in pending_child_policy_. This
175  // is true both when applying the updates to an existing child policy
176  // and when determining whether we need to create a new policy.
177  //
178  // As a result of this, there are several cases to consider here:
179  //
180  // 1. We have no existing child policy (i.e., this is the first update
181  // we receive after being created; in this case, both child_policy_
182  // and pending_child_policy_ are null). In this case, we create a
183  // new child policy and store it in child_policy_.
184  //
185  // 2. We have an existing child policy and have no pending child policy
186  // from a previous update (i.e., either there has not been a
187  // previous update that changed the policy name, or we have already
188  // finished swapping in the new policy; in this case, child_policy_
189  // is non-null but pending_child_policy_ is null). In this case:
190  // a. If going from the current config to the new config does not
191  // require a new policy, then we update the existing child policy.
192  // b. If going from the current config to the new config does require a
193  // new policy, we create a new policy. The policy will be stored in
194  // pending_child_policy_ and will later be swapped into
195  // child_policy_ by the helper when the new child transitions
196  // into state READY.
197  //
198  // 3. We have an existing child policy and have a pending child policy
199  // from a previous update (i.e., a previous update set
200  // pending_child_policy_ as per case 2b above and that policy has
201  // not yet transitioned into state READY and been swapped into
202  // child_policy_; in this case, both child_policy_ and
203  // pending_child_policy_ are non-null). In this case:
204  // a. If going from the current config to the new config does not
205  // require a new policy, then we update the existing pending
206  // child policy.
207  // b. If going from the current config to the new config does require a
208  // new child policy, then we create a new policy. The new
209  // policy is stored in pending_child_policy_ (replacing the one
210  // that was there before, which will be immediately shut down)
211  // and will later be swapped into child_policy_ by the helper
212  // when the new child transitions into state READY.
213  const bool create_policy =
214  // case 1
215  child_policy_ == nullptr ||
216  // cases 2b and 3b
218  args.config.get());
219  current_config_ = args.config;
220  LoadBalancingPolicy* policy_to_update = nullptr;
221  if (create_policy) {
222  // Cases 1, 2b, and 3b: create a new child policy.
223  // If child_policy_ is null, we set it (case 1), else we set
224  // pending_child_policy_ (cases 2b and 3b).
225  // TODO(roth): In cases 2b and 3b, we should start a timer here, so
226  // that there's an upper bound on the amount of time it takes us to
227  // switch to the new policy, even if the new policy stays in
228  // CONNECTING for a very long period of time.
231  "[child_policy_handler %p] creating new %schild policy %s", this,
232  child_policy_ == nullptr ? "" : "pending ", args.config->name());
233  }
234  auto& lb_policy =
236  lb_policy = CreateChildPolicy(args.config->name(), *args.args);
237  policy_to_update = lb_policy.get();
238  } else {
239  // Cases 2a and 3a: update an existing policy.
240  // If we have a pending child policy, send the update to the pending
241  // policy (case 3a), else send it to the current policy (case 2a).
242  policy_to_update = pending_child_policy_ != nullptr
243  ? pending_child_policy_.get()
244  : child_policy_.get();
245  }
246  GPR_ASSERT(policy_to_update != nullptr);
247  // Update the policy.
249  gpr_log(GPR_INFO, "[child_policy_handler %p] updating %schild policy %p",
250  this,
251  policy_to_update == pending_child_policy_.get() ? "pending " : "",
252  policy_to_update);
253  }
254  policy_to_update->UpdateLocked(std::move(args));
255 }
256 
258  if (child_policy_ != nullptr) {
259  child_policy_->ExitIdleLocked();
260  if (pending_child_policy_ != nullptr) {
261  pending_child_policy_->ExitIdleLocked();
262  }
263  }
264 }
265 
267  if (child_policy_ != nullptr) {
268  child_policy_->ResetBackoffLocked();
269  if (pending_child_policy_ != nullptr) {
270  pending_child_policy_->ResetBackoffLocked();
271  }
272  }
273 }
274 
276  const char* child_policy_name, const grpc_channel_args& args) {
277  Helper* helper = new Helper(Ref(DEBUG_LOCATION, "Helper"));
278  LoadBalancingPolicy::Args lb_policy_args;
279  lb_policy_args.work_serializer = work_serializer();
280  lb_policy_args.channel_control_helper =
281  std::unique_ptr<ChannelControlHelper>(helper);
282  lb_policy_args.args = &args;
284  CreateLoadBalancingPolicy(child_policy_name, std::move(lb_policy_args));
285  if (GPR_UNLIKELY(lb_policy == nullptr)) {
286  gpr_log(GPR_ERROR, "could not create LB policy \"%s\"", child_policy_name);
287  return nullptr;
288  }
289  helper->set_child(lb_policy.get());
292  "[child_policy_handler %p] created new LB policy \"%s\" (%p)", this,
293  child_policy_name, lb_policy.get());
294  }
297  absl::StrCat("Created new LB policy \"", child_policy_name, "\""));
298  grpc_pollset_set_add_pollset_set(lb_policy->interested_parties(),
300  return lb_policy;
301 }
302 
304  LoadBalancingPolicy::Config* old_config,
305  LoadBalancingPolicy::Config* new_config) const {
306  return strcmp(old_config->name(), new_config->name()) != 0;
307 }
308 
311  const char* name, LoadBalancingPolicy::Args args) const {
313  name, std::move(args));
314 }
315 
316 } // namespace grpc_core
grpc_core::ChildPolicyHandler::Helper::parent_
RefCountedPtr< ChildPolicyHandler > parent_
Definition: child_policy_handler.cc:127
grpc_core::LoadBalancingPolicy::ChannelControlHelper::TRACE_INFO
@ TRACE_INFO
Definition: lb_policy.h:297
GPR_INFO
#define GPR_INFO
Definition: include/grpc/impl/codegen/log.h:56
grpc_core::ChildPolicyHandler::tracer_
TraceFlag * tracer_
Definition: child_policy_handler.h:71
grpc_core::LoadBalancingPolicy::ChannelControlHelper::TraceSeverity
TraceSeverity
Adds a trace message associated with the channel.
Definition: lb_policy.h:297
log.h
bloat_diff.severity
def severity
Definition: bloat_diff.py:143
grpc_core::LoadBalancingPolicy::interested_parties
grpc_pollset_set * interested_parties() const
Definition: lb_policy.h:384
grpc_core::ChildPolicyHandler::Helper
Definition: child_policy_handler.cc:45
grpc_core::LoadBalancingPolicy::UpdateArgs
Definition: lb_policy.h:315
absl::Status::ToString
std::string ToString(StatusToStringMode mode=StatusToStringMode::kDefault) const
Definition: third_party/abseil-cpp/absl/status/status.h:821
absl::StrCat
std::string StrCat(const AlphaNum &a, const AlphaNum &b)
Definition: abseil-cpp/absl/strings/str_cat.cc:98
grpc_core::LoadBalancingPolicy
Definition: lb_policy.h:95
connectivity_state.h
grpc_core::LoadBalancingPolicy::Args::args
const grpc_channel_args * args
Channel args.
Definition: lb_policy.h:355
grpc_core::ChildPolicyHandler::Helper::~Helper
~Helper() override
Definition: child_policy_handler.cc:51
grpc_core::ChildPolicyHandler::Helper::RequestReresolution
void RequestReresolution() override
Requests that the resolver re-resolve.
Definition: child_policy_handler.cc:88
grpc_core::LoadBalancingPolicy::ChannelControlHelper::AddTraceEvent
virtual void AddTraceEvent(TraceSeverity severity, absl::string_view message)=0
grpc_core
Definition: call_metric_recorder.h:31
absl::string_view
Definition: abseil-cpp/absl/strings/string_view.h:167
grpc_core::ChildPolicyHandler::Helper::AddTraceEvent
void AddTraceEvent(TraceSeverity severity, absl::string_view message) override
Definition: child_policy_handler.cc:109
grpc_core::ServerAddress
Definition: server_address.h:49
grpc_core::LoadBalancingPolicy::Config
Definition: lb_policy.h:305
status
absl::Status status
Definition: rls.cc:251
setup.name
name
Definition: setup.py:542
grpc_core::ChildPolicyHandler::Helper::CalledByPendingChild
bool CalledByPendingChild() const
Definition: child_policy_handler.cc:119
grpc_core::LoadBalancingPolicy::UpdateLocked
virtual void UpdateLocked(UpdateArgs)=0
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
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
grpc_connectivity_state
grpc_connectivity_state
Definition: include/grpc/impl/codegen/connectivity_state.h:30
grpc_core::ChildPolicyHandler::ExitIdleLocked
void ExitIdleLocked() override
Definition: child_policy_handler.cc:257
grpc_core::ChildPolicyHandler::ConfigChangeRequiresNewPolicyInstance
virtual bool ConfigChangeRequiresNewPolicyInstance(LoadBalancingPolicy::Config *old_config, LoadBalancingPolicy::Config *new_config) const
Definition: child_policy_handler.cc:303
DEBUG_LOCATION
#define DEBUG_LOCATION
Definition: debug_location.h:41
grpc_core::ChildPolicyHandler::Helper::set_child
void set_child(LoadBalancingPolicy *child)
Definition: child_policy_handler.cc:116
asyncio_get_stats.args
args
Definition: asyncio_get_stats.py:40
grpc_core::RefCountedPtr
Definition: ref_counted_ptr.h:35
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
grpc_core::InternallyRefCounted< LoadBalancingPolicy >::Ref
RefCountedPtr< LoadBalancingPolicy > Ref() GRPC_MUST_USE_RESULT
Definition: orphanable.h:90
gpr_log
GPRAPI void gpr_log(const char *file, int line, gpr_log_severity severity, const char *format,...) GPR_PRINT_FORMAT_CHECK(4
GPR_UNLIKELY
#define GPR_UNLIKELY(x)
Definition: impl/codegen/port_platform.h:770
grpc_core::ChildPolicyHandler::Helper::UpdateState
void UpdateState(grpc_connectivity_state state, const absl::Status &status, std::unique_ptr< SubchannelPicker > picker) override
Definition: child_policy_handler.cc:61
connectivity_state.h
pollset_set.h
grpc_core::LoadBalancingPolicy::channel_control_helper
ChannelControlHelper * channel_control_helper() const
Definition: lb_policy.h:426
server_address.h
googletest-filter-unittest.child
child
Definition: bloaty/third_party/googletest/googletest/test/googletest-filter-unittest.py:62
grpc_core::LoadBalancingPolicy::Config::name
virtual const char * name() const =0
grpc_core::ChildPolicyHandler::Helper::CalledByCurrentChild
bool CalledByCurrentChild() const
Definition: child_policy_handler.cc:124
grpc_core::ChildPolicyHandler::UpdateLocked
void UpdateLocked(UpdateArgs args) override
Definition: child_policy_handler.cc:163
grpc_core::ChildPolicyHandler::current_config_
RefCountedPtr< LoadBalancingPolicy::Config > current_config_
Definition: child_policy_handler.h:78
GPR_ERROR
#define GPR_ERROR
Definition: include/grpc/impl/codegen/log.h:57
grpc_core::ChildPolicyHandler::shutting_down_
bool shutting_down_
Definition: child_policy_handler.h:73
grpc_core::ChildPolicyHandler::CreateChildPolicy
OrphanablePtr< LoadBalancingPolicy > CreateChildPolicy(const char *child_policy_name, const grpc_channel_args &args)
Definition: child_policy_handler.cc:275
grpc_core::LoadBalancingPolicy::Args
Args used to instantiate an LB policy.
Definition: lb_policy.h:343
GRPC_CHANNEL_CONNECTING
@ GRPC_CHANNEL_CONNECTING
Definition: include/grpc/impl/codegen/connectivity_state.h:34
grpc_core::LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy
static OrphanablePtr< LoadBalancingPolicy > CreateLoadBalancingPolicy(const char *name, LoadBalancingPolicy::Args args)
Creates an LB policy of the type specified by name.
Definition: lb_policy_registry.cc:98
grpc_core::LoadBalancingPolicy::Args::work_serializer
std::shared_ptr< WorkSerializer > work_serializer
The work_serializer under which all LB policy calls will be run.
Definition: lb_policy.h:345
child_policy_handler.h
grpc_core::ChildPolicyHandler::Helper::CreateSubchannel
RefCountedPtr< SubchannelInterface > CreateSubchannel(ServerAddress address, const grpc_channel_args &args) override
Creates a new subchannel with the specified channel args.
Definition: child_policy_handler.cc:53
grpc_core::ChildPolicyHandler::Helper::child_
LoadBalancingPolicy * child_
Definition: child_policy_handler.cc:130
grpc_core::ConnectivityStateName
const char * ConnectivityStateName(grpc_connectivity_state state)
Definition: connectivity_state.cc:38
debug_location.h
lb_policy_registry.h
absl::Status
Definition: third_party/abseil-cpp/absl/status/status.h:424
grpc_core::OrphanablePtr
std::unique_ptr< T, Deleter > OrphanablePtr
Definition: orphanable.h:64
std
Definition: grpcpp/impl/codegen/async_unary_call.h:407
grpc_core::ChildPolicyHandler::child_policy_
OrphanablePtr< LoadBalancingPolicy > child_policy_
Definition: child_policy_handler.h:81
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
state
Definition: bloaty/third_party/zlib/contrib/blast/blast.c:41
grpc_core::LoadBalancingPolicy::ChannelControlHelper
Definition: lb_policy.h:275
grpc_core::LoadBalancingPolicy::Args::channel_control_helper
std::unique_ptr< ChannelControlHelper > channel_control_helper
Definition: lb_policy.h:349
grpc_core::LoadBalancingPolicy::work_serializer
std::shared_ptr< WorkSerializer > work_serializer() const
Definition: lb_policy.h:420
grpc_core::ChildPolicyHandler::Helper::Helper
Helper(RefCountedPtr< ChildPolicyHandler > parent)
Definition: child_policy_handler.cc:48
grpc_core::ChildPolicyHandler::ResetBackoffLocked
void ResetBackoffLocked() override
Resets connection backoff.
Definition: child_policy_handler.cc:266
grpc_core::ChildPolicyHandler::ShutdownLocked
void ShutdownLocked() override
Shuts down the policy.
Definition: child_policy_handler.cc:137
grpc_core::ChildPolicyHandler::CreateLoadBalancingPolicy
virtual OrphanablePtr< LoadBalancingPolicy > CreateLoadBalancingPolicy(const char *name, LoadBalancingPolicy::Args args) const
Definition: child_policy_handler.cc:310
grpc_core::ChildPolicyHandler::Helper::GetAuthority
absl::string_view GetAuthority() override
Returns the channel authority.
Definition: child_policy_handler.cc:105
grpc_core::ChildPolicyHandler::pending_child_policy_
OrphanablePtr< LoadBalancingPolicy > pending_child_policy_
Definition: child_policy_handler.h:82
grpc_core::ChildPolicyHandler::name
const char * name() const override
Returns the name of the LB policy.
Definition: child_policy_handler.h:44
port_platform.h


grpc
Author(s):
autogenerated on Fri May 16 2025 02:57:53