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