• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * Copyright 2015 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 #include <grpc/support/port_platform.h>
20 
21 #include "src/core/ext/filters/client_channel/lb_policy.h"
22 
23 #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
24 #include "src/core/lib/iomgr/combiner.h"
25 
26 namespace grpc_core {
27 
28 DebugOnlyTraceFlag grpc_trace_lb_policy_refcount(false, "lb_policy_refcount");
29 
30 //
31 // LoadBalancingPolicy
32 //
33 
LoadBalancingPolicy(Args args,intptr_t initial_refcount)34 LoadBalancingPolicy::LoadBalancingPolicy(Args args, intptr_t initial_refcount)
35     : InternallyRefCounted(
36           GRPC_TRACE_FLAG_ENABLED(grpc_trace_lb_policy_refcount)
37               ? "LoadBalancingPolicy"
38               : nullptr,
39           initial_refcount),
40       work_serializer_(std::move(args.work_serializer)),
41       interested_parties_(grpc_pollset_set_create()),
42       channel_control_helper_(std::move(args.channel_control_helper)) {}
43 
~LoadBalancingPolicy()44 LoadBalancingPolicy::~LoadBalancingPolicy() {
45   grpc_pollset_set_destroy(interested_parties_);
46 }
47 
Orphan()48 void LoadBalancingPolicy::Orphan() {
49   ShutdownLocked();
50   Unref(DEBUG_LOCATION, "Orphan");
51 }
52 
53 //
54 // LoadBalancingPolicy::UpdateArgs
55 //
56 
UpdateArgs(const UpdateArgs & other)57 LoadBalancingPolicy::UpdateArgs::UpdateArgs(const UpdateArgs& other) {
58   addresses = other.addresses;
59   config = other.config;
60   args = grpc_channel_args_copy(other.args);
61 }
62 
UpdateArgs(UpdateArgs && other)63 LoadBalancingPolicy::UpdateArgs::UpdateArgs(UpdateArgs&& other) noexcept {
64   addresses = std::move(other.addresses);
65   config = std::move(other.config);
66   // TODO(roth): Use std::move() once channel args is converted to C++.
67   args = other.args;
68   other.args = nullptr;
69 }
70 
operator =(const UpdateArgs & other)71 LoadBalancingPolicy::UpdateArgs& LoadBalancingPolicy::UpdateArgs::operator=(
72     const UpdateArgs& other) {
73   addresses = other.addresses;
74   config = other.config;
75   grpc_channel_args_destroy(args);
76   args = grpc_channel_args_copy(other.args);
77   return *this;
78 }
79 
operator =(UpdateArgs && other)80 LoadBalancingPolicy::UpdateArgs& LoadBalancingPolicy::UpdateArgs::operator=(
81     UpdateArgs&& other) noexcept {
82   addresses = std::move(other.addresses);
83   config = std::move(other.config);
84   // TODO(roth): Use std::move() once channel args is converted to C++.
85   grpc_channel_args_destroy(args);
86   args = other.args;
87   other.args = nullptr;
88   return *this;
89 }
90 
91 //
92 // LoadBalancingPolicy::QueuePicker
93 //
94 
Pick(PickArgs)95 LoadBalancingPolicy::PickResult LoadBalancingPolicy::QueuePicker::Pick(
96     PickArgs /*args*/) {
97   // We invoke the parent's ExitIdleLocked() via a closure instead
98   // of doing it directly here, for two reasons:
99   // 1. ExitIdleLocked() may cause the policy's state to change and
100   //    a new picker to be delivered to the channel.  If that new
101   //    picker is delivered before ExitIdleLocked() returns, then by
102   //    the time this function returns, the pick will already have
103   //    been processed, and we'll be trying to re-process the same
104   //    pick again, leading to a crash.
105   // 2. We are currently running in the data plane mutex, but we
106   //    need to bounce into the control plane work_serializer to call
107   //    ExitIdleLocked().
108   if (!exit_idle_called_ && parent_ != nullptr) {
109     exit_idle_called_ = true;
110     auto* parent = parent_->Ref().release();  // ref held by lambda.
111     ExecCtx::Run(DEBUG_LOCATION,
112                  GRPC_CLOSURE_CREATE(
113                      [](void* arg, grpc_error* /*error*/) {
114                        auto* parent = static_cast<LoadBalancingPolicy*>(arg);
115                        parent->work_serializer()->Run(
116                            [parent]() {
117                              parent->ExitIdleLocked();
118                              parent->Unref();
119                            },
120                            DEBUG_LOCATION);
121                      },
122                      parent, nullptr),
123                  GRPC_ERROR_NONE);
124   }
125   PickResult result;
126   result.type = PickResult::PICK_QUEUE;
127   return result;
128 }
129 
130 //
131 // LoadBalancingPolicy::TransientFailurePicker
132 //
133 
134 LoadBalancingPolicy::PickResult
Pick(PickArgs)135 LoadBalancingPolicy::TransientFailurePicker::Pick(PickArgs /*args*/) {
136   PickResult result;
137   result.type = PickResult::PICK_FAILED;
138   result.error = GRPC_ERROR_REF(error_);
139   return result;
140 }
141 
142 }  // namespace grpc_core
143