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);
120 if (lb_config_array == nullptr) {
122 GRPC_ERROR_CREATE_FROM_STATIC_STRING("LB config JSON tree is null");
126 if (lb_config_array->type != GRPC_JSON_ARRAY) {
127 gpr_asprintf(&error_msg, "field:%s error:type should be array",
128 lb_config_array->key);
129 *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
133 const char* field_name = lb_config_array->key;
134 // Find the first LB policy that this client supports.
135 for (const grpc_json* lb_config = lb_config_array->child;
136 lb_config != nullptr; lb_config = lb_config->next) {
137 if (lb_config->type != GRPC_JSON_OBJECT) {
138 gpr_asprintf(&error_msg,
139 "field:%s error:child entry should be of type object",
141 *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
145 grpc_json* policy = nullptr;
146 for (grpc_json* field = lb_config->child; field != nullptr;
147 field = field->next) {
148 if (field->key == nullptr || field->type != GRPC_JSON_OBJECT) {
149 gpr_asprintf(&error_msg,
150 "field:%s error:child entry should be of type object",
152 *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
156 if (policy != nullptr) {
157 gpr_asprintf(&error_msg, "field:%s error:oneOf violation", field_name);
158 *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
161 } // Violate "oneof" type.
164 if (policy == nullptr) {
165 gpr_asprintf(&error_msg, "field:%s error:no policy found in child entry",
167 *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
171 // If we support this policy, then select it.
172 if (LoadBalancingPolicyRegistry::LoadBalancingPolicyExists(policy->key,
177 gpr_asprintf(&error_msg, "field:%s error:No known policy", field_name);
178 *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
184 RefCountedPtr<LoadBalancingPolicy::Config>
185 LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(const grpc_json* json,
186 grpc_error** error) {
187 GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
188 GPR_ASSERT(g_state != nullptr);
189 const grpc_json* policy = ParseLoadBalancingConfigHelper(json, error);
190 if (policy == nullptr) {
193 GPR_DEBUG_ASSERT(*error == GRPC_ERROR_NONE && json != nullptr);
195 LoadBalancingPolicyFactory* factory =
196 g_state->GetLoadBalancingPolicyFactory(policy->key);
197 if (factory == nullptr) {
199 gpr_asprintf(&msg, "field:%s error:Factory not found to create policy",
201 *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
205 // Parse load balancing config via factory.
206 return factory->ParseLoadBalancingConfig(policy, error);
210 } // namespace grpc_core