• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

grpc / grpc-java / #20160

28 Jan 2026 12:21AM UTC coverage: 88.71% (+0.04%) from 88.666%
#20160

push

github

ejona86
xds: Normalize weights before combining endpoint and locality weights

Previously, the number of endpoints in a locality would skew how much
traffic was sent to that locality. Also, if endpoints in localities had
wildly different weights, that would impact cross-locality weighting.

For example, consider:
  LocalityA weight=1 endpointWeights=[100, 100, 100, 100]
  LocalityB weight=1 endpointWeights=[1]

The endpoint in LocalityB should have an endpoint weight that is half
the total sum of endpoint weights, in order to receive half the traffic.
But the multiple endpoints in LocalityA would cause it to get 4x the
traffic and the endpoint weights in LocalityA causes them to get 100x
the traffic.

See gRFC A113

35415 of 39922 relevant lines covered (88.71%)

0.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.29
/../api/src/main/java/io/grpc/EquivalentAddressGroup.java
1
/*
2
 * Copyright 2015 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;
18

19
import com.google.common.base.Preconditions;
20
import java.lang.annotation.Documented;
21
import java.lang.annotation.Retention;
22
import java.lang.annotation.RetentionPolicy;
23
import java.net.SocketAddress;
24
import java.util.ArrayList;
25
import java.util.Collections;
26
import java.util.List;
27

28
/**
29
 * A group of {@link SocketAddress}es that are considered equivalent when channel makes connections.
30
 *
31
 * <p>Usually the addresses are addresses resolved from the same host name, and connecting to any of
32
 * them is equally sufficient. They do have order. An address appears earlier on the list is likely
33
 * to be tried earlier.
34
 */
35
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1770")
36
public final class EquivalentAddressGroup {
37

38
  /**
39
   * The authority to be used when constructing Subchannels for this EquivalentAddressGroup.
40
   * However, if the channel has overridden authority via
41
   * {@link ManagedChannelBuilder#overrideAuthority(String)}, the transport will use the channel's
42
   * authority override.
43
   *
44
   * <p>The authority <strong>must</strong> be from a trusted source, because if the authority is
45
   * tampered with, RPCs may be sent to attackers which may leak sensitive user data. If the
46
   * authority was acquired by doing I/O, the communication must be authenticated (e.g., via TLS).
47
   * Recognize that the server that provided the authority can trivially impersonate the service.
48
   */
49
  @Attr
50
  @ExperimentalApi("https://github.com/grpc/grpc-java/issues/6138")
51
  public static final Attributes.Key<String> ATTR_AUTHORITY_OVERRIDE =
1✔
52
      Attributes.Key.create("io.grpc.EquivalentAddressGroup.ATTR_AUTHORITY_OVERRIDE");
1✔
53
  /**
54
   * The name of the locality that this EquivalentAddressGroup is in.
55
   */
56
  public static final Attributes.Key<String> ATTR_LOCALITY_NAME =
1✔
57
      Attributes.Key.create("io.grpc.EquivalentAddressGroup.LOCALITY");
1✔
58
  /**
59
   * Endpoint weight for load balancing purposes. While the type is Long, it must be a valid uint32.
60
   * Must not be zero. The weight is proportional to the other endpoints; if an endpoint's weight is
61
   * twice that of another endpoint, it is intended to receive twice the load.
62
   */
63
  @Attr
64
  static final Attributes.Key<Long> ATTR_WEIGHT =
1✔
65
      Attributes.Key.create("io.grpc.EquivalentAddressGroup.ATTR_WEIGHT");
1✔
66

67
  private final List<SocketAddress> addrs;
68
  private final Attributes attrs;
69

70
  /**
71
   * {@link SocketAddress} docs say that the addresses are immutable, so we cache the hashCode.
72
   */
73
  private final int hashCode;
74

75
  /**
76
   * List constructor without {@link Attributes}.
77
   */
78
  public EquivalentAddressGroup(List<SocketAddress> addrs) {
79
    this(addrs, Attributes.EMPTY);
1✔
80
  }
1✔
81

82
  /**
83
   * List constructor with {@link Attributes}.
84
   */
85
  public EquivalentAddressGroup(List<SocketAddress> addrs, @Attr Attributes attrs) {
1✔
86
    Preconditions.checkArgument(!addrs.isEmpty(), "addrs is empty");
1✔
87
    this.addrs = Collections.unmodifiableList(new ArrayList<>(addrs));
1✔
88
    this.attrs = Preconditions.checkNotNull(attrs, "attrs");
1✔
89
    // Attributes may contain mutable objects, which means Attributes' hashCode may change over
90
    // time, thus we don't cache Attributes' hashCode.
91
    hashCode = this.addrs.hashCode();
1✔
92
  }
1✔
93

94
  /**
95
   * Singleton constructor without Attributes.
96
   */
97
  public EquivalentAddressGroup(SocketAddress addr) {
98
    this(addr, Attributes.EMPTY);
1✔
99
  }
1✔
100

101
  /**
102
   * Singleton constructor with Attributes.
103
   */
104
  public EquivalentAddressGroup(SocketAddress addr, @Attr Attributes attrs) {
105
    this(Collections.singletonList(addr), attrs);
1✔
106
  }
1✔
107

108
  /**
109
   * Returns an immutable list of the addresses.
110
   */
111
  public List<SocketAddress> getAddresses() {
112
    return addrs;
1✔
113
  }
114

115
  /**
116
   * Returns the attributes.
117
   */
118
  @Attr
119
  public Attributes getAttributes() {
120
    return attrs;
1✔
121
  }
122

123
  @Override
124
  public String toString() {
125
    // TODO(zpencer): Summarize return value if addr is very large
126
    return "[" + addrs + "/" + attrs + "]";
1✔
127
  }
128

129
  @Override
130
  public int hashCode() {
131
    // Avoids creating an iterator on the underlying array list.
132
    return hashCode;
1✔
133
  }
134

135
  /**
136
   * Returns true if the given object is also an {@link EquivalentAddressGroup} with an equal
137
   * address list and equal attribute values.
138
   *
139
   * <p>Note that if the attributes include mutable values, it is possible for two objects to be
140
   * considered equal at one point in time and not equal at another (due to concurrent mutation of
141
   * attribute values).
142
   */
143
  @Override
144
  public boolean equals(Object other) {
145
    if (this == other) {
1✔
146
      return true;
1✔
147
    }
148
    if (!(other instanceof EquivalentAddressGroup)) {
1✔
149
      return false;
×
150
    }
151
    EquivalentAddressGroup that = (EquivalentAddressGroup) other;
1✔
152
    if (addrs.size() != that.addrs.size()) {
1✔
153
      return false;
×
154
    }
155
    // Avoids creating an iterator on the underlying array list.
156
    for (int i = 0; i < addrs.size(); i++) {
1✔
157
      if (!addrs.get(i).equals(that.addrs.get(i))) {
1✔
158
        return false;
1✔
159
      }
160
    }
161
    if (!attrs.equals(that.attrs)) {
1✔
162
      return false;
1✔
163
    }
164
    return true;
1✔
165
  }
166

167
  /**
168
   * Annotation for {@link EquivalentAddressGroup}'s attributes. It follows the annotation semantics
169
   * defined by {@link Attributes}.
170
   */
171
  @ExperimentalApi("https://github.com/grpc/grpc-java/issues/4972")
172
  @Retention(RetentionPolicy.SOURCE)
173
  @Documented
174
  public @interface Attr {}
175
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc