Skip to content

Commit 42fc25a

Browse files
authored
weightedroundrobin: Move functions to manage Endpoint weights into a new internal package (#8087)
1 parent 607565d commit 42fc25a

File tree

10 files changed

+171
-181
lines changed

10 files changed

+171
-181
lines changed

balancer/weightedroundrobin/balancer.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@
1616
*
1717
*/
1818

19+
// Package weightedroundrobin provides an implementation of the weighted round
20+
// robin LB policy, as defined in [gRFC A58].
21+
//
22+
// # Experimental
23+
//
24+
// Notice: This package is EXPERIMENTAL and may be changed or removed in a
25+
// later release.
26+
//
27+
// [gRFC A58]: https://github.com/grpc/proposal/blob/master/A58-client-side-weighted-round-robin-lb-policy.md
1928
package weightedroundrobin
2029

2130
import (

balancer/weightedroundrobin/weightedroundrobin.go

Lines changed: 0 additions & 85 deletions
This file was deleted.

balancer/weightedroundrobin/weightedroundrobin_test.go

Lines changed: 0 additions & 82 deletions
This file was deleted.

internal/balancer/weight/weight.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
*
3+
* Copyright 2025 gRPC authors.
4+
*
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
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
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.
16+
*
17+
*/
18+
19+
// Package weight contains utilities to manage endpoint weights. Weights are
20+
// used by LB policies such as ringhash to distribute load across multiple
21+
// endpoints.
22+
package weight
23+
24+
import (
25+
"fmt"
26+
27+
"google.golang.org/grpc/resolver"
28+
)
29+
30+
// attributeKey is the type used as the key to store EndpointInfo in the
31+
// Attributes field of resolver.Endpoint.
32+
type attributeKey struct{}
33+
34+
// EndpointInfo will be stored in the Attributes field of Endpoints in order to
35+
// use the ringhash balancer.
36+
type EndpointInfo struct {
37+
Weight uint32
38+
}
39+
40+
// Equal allows the values to be compared by Attributes.Equal.
41+
func (a EndpointInfo) Equal(o any) bool {
42+
oa, ok := o.(EndpointInfo)
43+
return ok && oa.Weight == a.Weight
44+
}
45+
46+
// Set returns a copy of endpoint in which the Attributes field is updated with
47+
// EndpointInfo.
48+
func Set(endpoint resolver.Endpoint, epInfo EndpointInfo) resolver.Endpoint {
49+
endpoint.Attributes = endpoint.Attributes.WithValue(attributeKey{}, epInfo)
50+
return endpoint
51+
}
52+
53+
// String returns a human-readable representation of EndpointInfo.
54+
// This method is intended for logging, testing, and debugging purposes only.
55+
// Do not rely on the output format, as it is not guaranteed to remain stable.
56+
func (a EndpointInfo) String() string {
57+
return fmt.Sprintf("Weight: %d", a.Weight)
58+
}
59+
60+
// FromEndpoint returns the EndpointInfo stored in the Attributes field of an
61+
// endpoint. It returns an empty EndpointInfo if attribute is not found.
62+
func FromEndpoint(endpoint resolver.Endpoint) EndpointInfo {
63+
v := endpoint.Attributes.Value(attributeKey{})
64+
ei, _ := v.(EndpointInfo)
65+
return ei
66+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
*
3+
* Copyright 2025 gRPC authors.
4+
*
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
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
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.
16+
*
17+
*/
18+
19+
package weight_test
20+
21+
import (
22+
"testing"
23+
24+
"github.com/google/go-cmp/cmp"
25+
"google.golang.org/grpc/attributes"
26+
"google.golang.org/grpc/internal/balancer/weight"
27+
"google.golang.org/grpc/internal/grpctest"
28+
"google.golang.org/grpc/resolver"
29+
)
30+
31+
type s struct {
32+
grpctest.Tester
33+
}
34+
35+
func Test(t *testing.T) {
36+
grpctest.RunSubTests(t, s{})
37+
}
38+
39+
func (s) TestEndpointInfoToAndFromAttributes(t *testing.T) {
40+
tests := []struct {
41+
desc string
42+
inputEndpointInfo weight.EndpointInfo
43+
inputAttributes *attributes.Attributes
44+
wantEndpointInfo weight.EndpointInfo
45+
}{
46+
{
47+
desc: "empty_attributes",
48+
inputEndpointInfo: weight.EndpointInfo{Weight: 100},
49+
inputAttributes: nil,
50+
wantEndpointInfo: weight.EndpointInfo{Weight: 100},
51+
},
52+
{
53+
desc: "non-empty_attributes",
54+
inputEndpointInfo: weight.EndpointInfo{Weight: 100},
55+
inputAttributes: attributes.New("foo", "bar"),
56+
wantEndpointInfo: weight.EndpointInfo{Weight: 100},
57+
},
58+
{
59+
desc: "endpointInfo_not_present_in_empty_attributes",
60+
inputEndpointInfo: weight.EndpointInfo{},
61+
inputAttributes: nil,
62+
wantEndpointInfo: weight.EndpointInfo{},
63+
},
64+
{
65+
desc: "endpointInfo_not_present_in_non-empty_attributes",
66+
inputEndpointInfo: weight.EndpointInfo{},
67+
inputAttributes: attributes.New("foo", "bar"),
68+
wantEndpointInfo: weight.EndpointInfo{},
69+
},
70+
}
71+
72+
for _, test := range tests {
73+
t.Run(test.desc, func(t *testing.T) {
74+
endpoint := resolver.Endpoint{Attributes: test.inputAttributes}
75+
endpoint = weight.Set(endpoint, test.inputEndpointInfo)
76+
gotEndpointInfo := weight.FromEndpoint(endpoint)
77+
if !cmp.Equal(gotEndpointInfo, test.wantEndpointInfo) {
78+
t.Errorf("gotEndpointInfo: %v, wantEndpointInfo: %v", gotEndpointInfo, test.wantEndpointInfo)
79+
}
80+
81+
})
82+
}
83+
}

xds/internal/balancer/clusterresolver/configbuilder.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323
"fmt"
2424
"sort"
2525

26-
"google.golang.org/grpc/balancer/weightedroundrobin"
26+
"google.golang.org/grpc/internal/balancer/weight"
2727
"google.golang.org/grpc/internal/hierarchy"
2828
internalserviceconfig "google.golang.org/grpc/internal/serviceconfig"
2929
"google.golang.org/grpc/resolver"
@@ -281,7 +281,7 @@ func priorityLocalitiesToClusterImpl(localities []xdsresource.Locality, priority
281281
if endpoint.Weight != 0 {
282282
ew = endpoint.Weight
283283
}
284-
resolverEndpoint = weightedroundrobin.SetAddrInfoInEndpoint(resolverEndpoint, weightedroundrobin.AddrInfo{Weight: lw * ew})
284+
resolverEndpoint = weight.Set(resolverEndpoint, weight.EndpointInfo{Weight: lw * ew})
285285
retEndpoints = append(retEndpoints, resolverEndpoint)
286286
}
287287
}

xds/internal/balancer/clusterresolver/configbuilder_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import (
3030
"google.golang.org/grpc/attributes"
3131
"google.golang.org/grpc/balancer"
3232
"google.golang.org/grpc/balancer/roundrobin"
33-
"google.golang.org/grpc/balancer/weightedroundrobin"
33+
"google.golang.org/grpc/internal/balancer/weight"
3434
"google.golang.org/grpc/internal/hierarchy"
3535
iserviceconfig "google.golang.org/grpc/internal/serviceconfig"
3636
"google.golang.org/grpc/internal/xds/bootstrap"
@@ -653,7 +653,7 @@ func testEndpointWithAttrs(addrStrs []string, localityWeight, endpointWeight uin
653653
}
654654
endpoint = hierarchy.SetInEndpoint(endpoint, path)
655655
endpoint = wrrlocality.SetAddrInfoInEndpoint(endpoint, wrrlocality.AddrInfo{LocalityWeight: localityWeight})
656-
endpoint = weightedroundrobin.SetAddrInfoInEndpoint(endpoint, weightedroundrobin.AddrInfo{Weight: localityWeight * endpointWeight})
656+
endpoint = weight.Set(endpoint, weight.EndpointInfo{Weight: localityWeight * endpointWeight})
657657
return endpoint
658658
}
659659

xds/internal/balancer/ringhash/ring_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@ import (
2323
"math"
2424
"testing"
2525

26-
xxhash "github.com/cespare/xxhash/v2"
27-
"google.golang.org/grpc/balancer/weightedroundrobin"
26+
"google.golang.org/grpc/internal/balancer/weight"
2827
"google.golang.org/grpc/resolver"
28+
29+
xxhash "github.com/cespare/xxhash/v2"
2930
)
3031

3132
var testEndpoints []resolver.Endpoint
@@ -43,9 +44,9 @@ func init() {
4344
testEndpointStateMap.Set(testEndpoints[2], &endpointState{firstAddr: "c", weight: 4})
4445
}
4546

46-
func testEndpoint(addr string, weight uint32) resolver.Endpoint {
47+
func testEndpoint(addr string, endpointWeight uint32) resolver.Endpoint {
4748
ep := resolver.Endpoint{Addresses: []resolver.Address{{Addr: addr}}}
48-
return weightedroundrobin.SetAddrInfoInEndpoint(ep, weightedroundrobin.AddrInfo{Weight: weight})
49+
return weight.Set(ep, weight.EndpointInfo{Weight: endpointWeight})
4950
}
5051

5152
func (s) TestRingNew(t *testing.T) {

0 commit comments

Comments
 (0)