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 if (&other == this) {
74 return *this;
75 }
76 addresses = other.addresses;
77 config = other.config;
78 grpc_channel_args_destroy(args);
79 args = grpc_channel_args_copy(other.args);
80 return *this;
81 }
82
operator =(UpdateArgs && other)83 LoadBalancingPolicy::UpdateArgs& LoadBalancingPolicy::UpdateArgs::operator=(
84 UpdateArgs&& other) noexcept {
85 addresses = std::move(other.addresses);
86 config = std::move(other.config);
87 // TODO(roth): Use std::move() once channel args is converted to C++.
88 grpc_channel_args_destroy(args);
89 args = other.args;
90 other.args = nullptr;
91 return *this;
92 }
93
94 //
95 // LoadBalancingPolicy::QueuePicker
96 //
97
Pick(PickArgs)98 LoadBalancingPolicy::PickResult LoadBalancingPolicy::QueuePicker::Pick(
99 PickArgs /*args*/) {
100 // We invoke the parent's ExitIdleLocked() via a closure instead
101 // of doing it directly here, for two reasons:
102 // 1. ExitIdleLocked() may cause the policy's state to change and
103 // a new picker to be delivered to the channel. If that new
104 // picker is delivered before ExitIdleLocked() returns, then by
105 // the time this function returns, the pick will already have
106 // been processed, and we'll be trying to re-process the same
107 // pick again, leading to a crash.
108 // 2. We are currently running in the data plane mutex, but we
109 // need to bounce into the control plane work_serializer to call
110 // ExitIdleLocked().
111 if (!exit_idle_called_ && parent_ != nullptr) {
112 exit_idle_called_ = true;
113 auto* parent = parent_->Ref().release(); // ref held by lambda.
114 ExecCtx::Run(DEBUG_LOCATION,
115 GRPC_CLOSURE_CREATE(
116 [](void* arg, grpc_error_handle /*error*/) {
117 auto* parent = static_cast<LoadBalancingPolicy*>(arg);
118 parent->work_serializer()->Run(
119 [parent]() {
120 parent->ExitIdleLocked();
121 parent->Unref();
122 },
123 DEBUG_LOCATION);
124 },
125 parent, nullptr),
126 GRPC_ERROR_NONE);
127 }
128 return PickResult::Queue();
129 }
130
131 } // namespace grpc_core
132