3 * Copyright 2015 gRPC authors.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <grpc/support/port_platform.h>
21 #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
25 #include "src/core/lib/gpr/string.h"
26 #include "src/core/lib/gprpp/inlined_vector.h"
36 void RegisterLoadBalancingPolicyFactory(
37 UniquePtr<LoadBalancingPolicyFactory> factory) {
38 for (size_t i = 0; i < factories_.size(); ++i) {
39 GPR_ASSERT(strcmp(factories_[i]->name(), factory->name()) != 0);
41 factories_.push_back(std::move(factory));
44 LoadBalancingPolicyFactory* GetLoadBalancingPolicyFactory(
45 const char* name) const {
46 for (size_t i = 0; i < factories_.size(); ++i) {
47 if (strcmp(name, factories_[i]->name()) == 0) {
48 return factories_[i].get();
55 InlinedVector<UniquePtr<LoadBalancingPolicyFactory>, 10> factories_;
58 RegistryState* g_state = nullptr;
63 // LoadBalancingPolicyRegistry::Builder
66 void LoadBalancingPolicyRegistry::Builder::InitRegistry() {
67 if (g_state == nullptr) g_state = New<RegistryState>();
70 void LoadBalancingPolicyRegistry::Builder::ShutdownRegistry() {
75 void LoadBalancingPolicyRegistry::Builder::RegisterLoadBalancingPolicyFactory(
76 UniquePtr<LoadBalancingPolicyFactory> factory) {
78 g_state->RegisterLoadBalancingPolicyFactory(std::move(factory));
82 // LoadBalancingPolicyRegistry
85 OrphanablePtr<LoadBalancingPolicy>
86 LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy(
87 const char* name, LoadBalancingPolicy::Args args) {
88 GPR_ASSERT(g_state != nullptr);
90 LoadBalancingPolicyFactory* factory =
91 g_state->GetLoadBalancingPolicyFactory(name);
92 if (factory == nullptr) return nullptr; // Specified name not found.
93 // Create policy via factory.
94 return factory->CreateLoadBalancingPolicy(std::move(args));
97 bool LoadBalancingPolicyRegistry::LoadBalancingPolicyExists(
98 const char* name, bool* requires_config) {
99 GPR_ASSERT(g_state != nullptr);
100 auto* factory = g_state->GetLoadBalancingPolicyFactory(name);
101 if (factory == nullptr) {
104 if (requires_config != nullptr) {
105 grpc_error* error = GRPC_ERROR_NONE;
106 // Check if the load balancing policy allows an empty config
108 factory->ParseLoadBalancingConfig(nullptr, &error) == nullptr;
109 GRPC_ERROR_UNREF(error);
115 // Returns the JSON node of policy (with both policy name and config content)
116 // given the JSON node of a LoadBalancingConfig array.
117 grpc_json* ParseLoadBalancingConfigHelper(const grpc_json* lb_config_array,
118 grpc_error** error) {
119 GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
121 if (lb_config_array == nullptr || lb_config_array->type != GRPC_JSON_ARRAY) {
122 gpr_asprintf(&error_msg, "field:%s error:type should be array",
123 lb_config_array->key);
124 *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
128 const char* field_name = lb_config_array->key;
129 // Find the first LB policy that this client supports.
130 for (const grpc_json* lb_config = lb_config_array->child;
131 lb_config != nullptr; lb_config = lb_config->next) {
132 if (lb_config->type != GRPC_JSON_OBJECT) {
133 gpr_asprintf(&error_msg,
134 "field:%s error:child entry should be of type object",
136 *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
140 grpc_json* policy = nullptr;
141 for (grpc_json* field = lb_config->child; field != nullptr;
142 field = field->next) {
143 if (field->key == nullptr || field->type != GRPC_JSON_OBJECT) {
144 gpr_asprintf(&error_msg,
145 "field:%s error:child entry should be of type object",
147 *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
151 if (policy != nullptr) {
152 gpr_asprintf(&error_msg, "field:%s error:oneOf violation", field_name);
153 *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
156 } // Violate "oneof" type.
159 if (policy == nullptr) {
160 gpr_asprintf(&error_msg, "field:%s error:no policy found in child entry",
162 *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
166 // If we support this policy, then select it.
167 if (LoadBalancingPolicyRegistry::LoadBalancingPolicyExists(policy->key,
172 gpr_asprintf(&error_msg, "field:%s error:No known policy", field_name);
173 *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
179 RefCountedPtr<LoadBalancingPolicy::Config>
180 LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(const grpc_json* json,
181 grpc_error** error) {
182 GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
183 GPR_ASSERT(g_state != nullptr);
184 const grpc_json* policy = ParseLoadBalancingConfigHelper(json, error);
185 if (policy == nullptr) {
188 GPR_DEBUG_ASSERT(*error == GRPC_ERROR_NONE && json != nullptr);
190 LoadBalancingPolicyFactory* factory =
191 g_state->GetLoadBalancingPolicyFactory(policy->key);
192 if (factory == nullptr) {
194 gpr_asprintf(&msg, "field:%s error:Factory not found to create policy",
196 *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
200 // Parse load balancing config via factory.
201 return factory->ParseLoadBalancingConfig(policy, error);
205 } // namespace grpc_core