Skip to content

Commit 163464c

Browse files
committed
Merge remote-tracking branch 'upstream/master' into fix/xds-resolver-close-drop-field-refs
# Conflicts: # internal/xds/resolver/xds_resolver.go
2 parents 32418c1 + 6d697e4 commit 163464c

163 files changed

Lines changed: 9375 additions & 2468 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CONTRIBUTING.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,29 @@ wanted"](https://github.com/grpc/grpc-go/issues?q=sort%3Aupdated-desc%20is%3Aiss
2323
are especially nice for first-time contributors, as they should be well-defined
2424
problems that already have agreed-upon solutions.
2525

26+
## Generative AI Policy
27+
28+
AI tools have the ability to produce more code than is possible for the gRPC
29+
team to read, understand, review, and accept into the repository. For this
30+
reason, we request that all contributions adhere to the following rules:
31+
32+
1. **No AI-Generated Interactions:** All communication in the repo must be
33+
authored by a human. _Exception: AIs may be used for directed writing
34+
assistance or translation._ Absolutely no automated agents are allowed to
35+
directly publish to GitHub.
36+
37+
2. **Author Ownership and Accountability:** Code contributions are expected to
38+
be fully owned and understood by the human contributor. If the code was
39+
produced by generative AI, the author is expected to have reviewed and
40+
understood it in its entirety before submitting it for review. This includes
41+
all content: production code, tests, examples, tools, etc.
42+
43+
In addition to the above requirements, any AI-assisted contributions must also
44+
comply with the [Linux Foundation Generative AI
45+
Policy](https://www.linuxfoundation.org/legal/generative-ai). This includes
46+
confirming that all contributions are legally allowed to be contributed to the
47+
gRPC project under the applicable license terms.
48+
2649
## Code Style
2750

2851
We follow [Google's published Go style
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
*
3+
* Copyright 2026 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 autosharding implements the autosharding load balancing policy.
20+
package autosharding
21+
22+
import (
23+
"encoding/json"
24+
"fmt"
25+
"time"
26+
27+
"google.golang.org/grpc/balancer"
28+
iserviceconfig "google.golang.org/grpc/internal/serviceconfig"
29+
"google.golang.org/grpc/serviceconfig"
30+
)
31+
32+
// Name is the name of the autosharding balancer.
33+
const Name = "autosharding_experimental"
34+
35+
func init() {
36+
balancer.Register(bb{})
37+
}
38+
39+
// lbConfig is the balancer config for the autosharding balancer.
40+
type lbConfig struct {
41+
serviceconfig.LoadBalancingConfig `json:"-"`
42+
43+
ChannelFactoryKey string `json:"channelFactoryKey,omitempty"`
44+
AutoShardingTarget string `json:"autoshardingTarget,omitempty"`
45+
KeyHeaderName string `json:"keyHeaderName,omitempty"`
46+
EnableFallback bool `json:"enableFallback,omitempty"`
47+
InitialAssignmentTimeout iserviceconfig.Duration `json:"initialAssignmentTimeout,omitempty"`
48+
}
49+
50+
type bb struct{}
51+
52+
func (bb) Name() string {
53+
return Name
54+
}
55+
56+
func (bb) ParseConfig(s json.RawMessage) (serviceconfig.LoadBalancingConfig, error) {
57+
lbConfig := &lbConfig{InitialAssignmentTimeout: iserviceconfig.Duration(60 * time.Second)}
58+
if err := json.Unmarshal(s, lbConfig); err != nil {
59+
return nil, fmt.Errorf("autosharding: unable to unmarshal LBConfig: %v", err)
60+
}
61+
if lbConfig.ChannelFactoryKey == "" {
62+
return nil, fmt.Errorf("autosharding: channelFactoryKey field is required")
63+
}
64+
if lbConfig.AutoShardingTarget == "" {
65+
return nil, fmt.Errorf("autosharding: autoshardingTarget field is required")
66+
}
67+
if lbConfig.KeyHeaderName == "" {
68+
return nil, fmt.Errorf("autosharding: keyHeaderName field is required")
69+
}
70+
return lbConfig, nil
71+
}
72+
73+
func (bb) Build(balancer.ClientConn, balancer.BuildOptions) balancer.Balancer {
74+
return &autoshardingBalancer{}
75+
}
76+
77+
type autoshardingBalancer struct {
78+
balancer.Balancer
79+
}
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/*
2+
*
3+
* Copyright 2026 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 autosharding
20+
21+
import (
22+
"encoding/json"
23+
"testing"
24+
"time"
25+
26+
"github.com/google/go-cmp/cmp"
27+
"google.golang.org/grpc/internal/grpctest"
28+
iserviceconfig "google.golang.org/grpc/internal/serviceconfig"
29+
"google.golang.org/grpc/serviceconfig"
30+
)
31+
32+
type s struct {
33+
grpctest.Tester
34+
}
35+
36+
func Test(t *testing.T) {
37+
grpctest.RunSubTests(t, s{})
38+
}
39+
40+
func (s) TestParseConfig_Success(t *testing.T) {
41+
parser := bb{}
42+
tests := []struct {
43+
name string
44+
input string
45+
wantCfg serviceconfig.LoadBalancingConfig
46+
}{
47+
{
48+
name: "all-fields",
49+
input: `{
50+
"channelFactoryKey": "factory-key",
51+
"autoshardingTarget": "target",
52+
"keyHeaderName": "header",
53+
"enableFallback": true,
54+
"initialAssignmentTimeout": "30s"
55+
}`,
56+
wantCfg: &lbConfig{
57+
ChannelFactoryKey: "factory-key",
58+
AutoShardingTarget: "target",
59+
KeyHeaderName: "header",
60+
EnableFallback: true,
61+
InitialAssignmentTimeout: iserviceconfig.Duration(30 * time.Second),
62+
},
63+
},
64+
{
65+
name: "default-timeout",
66+
input: `{
67+
"channelFactoryKey": "factory-key",
68+
"autoshardingTarget": "target",
69+
"keyHeaderName": "header"
70+
}`,
71+
wantCfg: &lbConfig{
72+
ChannelFactoryKey: "factory-key",
73+
AutoShardingTarget: "target",
74+
KeyHeaderName: "header",
75+
InitialAssignmentTimeout: iserviceconfig.Duration(60 * time.Second),
76+
},
77+
},
78+
}
79+
for _, test := range tests {
80+
t.Run(test.name, func(t *testing.T) {
81+
gotCfg, err := parser.ParseConfig(json.RawMessage(test.input))
82+
if err != nil {
83+
t.Fatalf("ParseConfig() error = %v, want nil", err)
84+
}
85+
if diff := cmp.Diff(test.wantCfg, gotCfg); diff != "" {
86+
t.Errorf("ParseConfig() config diff (-want +got):\n%s", diff)
87+
}
88+
})
89+
}
90+
}
91+
92+
func (s) TestParseConfig_Failure(t *testing.T) {
93+
parser := bb{}
94+
tests := []struct {
95+
name string
96+
input string
97+
}{
98+
{
99+
name: "invalid-json",
100+
input: "{{invalidjson{{",
101+
},
102+
{
103+
name: "invalid-duration",
104+
input: `{
105+
"channelFactoryKey": "factory-key",
106+
"autoshardingTarget": "target",
107+
"keyHeaderName": "header",
108+
"initialAssignmentTimeout": "invalid"
109+
}`,
110+
},
111+
{
112+
name: "missing-channel-factory-key",
113+
input: `{
114+
"autoshardingTarget": "target",
115+
"keyHeaderName": "header"
116+
}`,
117+
},
118+
{
119+
name: "missing-autosharding-target",
120+
input: `{
121+
"channelFactoryKey": "factory-key",
122+
"keyHeaderName": "header"
123+
}`,
124+
},
125+
{
126+
name: "missing-key-header-name",
127+
input: `{
128+
"channelFactoryKey": "factory-key",
129+
"autoshardingTarget": "target"
130+
}`,
131+
},
132+
{
133+
name: "empty-config",
134+
input: `{}`,
135+
},
136+
}
137+
for _, test := range tests {
138+
t.Run(test.name, func(t *testing.T) {
139+
if _, err := parser.ParseConfig(json.RawMessage(test.input)); err == nil {
140+
t.Fatalf("ParseConfig() succeeded, want error")
141+
}
142+
})
143+
}
144+
}

0 commit comments

Comments
 (0)