1 /* 2 * Copyright 2023 The gRPC Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package io.grpc.xds; 18 19 import com.google.common.annotations.VisibleForTesting; 20 import io.grpc.Deadline; 21 import io.grpc.ExperimentalApi; 22 import io.grpc.Internal; 23 import io.grpc.LoadBalancer; 24 import io.grpc.LoadBalancer.Helper; 25 import io.grpc.LoadBalancerProvider; 26 import io.grpc.NameResolver.ConfigOrError; 27 import io.grpc.Status; 28 import io.grpc.internal.JsonUtil; 29 import io.grpc.xds.WeightedRoundRobinLoadBalancer.WeightedRoundRobinLoadBalancerConfig; 30 import java.util.Map; 31 32 /** 33 * Provides a {@link WeightedRoundRobinLoadBalancer}. 34 * */ 35 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/9885") 36 @Internal 37 public final class WeightedRoundRobinLoadBalancerProvider extends LoadBalancerProvider { 38 39 @VisibleForTesting 40 static final long MIN_WEIGHT_UPDATE_PERIOD_NANOS = 100_000_000L; // 100ms 41 42 static final String SCHEME = "weighted_round_robin"; 43 44 @Override newLoadBalancer(Helper helper)45 public LoadBalancer newLoadBalancer(Helper helper) { 46 return new WeightedRoundRobinLoadBalancer(helper, Deadline.getSystemTicker()); 47 } 48 49 @Override isAvailable()50 public boolean isAvailable() { 51 return true; 52 } 53 54 @Override getPriority()55 public int getPriority() { 56 return 5; 57 } 58 59 @Override getPolicyName()60 public String getPolicyName() { 61 return SCHEME; 62 } 63 64 @Override parseLoadBalancingPolicyConfig(Map<String, ?> rawConfig)65 public ConfigOrError parseLoadBalancingPolicyConfig(Map<String, ?> rawConfig) { 66 try { 67 return parseLoadBalancingPolicyConfigInternal(rawConfig); 68 } catch (RuntimeException e) { 69 return ConfigOrError.fromError( 70 Status.UNAVAILABLE.withCause(e).withDescription( 71 "Failed parsing configuration for " + getPolicyName())); 72 } 73 } 74 parseLoadBalancingPolicyConfigInternal(Map<String, ?> rawConfig)75 private ConfigOrError parseLoadBalancingPolicyConfigInternal(Map<String, ?> rawConfig) { 76 Long blackoutPeriodNanos = JsonUtil.getStringAsDuration(rawConfig, "blackoutPeriod"); 77 Long weightExpirationPeriodNanos = 78 JsonUtil.getStringAsDuration(rawConfig, "weightExpirationPeriod"); 79 Long oobReportingPeriodNanos = JsonUtil.getStringAsDuration(rawConfig, "oobReportingPeriod"); 80 Boolean enableOobLoadReport = JsonUtil.getBoolean(rawConfig, "enableOobLoadReport"); 81 Long weightUpdatePeriodNanos = JsonUtil.getStringAsDuration(rawConfig, "weightUpdatePeriod"); 82 Float errorUtilizationPenalty = JsonUtil.getNumberAsFloat(rawConfig, "errorUtilizationPenalty"); 83 84 WeightedRoundRobinLoadBalancerConfig.Builder configBuilder = 85 WeightedRoundRobinLoadBalancerConfig.newBuilder(); 86 if (blackoutPeriodNanos != null) { 87 configBuilder.setBlackoutPeriodNanos(blackoutPeriodNanos); 88 } 89 if (weightExpirationPeriodNanos != null) { 90 configBuilder.setWeightExpirationPeriodNanos(weightExpirationPeriodNanos); 91 } 92 if (enableOobLoadReport != null) { 93 configBuilder.setEnableOobLoadReport(enableOobLoadReport); 94 } 95 if (oobReportingPeriodNanos != null) { 96 configBuilder.setOobReportingPeriodNanos(oobReportingPeriodNanos); 97 } 98 if (weightUpdatePeriodNanos != null) { 99 configBuilder.setWeightUpdatePeriodNanos(weightUpdatePeriodNanos); 100 if (weightUpdatePeriodNanos < MIN_WEIGHT_UPDATE_PERIOD_NANOS) { 101 configBuilder.setWeightUpdatePeriodNanos(MIN_WEIGHT_UPDATE_PERIOD_NANOS); 102 } 103 } 104 if (errorUtilizationPenalty != null) { 105 configBuilder.setErrorUtilizationPenalty(errorUtilizationPenalty); 106 } 107 return ConfigOrError.fromConfig(configBuilder.build()); 108 } 109 } 110