1 /* 2 * Copyright 2016 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.grpclb; 18 19 import static com.google.common.base.Preconditions.checkNotNull; 20 21 import com.google.common.annotations.VisibleForTesting; 22 import io.grpc.Attributes; 23 import io.grpc.ConnectivityStateInfo; 24 import io.grpc.EquivalentAddressGroup; 25 import io.grpc.InternalLogId; 26 import io.grpc.InternalWithLogId; 27 import io.grpc.LoadBalancer; 28 import io.grpc.Status; 29 import io.grpc.internal.BackoffPolicy; 30 import io.grpc.internal.GrpcAttributes; 31 import io.grpc.internal.ObjectPool; 32 import io.grpc.internal.TimeProvider; 33 import java.util.ArrayList; 34 import java.util.Collections; 35 import java.util.List; 36 import java.util.concurrent.ScheduledExecutorService; 37 import javax.annotation.Nullable; 38 39 /** 40 * A {@link LoadBalancer} that uses the GRPCLB protocol. 41 * 42 * <p>Optionally, when requested by the naming system, will delegate the work to a local pick-first 43 * or round-robin balancer. 44 */ 45 class GrpclbLoadBalancer extends LoadBalancer implements InternalWithLogId { 46 47 private final InternalLogId logId = InternalLogId.allocate(getClass().getName()); 48 private final SubchannelPool subchannelPool; 49 private final ObjectPool<ScheduledExecutorService> timerServicePool; 50 51 // All mutable states in this class are mutated ONLY from Channel Executor 52 private ScheduledExecutorService timerService; 53 54 @Nullable 55 private GrpclbState grpclbState; 56 GrpclbLoadBalancer( Helper helper, SubchannelPool subchannelPool, ObjectPool<ScheduledExecutorService> timerServicePool, TimeProvider time, BackoffPolicy.Provider backoffPolicyProvider)57 GrpclbLoadBalancer( 58 Helper helper, 59 SubchannelPool subchannelPool, 60 ObjectPool<ScheduledExecutorService> timerServicePool, 61 TimeProvider time, 62 BackoffPolicy.Provider backoffPolicyProvider) { 63 checkNotNull(helper, "helper"); 64 this.timerServicePool = checkNotNull(timerServicePool, "timerServicePool"); 65 this.timerService = checkNotNull(timerServicePool.getObject(), "timerService"); 66 checkNotNull(time, "time provider"); 67 checkNotNull(backoffPolicyProvider, "backoffPolicyProvider"); 68 this.subchannelPool = checkNotNull(subchannelPool, "subchannelPool"); 69 this.subchannelPool.init(helper, timerService); 70 grpclbState = 71 new GrpclbState(helper, subchannelPool, time, timerService, backoffPolicyProvider, logId); 72 } 73 74 @Override getLogId()75 public InternalLogId getLogId() { 76 return logId; 77 } 78 79 @Override handleSubchannelState(Subchannel subchannel, ConnectivityStateInfo newState)80 public void handleSubchannelState(Subchannel subchannel, ConnectivityStateInfo newState) { 81 // grpclbState should never be null here since handleSubchannelState cannot be called while the 82 // lb is shutdown. 83 grpclbState.handleSubchannelState(subchannel, newState); 84 } 85 86 @Override handleResolvedAddressGroups( List<EquivalentAddressGroup> updatedServers, Attributes attributes)87 public void handleResolvedAddressGroups( 88 List<EquivalentAddressGroup> updatedServers, Attributes attributes) { 89 // LB addresses and backend addresses are treated separately 90 List<LbAddressGroup> newLbAddressGroups = new ArrayList<>(); 91 List<EquivalentAddressGroup> newBackendServers = new ArrayList<>(); 92 for (EquivalentAddressGroup server : updatedServers) { 93 String lbAddrAuthority = server.getAttributes().get(GrpcAttributes.ATTR_LB_ADDR_AUTHORITY); 94 if (lbAddrAuthority != null) { 95 newLbAddressGroups.add(new LbAddressGroup(server, lbAddrAuthority)); 96 } else { 97 newBackendServers.add(server); 98 } 99 } 100 101 newLbAddressGroups = Collections.unmodifiableList(newLbAddressGroups); 102 newBackendServers = Collections.unmodifiableList(newBackendServers); 103 grpclbState.handleAddresses(newLbAddressGroups, newBackendServers); 104 } 105 resetStates()106 private void resetStates() { 107 if (grpclbState != null) { 108 grpclbState.shutdown(); 109 grpclbState = null; 110 } 111 } 112 113 @Override shutdown()114 public void shutdown() { 115 resetStates(); 116 timerService = timerServicePool.returnObject(timerService); 117 } 118 119 @Override handleNameResolutionError(Status error)120 public void handleNameResolutionError(Status error) { 121 if (grpclbState != null) { 122 grpclbState.propagateError(error); 123 } 124 } 125 126 @VisibleForTesting 127 @Nullable getGrpclbState()128 GrpclbState getGrpclbState() { 129 return grpclbState; 130 } 131 } 132