• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 import static com.google.common.base.Preconditions.checkState;
21 
22 import com.google.common.annotations.VisibleForTesting;
23 import com.google.common.base.Stopwatch;
24 import io.grpc.Attributes;
25 import io.grpc.ChannelLogger.ChannelLogLevel;
26 import io.grpc.Context;
27 import io.grpc.EquivalentAddressGroup;
28 import io.grpc.LoadBalancer;
29 import io.grpc.Status;
30 import io.grpc.grpclb.GrpclbState.Mode;
31 import io.grpc.internal.BackoffPolicy;
32 import io.grpc.internal.TimeProvider;
33 import java.util.ArrayList;
34 import java.util.Collections;
35 import java.util.List;
36 import javax.annotation.Nullable;
37 
38 /**
39  * A {@link LoadBalancer} that uses the GRPCLB protocol.
40  *
41  * <p>Optionally, when requested by the naming system, will delegate the work to a local pick-first
42  * or round-robin balancer.
43  */
44 class GrpclbLoadBalancer extends LoadBalancer {
45 
46   private static final GrpclbConfig DEFAULT_CONFIG = GrpclbConfig.create(Mode.ROUND_ROBIN);
47 
48   private final Helper helper;
49   private final Context context;
50   private final TimeProvider time;
51   private final Stopwatch stopwatch;
52   private final SubchannelPool subchannelPool;
53   private final BackoffPolicy.Provider backoffPolicyProvider;
54 
55   private GrpclbConfig config = DEFAULT_CONFIG;
56 
57   // All mutable states in this class are mutated ONLY from Channel Executor
58   @Nullable
59   private GrpclbState grpclbState;
60 
GrpclbLoadBalancer( Helper helper, Context context, SubchannelPool subchannelPool, TimeProvider time, Stopwatch stopwatch, BackoffPolicy.Provider backoffPolicyProvider)61   GrpclbLoadBalancer(
62       Helper helper,
63       Context context,
64       SubchannelPool subchannelPool,
65       TimeProvider time,
66       Stopwatch stopwatch,
67       BackoffPolicy.Provider backoffPolicyProvider) {
68     this.helper = checkNotNull(helper, "helper");
69     this.context = checkNotNull(context, "context");
70     this.time = checkNotNull(time, "time provider");
71     this.stopwatch = checkNotNull(stopwatch, "stopwatch");
72     this.backoffPolicyProvider = checkNotNull(backoffPolicyProvider, "backoffPolicyProvider");
73     this.subchannelPool = checkNotNull(subchannelPool, "subchannelPool");
74     recreateStates();
75     checkNotNull(grpclbState, "grpclbState");
76   }
77 
78   @Override
acceptResolvedAddresses(ResolvedAddresses resolvedAddresses)79   public boolean acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) {
80     Attributes attributes = resolvedAddresses.getAttributes();
81     List<EquivalentAddressGroup> newLbAddresses = attributes.get(GrpclbConstants.ATTR_LB_ADDRS);
82     if (newLbAddresses == null) {
83       newLbAddresses = Collections.emptyList();
84     }
85     if (newLbAddresses.isEmpty() && resolvedAddresses.getAddresses().isEmpty()) {
86       handleNameResolutionError(
87           Status.UNAVAILABLE.withDescription("No backend or balancer addresses found"));
88       return false;
89     }
90     List<EquivalentAddressGroup> overrideAuthorityLbAddresses =
91         new ArrayList<>(newLbAddresses.size());
92     for (EquivalentAddressGroup lbAddr : newLbAddresses) {
93       String lbAddrAuthority = lbAddr.getAttributes().get(GrpclbConstants.ATTR_LB_ADDR_AUTHORITY);
94       if (lbAddrAuthority == null) {
95         throw new AssertionError(
96             "This is a bug: LB address " + lbAddr + " does not have an authority.");
97       }
98       Attributes attrs = lbAddr.getAttributes().toBuilder()
99           .set(EquivalentAddressGroup.ATTR_AUTHORITY_OVERRIDE, lbAddrAuthority)
100           .build();
101       overrideAuthorityLbAddresses.add(new EquivalentAddressGroup(lbAddr.getAddresses(), attrs));
102     }
103 
104     List<EquivalentAddressGroup> newBackendServers =
105         Collections.unmodifiableList(resolvedAddresses.getAddresses());
106     GrpclbConfig newConfig = (GrpclbConfig) resolvedAddresses.getLoadBalancingPolicyConfig();
107     if (newConfig == null) {
108       newConfig = DEFAULT_CONFIG;
109     }
110     if (!config.equals(newConfig)) {
111       config = newConfig;
112       helper.getChannelLogger().log(ChannelLogLevel.INFO, "Config: " + newConfig);
113       recreateStates();
114     }
115     grpclbState.handleAddresses(Collections.unmodifiableList(overrideAuthorityLbAddresses),
116         newBackendServers);
117 
118     return true;
119   }
120 
121   @Override
requestConnection()122   public void requestConnection() {
123     if (grpclbState != null) {
124       grpclbState.requestConnection();
125     }
126   }
127 
resetStates()128   private void resetStates() {
129     if (grpclbState != null) {
130       grpclbState.shutdown();
131       grpclbState = null;
132     }
133   }
134 
recreateStates()135   private void recreateStates() {
136     resetStates();
137     checkState(grpclbState == null, "Should've been cleared");
138     grpclbState =
139         new GrpclbState(
140             config, helper, context, subchannelPool, time, stopwatch, backoffPolicyProvider);
141   }
142 
143   @Override
shutdown()144   public void shutdown() {
145     resetStates();
146   }
147 
148   @Override
handleNameResolutionError(Status error)149   public void handleNameResolutionError(Status error) {
150     if (grpclbState != null) {
151       grpclbState.propagateError(error);
152     }
153   }
154 
155   @Override
canHandleEmptyAddressListFromNameResolution()156   public boolean canHandleEmptyAddressListFromNameResolution() {
157     return true;
158   }
159 
160   @VisibleForTesting
161   @Nullable
getGrpclbState()162   GrpclbState getGrpclbState() {
163     return grpclbState;
164   }
165 }
166