mirror of https://github.com/knative/pkg.git
Bump google.golang.org/grpc from 1.64.0 to 1.65.0 (#3073)
* Bump google.golang.org/grpc from 1.64.0 to 1.65.0 Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.64.0 to 1.65.0. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.64.0...v1.65.0) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * Run ./hack/update-codegen.sh --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
parent
fe204d0869
commit
b4e5f07a2c
4
go.mod
4
go.mod
|
@ -28,7 +28,7 @@ require (
|
||||||
golang.org/x/sync v0.7.0
|
golang.org/x/sync v0.7.0
|
||||||
golang.org/x/tools v0.23.0
|
golang.org/x/tools v0.23.0
|
||||||
gomodules.xyz/jsonpatch/v2 v2.4.0
|
gomodules.xyz/jsonpatch/v2 v2.4.0
|
||||||
google.golang.org/grpc v1.64.0
|
google.golang.org/grpc v1.65.0
|
||||||
google.golang.org/protobuf v1.34.1
|
google.golang.org/protobuf v1.34.1
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
k8s.io/api v0.29.2
|
k8s.io/api v0.29.2
|
||||||
|
@ -45,7 +45,7 @@ require (
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||||
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
|
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
|
||||||
github.com/go-kit/log v0.2.1 // indirect
|
github.com/go-kit/log v0.2.1 // indirect
|
||||||
|
|
12
go.sum
12
go.sum
|
@ -63,8 +63,8 @@ github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMr
|
||||||
github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
|
github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
|
@ -126,8 +126,8 @@ github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68=
|
github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4=
|
||||||
github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
@ -657,8 +657,8 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji
|
||||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||||
google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
|
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
|
||||||
google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
|
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
|
|
@ -70,3 +70,5 @@ benchstat <(go test -benchtime 500ms -count 15 -bench 'Sum64$')
|
||||||
- [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics)
|
- [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics)
|
||||||
- [FreeCache](https://github.com/coocood/freecache)
|
- [FreeCache](https://github.com/coocood/freecache)
|
||||||
- [FastCache](https://github.com/VictoriaMetrics/fastcache)
|
- [FastCache](https://github.com/VictoriaMetrics/fastcache)
|
||||||
|
- [Ristretto](https://github.com/dgraph-io/ristretto)
|
||||||
|
- [Badger](https://github.com/dgraph-io/badger)
|
||||||
|
|
|
@ -19,10 +19,13 @@ const (
|
||||||
// Store the primes in an array as well.
|
// Store the primes in an array as well.
|
||||||
//
|
//
|
||||||
// The consts are used when possible in Go code to avoid MOVs but we need a
|
// The consts are used when possible in Go code to avoid MOVs but we need a
|
||||||
// contiguous array of the assembly code.
|
// contiguous array for the assembly code.
|
||||||
var primes = [...]uint64{prime1, prime2, prime3, prime4, prime5}
|
var primes = [...]uint64{prime1, prime2, prime3, prime4, prime5}
|
||||||
|
|
||||||
// Digest implements hash.Hash64.
|
// Digest implements hash.Hash64.
|
||||||
|
//
|
||||||
|
// Note that a zero-valued Digest is not ready to receive writes.
|
||||||
|
// Call Reset or create a Digest using New before calling other methods.
|
||||||
type Digest struct {
|
type Digest struct {
|
||||||
v1 uint64
|
v1 uint64
|
||||||
v2 uint64
|
v2 uint64
|
||||||
|
@ -33,19 +36,31 @@ type Digest struct {
|
||||||
n int // how much of mem is used
|
n int // how much of mem is used
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new Digest that computes the 64-bit xxHash algorithm.
|
// New creates a new Digest with a zero seed.
|
||||||
func New() *Digest {
|
func New() *Digest {
|
||||||
|
return NewWithSeed(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWithSeed creates a new Digest with the given seed.
|
||||||
|
func NewWithSeed(seed uint64) *Digest {
|
||||||
var d Digest
|
var d Digest
|
||||||
d.Reset()
|
d.ResetWithSeed(seed)
|
||||||
return &d
|
return &d
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset clears the Digest's state so that it can be reused.
|
// Reset clears the Digest's state so that it can be reused.
|
||||||
|
// It uses a seed value of zero.
|
||||||
func (d *Digest) Reset() {
|
func (d *Digest) Reset() {
|
||||||
d.v1 = primes[0] + prime2
|
d.ResetWithSeed(0)
|
||||||
d.v2 = prime2
|
}
|
||||||
d.v3 = 0
|
|
||||||
d.v4 = -primes[0]
|
// ResetWithSeed clears the Digest's state so that it can be reused.
|
||||||
|
// It uses the given seed to initialize the state.
|
||||||
|
func (d *Digest) ResetWithSeed(seed uint64) {
|
||||||
|
d.v1 = seed + prime1 + prime2
|
||||||
|
d.v2 = seed + prime2
|
||||||
|
d.v3 = seed
|
||||||
|
d.v4 = seed - prime1
|
||||||
d.total = 0
|
d.total = 0
|
||||||
d.n = 0
|
d.n = 0
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
package xxhash
|
package xxhash
|
||||||
|
|
||||||
// Sum64 computes the 64-bit xxHash digest of b.
|
// Sum64 computes the 64-bit xxHash digest of b with a zero seed.
|
||||||
//
|
//
|
||||||
//go:noescape
|
//go:noescape
|
||||||
func Sum64(b []byte) uint64
|
func Sum64(b []byte) uint64
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
package xxhash
|
package xxhash
|
||||||
|
|
||||||
// Sum64 computes the 64-bit xxHash digest of b.
|
// Sum64 computes the 64-bit xxHash digest of b with a zero seed.
|
||||||
func Sum64(b []byte) uint64 {
|
func Sum64(b []byte) uint64 {
|
||||||
// A simpler version would be
|
// A simpler version would be
|
||||||
// d := New()
|
// d := New()
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
package xxhash
|
package xxhash
|
||||||
|
|
||||||
// Sum64String computes the 64-bit xxHash digest of s.
|
// Sum64String computes the 64-bit xxHash digest of s with a zero seed.
|
||||||
func Sum64String(s string) uint64 {
|
func Sum64String(s string) uint64 {
|
||||||
return Sum64([]byte(s))
|
return Sum64([]byte(s))
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ import (
|
||||||
//
|
//
|
||||||
// See https://github.com/golang/go/issues/42739 for discussion.
|
// See https://github.com/golang/go/issues/42739 for discussion.
|
||||||
|
|
||||||
// Sum64String computes the 64-bit xxHash digest of s.
|
// Sum64String computes the 64-bit xxHash digest of s with a zero seed.
|
||||||
// It may be faster than Sum64([]byte(s)) by avoiding a copy.
|
// It may be faster than Sum64([]byte(s)) by avoiding a copy.
|
||||||
func Sum64String(s string) uint64 {
|
func Sum64String(s string) uint64 {
|
||||||
b := *(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)}))
|
b := *(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)}))
|
||||||
|
|
|
@ -10,7 +10,7 @@ RPC framework that puts mobile and HTTP/2 first. For more information see the
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
- **[Go][]**: any one of the **three latest major** [releases][go-releases].
|
- **[Go][]**: any one of the **two latest major** [releases][go-releases].
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|
|
@ -16,26 +16,36 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package grpc
|
// Package pickfirst contains the pick_first load balancing policy.
|
||||||
|
package pickfirst
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
|
||||||
"google.golang.org/grpc/balancer"
|
"google.golang.org/grpc/balancer"
|
||||||
"google.golang.org/grpc/connectivity"
|
"google.golang.org/grpc/connectivity"
|
||||||
|
"google.golang.org/grpc/grpclog"
|
||||||
|
"google.golang.org/grpc/internal"
|
||||||
internalgrpclog "google.golang.org/grpc/internal/grpclog"
|
internalgrpclog "google.golang.org/grpc/internal/grpclog"
|
||||||
"google.golang.org/grpc/internal/grpcrand"
|
|
||||||
"google.golang.org/grpc/internal/pretty"
|
"google.golang.org/grpc/internal/pretty"
|
||||||
"google.golang.org/grpc/resolver"
|
"google.golang.org/grpc/resolver"
|
||||||
"google.golang.org/grpc/serviceconfig"
|
"google.golang.org/grpc/serviceconfig"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
balancer.Register(pickfirstBuilder{})
|
||||||
|
internal.ShuffleAddressListForTesting = func(n int, swap func(i, j int)) { rand.Shuffle(n, swap) }
|
||||||
|
}
|
||||||
|
|
||||||
|
var logger = grpclog.Component("pick-first-lb")
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// PickFirstBalancerName is the name of the pick_first balancer.
|
// Name is the name of the pick_first balancer.
|
||||||
PickFirstBalancerName = "pick_first"
|
Name = "pick_first"
|
||||||
logPrefix = "[pick-first-lb %p] "
|
logPrefix = "[pick-first-lb %p] "
|
||||||
)
|
)
|
||||||
|
|
||||||
type pickfirstBuilder struct{}
|
type pickfirstBuilder struct{}
|
||||||
|
@ -47,7 +57,7 @@ func (pickfirstBuilder) Build(cc balancer.ClientConn, opt balancer.BuildOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pickfirstBuilder) Name() string {
|
func (pickfirstBuilder) Name() string {
|
||||||
return PickFirstBalancerName
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
type pfConfig struct {
|
type pfConfig struct {
|
||||||
|
@ -93,6 +103,12 @@ func (b *pickfirstBalancer) ResolverError(err error) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Shuffler interface {
|
||||||
|
ShuffleAddressListForTesting(n int, swap func(i, j int))
|
||||||
|
}
|
||||||
|
|
||||||
|
func ShuffleAddressListForTesting(n int, swap func(i, j int)) { rand.Shuffle(n, swap) }
|
||||||
|
|
||||||
func (b *pickfirstBalancer) UpdateClientConnState(state balancer.ClientConnState) error {
|
func (b *pickfirstBalancer) UpdateClientConnState(state balancer.ClientConnState) error {
|
||||||
if len(state.ResolverState.Addresses) == 0 && len(state.ResolverState.Endpoints) == 0 {
|
if len(state.ResolverState.Addresses) == 0 && len(state.ResolverState.Endpoints) == 0 {
|
||||||
// The resolver reported an empty address list. Treat it like an error by
|
// The resolver reported an empty address list. Treat it like an error by
|
||||||
|
@ -124,7 +140,7 @@ func (b *pickfirstBalancer) UpdateClientConnState(state balancer.ClientConnState
|
||||||
// within each endpoint. - A61
|
// within each endpoint. - A61
|
||||||
if cfg.ShuffleAddressList {
|
if cfg.ShuffleAddressList {
|
||||||
endpoints = append([]resolver.Endpoint{}, endpoints...)
|
endpoints = append([]resolver.Endpoint{}, endpoints...)
|
||||||
grpcrand.Shuffle(len(endpoints), func(i, j int) { endpoints[i], endpoints[j] = endpoints[j], endpoints[i] })
|
internal.ShuffleAddressListForTesting.(func(int, func(int, int)))(len(endpoints), func(i, j int) { endpoints[i], endpoints[j] = endpoints[j], endpoints[i] })
|
||||||
}
|
}
|
||||||
|
|
||||||
// "Flatten the list by concatenating the ordered list of addresses for each
|
// "Flatten the list by concatenating the ordered list of addresses for each
|
||||||
|
@ -145,7 +161,7 @@ func (b *pickfirstBalancer) UpdateClientConnState(state balancer.ClientConnState
|
||||||
addrs = state.ResolverState.Addresses
|
addrs = state.ResolverState.Addresses
|
||||||
if cfg.ShuffleAddressList {
|
if cfg.ShuffleAddressList {
|
||||||
addrs = append([]resolver.Address{}, addrs...)
|
addrs = append([]resolver.Address{}, addrs...)
|
||||||
grpcrand.Shuffle(len(addrs), func(i, j int) { addrs[i], addrs[j] = addrs[j], addrs[i] })
|
rand.Shuffle(len(addrs), func(i, j int) { addrs[i], addrs[j] = addrs[j], addrs[i] })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,12 +22,12 @@
|
||||||
package roundrobin
|
package roundrobin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/rand"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"google.golang.org/grpc/balancer"
|
"google.golang.org/grpc/balancer"
|
||||||
"google.golang.org/grpc/balancer/base"
|
"google.golang.org/grpc/balancer/base"
|
||||||
"google.golang.org/grpc/grpclog"
|
"google.golang.org/grpc/grpclog"
|
||||||
"google.golang.org/grpc/internal/grpcrand"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Name is the name of round_robin balancer.
|
// Name is the name of round_robin balancer.
|
||||||
|
@ -60,7 +60,7 @@ func (*rrPickerBuilder) Build(info base.PickerBuildInfo) balancer.Picker {
|
||||||
// Start at a random index, as the same RR balancer rebuilds a new
|
// Start at a random index, as the same RR balancer rebuilds a new
|
||||||
// picker when SubConn states change, and we don't want to apply excess
|
// picker when SubConn states change, and we don't want to apply excess
|
||||||
// load to the first server in the list.
|
// load to the first server in the list.
|
||||||
next: uint32(grpcrand.Intn(len(scs))),
|
next: uint32(rand.Intn(len(scs))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -198,6 +198,10 @@ func (ccb *ccBalancerWrapper) UpdateAddresses(sc balancer.SubConn, addrs []resol
|
||||||
func (ccb *ccBalancerWrapper) UpdateState(s balancer.State) {
|
func (ccb *ccBalancerWrapper) UpdateState(s balancer.State) {
|
||||||
ccb.cc.mu.Lock()
|
ccb.cc.mu.Lock()
|
||||||
defer ccb.cc.mu.Unlock()
|
defer ccb.cc.mu.Unlock()
|
||||||
|
if ccb.cc.conns == nil {
|
||||||
|
// The CC has been closed; ignore this update.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ccb.mu.Lock()
|
ccb.mu.Lock()
|
||||||
if ccb.closed {
|
if ccb.closed {
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.33.0
|
// protoc-gen-go v1.34.1
|
||||||
// protoc v4.25.2
|
// protoc v4.25.2
|
||||||
// source: grpc/binlog/v1/binarylog.proto
|
// source: grpc/binlog/v1/binarylog.proto
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ import (
|
||||||
|
|
||||||
"google.golang.org/grpc/balancer"
|
"google.golang.org/grpc/balancer"
|
||||||
"google.golang.org/grpc/balancer/base"
|
"google.golang.org/grpc/balancer/base"
|
||||||
|
"google.golang.org/grpc/balancer/pickfirst"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/connectivity"
|
"google.golang.org/grpc/connectivity"
|
||||||
"google.golang.org/grpc/internal"
|
"google.golang.org/grpc/internal"
|
||||||
|
@ -72,6 +73,8 @@ var (
|
||||||
// invalidDefaultServiceConfigErrPrefix is used to prefix the json parsing error for the default
|
// invalidDefaultServiceConfigErrPrefix is used to prefix the json parsing error for the default
|
||||||
// service config.
|
// service config.
|
||||||
invalidDefaultServiceConfigErrPrefix = "grpc: the provided default service config is invalid"
|
invalidDefaultServiceConfigErrPrefix = "grpc: the provided default service config is invalid"
|
||||||
|
// PickFirstBalancerName is the name of the pick_first balancer.
|
||||||
|
PickFirstBalancerName = pickfirst.Name
|
||||||
)
|
)
|
||||||
|
|
||||||
// The following errors are returned from Dial and DialContext
|
// The following errors are returned from Dial and DialContext
|
||||||
|
@ -152,6 +155,16 @@ func NewClient(target string, opts ...DialOption) (conn *ClientConn, err error)
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
opt.apply(&cc.dopts)
|
opt.apply(&cc.dopts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine the resolver to use.
|
||||||
|
if err := cc.initParsedTargetAndResolverBuilder(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, opt := range globalPerTargetDialOptions {
|
||||||
|
opt.DialOptionForTarget(cc.parsedTarget.URL).apply(&cc.dopts)
|
||||||
|
}
|
||||||
|
|
||||||
chainUnaryClientInterceptors(cc)
|
chainUnaryClientInterceptors(cc)
|
||||||
chainStreamClientInterceptors(cc)
|
chainStreamClientInterceptors(cc)
|
||||||
|
|
||||||
|
@ -160,7 +173,7 @@ func NewClient(target string, opts ...DialOption) (conn *ClientConn, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cc.dopts.defaultServiceConfigRawJSON != nil {
|
if cc.dopts.defaultServiceConfigRawJSON != nil {
|
||||||
scpr := parseServiceConfig(*cc.dopts.defaultServiceConfigRawJSON)
|
scpr := parseServiceConfig(*cc.dopts.defaultServiceConfigRawJSON, cc.dopts.maxCallAttempts)
|
||||||
if scpr.Err != nil {
|
if scpr.Err != nil {
|
||||||
return nil, fmt.Errorf("%s: %v", invalidDefaultServiceConfigErrPrefix, scpr.Err)
|
return nil, fmt.Errorf("%s: %v", invalidDefaultServiceConfigErrPrefix, scpr.Err)
|
||||||
}
|
}
|
||||||
|
@ -168,24 +181,15 @@ func NewClient(target string, opts ...DialOption) (conn *ClientConn, err error)
|
||||||
}
|
}
|
||||||
cc.mkp = cc.dopts.copts.KeepaliveParams
|
cc.mkp = cc.dopts.copts.KeepaliveParams
|
||||||
|
|
||||||
// Register ClientConn with channelz.
|
if err = cc.initAuthority(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register ClientConn with channelz. Note that this is only done after
|
||||||
|
// channel creation cannot fail.
|
||||||
cc.channelzRegistration(target)
|
cc.channelzRegistration(target)
|
||||||
|
channelz.Infof(logger, cc.channelz, "parsed dial target is: %#v", cc.parsedTarget)
|
||||||
// TODO: Ideally it should be impossible to error from this function after
|
channelz.Infof(logger, cc.channelz, "Channel authority set to %q", cc.authority)
|
||||||
// channelz registration. This will require removing some channelz logs
|
|
||||||
// from the following functions that can error. Errors can be returned to
|
|
||||||
// the user, and successful logs can be emitted here, after the checks have
|
|
||||||
// passed and channelz is subsequently registered.
|
|
||||||
|
|
||||||
// Determine the resolver to use.
|
|
||||||
if err := cc.parseTargetAndFindResolver(); err != nil {
|
|
||||||
channelz.RemoveEntry(cc.channelz.ID)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err = cc.determineAuthority(); err != nil {
|
|
||||||
channelz.RemoveEntry(cc.channelz.ID)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cc.csMgr = newConnectivityStateManager(cc.ctx, cc.channelz)
|
cc.csMgr = newConnectivityStateManager(cc.ctx, cc.channelz)
|
||||||
cc.pickerWrapper = newPickerWrapper(cc.dopts.copts.StatsHandlers)
|
cc.pickerWrapper = newPickerWrapper(cc.dopts.copts.StatsHandlers)
|
||||||
|
@ -587,11 +591,11 @@ type ClientConn struct {
|
||||||
|
|
||||||
// The following are initialized at dial time, and are read-only after that.
|
// The following are initialized at dial time, and are read-only after that.
|
||||||
target string // User's dial target.
|
target string // User's dial target.
|
||||||
parsedTarget resolver.Target // See parseTargetAndFindResolver().
|
parsedTarget resolver.Target // See initParsedTargetAndResolverBuilder().
|
||||||
authority string // See determineAuthority().
|
authority string // See initAuthority().
|
||||||
dopts dialOptions // Default and user specified dial options.
|
dopts dialOptions // Default and user specified dial options.
|
||||||
channelz *channelz.Channel // Channelz object.
|
channelz *channelz.Channel // Channelz object.
|
||||||
resolverBuilder resolver.Builder // See parseTargetAndFindResolver().
|
resolverBuilder resolver.Builder // See initParsedTargetAndResolverBuilder().
|
||||||
idlenessMgr *idle.Manager
|
idlenessMgr *idle.Manager
|
||||||
|
|
||||||
// The following provide their own synchronization, and therefore don't
|
// The following provide their own synchronization, and therefore don't
|
||||||
|
@ -692,8 +696,7 @@ func (cc *ClientConn) waitForResolvedAddrs(ctx context.Context) error {
|
||||||
var emptyServiceConfig *ServiceConfig
|
var emptyServiceConfig *ServiceConfig
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
balancer.Register(pickfirstBuilder{})
|
cfg := parseServiceConfig("{}", defaultMaxCallAttempts)
|
||||||
cfg := parseServiceConfig("{}")
|
|
||||||
if cfg.Err != nil {
|
if cfg.Err != nil {
|
||||||
panic(fmt.Sprintf("impossible error parsing empty service config: %v", cfg.Err))
|
panic(fmt.Sprintf("impossible error parsing empty service config: %v", cfg.Err))
|
||||||
}
|
}
|
||||||
|
@ -1673,22 +1676,19 @@ func (cc *ClientConn) connectionError() error {
|
||||||
return cc.lastConnectionError
|
return cc.lastConnectionError
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseTargetAndFindResolver parses the user's dial target and stores the
|
// initParsedTargetAndResolverBuilder parses the user's dial target and stores
|
||||||
// parsed target in `cc.parsedTarget`.
|
// the parsed target in `cc.parsedTarget`.
|
||||||
//
|
//
|
||||||
// The resolver to use is determined based on the scheme in the parsed target
|
// The resolver to use is determined based on the scheme in the parsed target
|
||||||
// and the same is stored in `cc.resolverBuilder`.
|
// and the same is stored in `cc.resolverBuilder`.
|
||||||
//
|
//
|
||||||
// Doesn't grab cc.mu as this method is expected to be called only at Dial time.
|
// Doesn't grab cc.mu as this method is expected to be called only at Dial time.
|
||||||
func (cc *ClientConn) parseTargetAndFindResolver() error {
|
func (cc *ClientConn) initParsedTargetAndResolverBuilder() error {
|
||||||
channelz.Infof(logger, cc.channelz, "original dial target is: %q", cc.target)
|
logger.Infof("original dial target is: %q", cc.target)
|
||||||
|
|
||||||
var rb resolver.Builder
|
var rb resolver.Builder
|
||||||
parsedTarget, err := parseTarget(cc.target)
|
parsedTarget, err := parseTarget(cc.target)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
channelz.Infof(logger, cc.channelz, "dial target %q parse failed: %v", cc.target, err)
|
|
||||||
} else {
|
|
||||||
channelz.Infof(logger, cc.channelz, "parsed dial target is: %#v", parsedTarget)
|
|
||||||
rb = cc.getResolver(parsedTarget.URL.Scheme)
|
rb = cc.getResolver(parsedTarget.URL.Scheme)
|
||||||
if rb != nil {
|
if rb != nil {
|
||||||
cc.parsedTarget = parsedTarget
|
cc.parsedTarget = parsedTarget
|
||||||
|
@ -1707,15 +1707,12 @@ func (cc *ClientConn) parseTargetAndFindResolver() error {
|
||||||
defScheme = resolver.GetDefaultScheme()
|
defScheme = resolver.GetDefaultScheme()
|
||||||
}
|
}
|
||||||
|
|
||||||
channelz.Infof(logger, cc.channelz, "fallback to scheme %q", defScheme)
|
|
||||||
canonicalTarget := defScheme + ":///" + cc.target
|
canonicalTarget := defScheme + ":///" + cc.target
|
||||||
|
|
||||||
parsedTarget, err = parseTarget(canonicalTarget)
|
parsedTarget, err = parseTarget(canonicalTarget)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
channelz.Infof(logger, cc.channelz, "dial target %q parse failed: %v", canonicalTarget, err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
channelz.Infof(logger, cc.channelz, "parsed dial target is: %+v", parsedTarget)
|
|
||||||
rb = cc.getResolver(parsedTarget.URL.Scheme)
|
rb = cc.getResolver(parsedTarget.URL.Scheme)
|
||||||
if rb == nil {
|
if rb == nil {
|
||||||
return fmt.Errorf("could not get resolver for default scheme: %q", parsedTarget.URL.Scheme)
|
return fmt.Errorf("could not get resolver for default scheme: %q", parsedTarget.URL.Scheme)
|
||||||
|
@ -1805,7 +1802,7 @@ func encodeAuthority(authority string) string {
|
||||||
// credentials do not match the authority configured through the dial option.
|
// credentials do not match the authority configured through the dial option.
|
||||||
//
|
//
|
||||||
// Doesn't grab cc.mu as this method is expected to be called only at Dial time.
|
// Doesn't grab cc.mu as this method is expected to be called only at Dial time.
|
||||||
func (cc *ClientConn) determineAuthority() error {
|
func (cc *ClientConn) initAuthority() error {
|
||||||
dopts := cc.dopts
|
dopts := cc.dopts
|
||||||
// Historically, we had two options for users to specify the serverName or
|
// Historically, we had two options for users to specify the serverName or
|
||||||
// authority for a channel. One was through the transport credentials
|
// authority for a channel. One was through the transport credentials
|
||||||
|
@ -1838,6 +1835,5 @@ func (cc *ClientConn) determineAuthority() error {
|
||||||
} else {
|
} else {
|
||||||
cc.authority = encodeAuthority(endpoint)
|
cc.authority = encodeAuthority(endpoint)
|
||||||
}
|
}
|
||||||
channelz.Infof(logger, cc.channelz, "Channel authority set to %q", cc.authority)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,9 +27,13 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"google.golang.org/grpc/grpclog"
|
||||||
credinternal "google.golang.org/grpc/internal/credentials"
|
credinternal "google.golang.org/grpc/internal/credentials"
|
||||||
|
"google.golang.org/grpc/internal/envconfig"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var logger = grpclog.Component("credentials")
|
||||||
|
|
||||||
// TLSInfo contains the auth information for a TLS authenticated connection.
|
// TLSInfo contains the auth information for a TLS authenticated connection.
|
||||||
// It implements the AuthInfo interface.
|
// It implements the AuthInfo interface.
|
||||||
type TLSInfo struct {
|
type TLSInfo struct {
|
||||||
|
@ -112,6 +116,22 @@ func (c *tlsCreds) ClientHandshake(ctx context.Context, authority string, rawCon
|
||||||
conn.Close()
|
conn.Close()
|
||||||
return nil, nil, ctx.Err()
|
return nil, nil, ctx.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The negotiated protocol can be either of the following:
|
||||||
|
// 1. h2: When the server supports ALPN. Only HTTP/2 can be negotiated since
|
||||||
|
// it is the only protocol advertised by the client during the handshake.
|
||||||
|
// The tls library ensures that the server chooses a protocol advertised
|
||||||
|
// by the client.
|
||||||
|
// 2. "" (empty string): If the server doesn't support ALPN. ALPN is a requirement
|
||||||
|
// for using HTTP/2 over TLS. We can terminate the connection immediately.
|
||||||
|
np := conn.ConnectionState().NegotiatedProtocol
|
||||||
|
if np == "" {
|
||||||
|
if envconfig.EnforceALPNEnabled {
|
||||||
|
conn.Close()
|
||||||
|
return nil, nil, fmt.Errorf("credentials: cannot check peer: missing selected ALPN property")
|
||||||
|
}
|
||||||
|
logger.Warningf("Allowing TLS connection to server %q with ALPN disabled. TLS connections to servers with ALPN disabled will be disallowed in future grpc-go releases", cfg.ServerName)
|
||||||
|
}
|
||||||
tlsInfo := TLSInfo{
|
tlsInfo := TLSInfo{
|
||||||
State: conn.ConnectionState(),
|
State: conn.ConnectionState(),
|
||||||
CommonAuthInfo: CommonAuthInfo{
|
CommonAuthInfo: CommonAuthInfo{
|
||||||
|
@ -131,8 +151,20 @@ func (c *tlsCreds) ServerHandshake(rawConn net.Conn) (net.Conn, AuthInfo, error)
|
||||||
conn.Close()
|
conn.Close()
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
cs := conn.ConnectionState()
|
||||||
|
// The negotiated application protocol can be empty only if the client doesn't
|
||||||
|
// support ALPN. In such cases, we can close the connection since ALPN is required
|
||||||
|
// for using HTTP/2 over TLS.
|
||||||
|
if cs.NegotiatedProtocol == "" {
|
||||||
|
if envconfig.EnforceALPNEnabled {
|
||||||
|
conn.Close()
|
||||||
|
return nil, nil, fmt.Errorf("credentials: cannot check peer: missing selected ALPN property")
|
||||||
|
} else if logger.V(2) {
|
||||||
|
logger.Info("Allowing TLS connection from client with ALPN disabled. TLS connections with ALPN disabled will be disallowed in future grpc-go releases")
|
||||||
|
}
|
||||||
|
}
|
||||||
tlsInfo := TLSInfo{
|
tlsInfo := TLSInfo{
|
||||||
State: conn.ConnectionState(),
|
State: cs,
|
||||||
CommonAuthInfo: CommonAuthInfo{
|
CommonAuthInfo: CommonAuthInfo{
|
||||||
SecurityLevel: PrivacyAndIntegrity,
|
SecurityLevel: PrivacyAndIntegrity,
|
||||||
},
|
},
|
||||||
|
|
|
@ -21,6 +21,7 @@ package grpc
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"google.golang.org/grpc/backoff"
|
"google.golang.org/grpc/backoff"
|
||||||
|
@ -36,6 +37,11 @@ import (
|
||||||
"google.golang.org/grpc/stats"
|
"google.golang.org/grpc/stats"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// https://github.com/grpc/proposal/blob/master/A6-client-retries.md#limits-on-retries-and-hedges
|
||||||
|
defaultMaxCallAttempts = 5
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
internal.AddGlobalDialOptions = func(opt ...DialOption) {
|
internal.AddGlobalDialOptions = func(opt ...DialOption) {
|
||||||
globalDialOptions = append(globalDialOptions, opt...)
|
globalDialOptions = append(globalDialOptions, opt...)
|
||||||
|
@ -43,6 +49,14 @@ func init() {
|
||||||
internal.ClearGlobalDialOptions = func() {
|
internal.ClearGlobalDialOptions = func() {
|
||||||
globalDialOptions = nil
|
globalDialOptions = nil
|
||||||
}
|
}
|
||||||
|
internal.AddGlobalPerTargetDialOptions = func(opt any) {
|
||||||
|
if ptdo, ok := opt.(perTargetDialOption); ok {
|
||||||
|
globalPerTargetDialOptions = append(globalPerTargetDialOptions, ptdo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal.ClearGlobalPerTargetDialOptions = func() {
|
||||||
|
globalPerTargetDialOptions = nil
|
||||||
|
}
|
||||||
internal.WithBinaryLogger = withBinaryLogger
|
internal.WithBinaryLogger = withBinaryLogger
|
||||||
internal.JoinDialOptions = newJoinDialOption
|
internal.JoinDialOptions = newJoinDialOption
|
||||||
internal.DisableGlobalDialOptions = newDisableGlobalDialOptions
|
internal.DisableGlobalDialOptions = newDisableGlobalDialOptions
|
||||||
|
@ -80,6 +94,7 @@ type dialOptions struct {
|
||||||
idleTimeout time.Duration
|
idleTimeout time.Duration
|
||||||
recvBufferPool SharedBufferPool
|
recvBufferPool SharedBufferPool
|
||||||
defaultScheme string
|
defaultScheme string
|
||||||
|
maxCallAttempts int
|
||||||
}
|
}
|
||||||
|
|
||||||
// DialOption configures how we set up the connection.
|
// DialOption configures how we set up the connection.
|
||||||
|
@ -89,6 +104,19 @@ type DialOption interface {
|
||||||
|
|
||||||
var globalDialOptions []DialOption
|
var globalDialOptions []DialOption
|
||||||
|
|
||||||
|
// perTargetDialOption takes a parsed target and returns a dial option to apply.
|
||||||
|
//
|
||||||
|
// This gets called after NewClient() parses the target, and allows per target
|
||||||
|
// configuration set through a returned DialOption. The DialOption will not take
|
||||||
|
// effect if specifies a resolver builder, as that Dial Option is factored in
|
||||||
|
// while parsing target.
|
||||||
|
type perTargetDialOption interface {
|
||||||
|
// DialOption returns a Dial Option to apply.
|
||||||
|
DialOptionForTarget(parsedTarget url.URL) DialOption
|
||||||
|
}
|
||||||
|
|
||||||
|
var globalPerTargetDialOptions []perTargetDialOption
|
||||||
|
|
||||||
// EmptyDialOption does not alter the dial configuration. It can be embedded in
|
// EmptyDialOption does not alter the dial configuration. It can be embedded in
|
||||||
// another structure to build custom dial options.
|
// another structure to build custom dial options.
|
||||||
//
|
//
|
||||||
|
@ -655,6 +683,7 @@ func defaultDialOptions() dialOptions {
|
||||||
idleTimeout: 30 * time.Minute,
|
idleTimeout: 30 * time.Minute,
|
||||||
recvBufferPool: nopBufferPool{},
|
recvBufferPool: nopBufferPool{},
|
||||||
defaultScheme: "dns",
|
defaultScheme: "dns",
|
||||||
|
maxCallAttempts: defaultMaxCallAttempts,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -712,6 +741,23 @@ func WithIdleTimeout(d time.Duration) DialOption {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithMaxCallAttempts returns a DialOption that configures the maximum number
|
||||||
|
// of attempts per call (including retries and hedging) using the channel.
|
||||||
|
// Service owners may specify a higher value for these parameters, but higher
|
||||||
|
// values will be treated as equal to the maximum value by the client
|
||||||
|
// implementation. This mitigates security concerns related to the service
|
||||||
|
// config being transferred to the client via DNS.
|
||||||
|
//
|
||||||
|
// A value of 5 will be used if this dial option is not set or n < 2.
|
||||||
|
func WithMaxCallAttempts(n int) DialOption {
|
||||||
|
return newFuncDialOption(func(o *dialOptions) {
|
||||||
|
if n < 2 {
|
||||||
|
n = defaultMaxCallAttempts
|
||||||
|
}
|
||||||
|
o.maxCallAttempts = n
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// WithRecvBufferPool returns a DialOption that configures the ClientConn
|
// WithRecvBufferPool returns a DialOption that configures the ClientConn
|
||||||
// to use the provided shared buffer pool for parsing incoming messages. Depending
|
// to use the provided shared buffer pool for parsing incoming messages. Depending
|
||||||
// on the application's workload, this could result in reduced memory allocation.
|
// on the application's workload, this could result in reduced memory allocation.
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.33.0
|
// protoc-gen-go v1.34.1
|
||||||
// protoc v4.25.2
|
// protoc v4.25.2
|
||||||
// source: grpc/health/v1/health.proto
|
// source: grpc/health/v1/health.proto
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// - protoc-gen-go-grpc v1.3.0
|
// - protoc-gen-go-grpc v1.4.0
|
||||||
// - protoc v4.25.2
|
// - protoc v4.25.2
|
||||||
// source: grpc/health/v1/health.proto
|
// source: grpc/health/v1/health.proto
|
||||||
|
|
||||||
|
@ -43,6 +43,10 @@ const (
|
||||||
// HealthClient is the client API for Health service.
|
// HealthClient is the client API for Health service.
|
||||||
//
|
//
|
||||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||||
|
//
|
||||||
|
// Health is gRPC's mechanism for checking whether a server is able to handle
|
||||||
|
// RPCs. Its semantics are documented in
|
||||||
|
// https://github.com/grpc/grpc/blob/master/doc/health-checking.md.
|
||||||
type HealthClient interface {
|
type HealthClient interface {
|
||||||
// Check gets the health of the specified service. If the requested service
|
// Check gets the health of the specified service. If the requested service
|
||||||
// is unknown, the call will fail with status NOT_FOUND. If the caller does
|
// is unknown, the call will fail with status NOT_FOUND. If the caller does
|
||||||
|
@ -126,6 +130,10 @@ func (x *healthWatchClient) Recv() (*HealthCheckResponse, error) {
|
||||||
// HealthServer is the server API for Health service.
|
// HealthServer is the server API for Health service.
|
||||||
// All implementations should embed UnimplementedHealthServer
|
// All implementations should embed UnimplementedHealthServer
|
||||||
// for forward compatibility
|
// for forward compatibility
|
||||||
|
//
|
||||||
|
// Health is gRPC's mechanism for checking whether a server is able to handle
|
||||||
|
// RPCs. Its semantics are documented in
|
||||||
|
// https://github.com/grpc/grpc/blob/master/doc/health-checking.md.
|
||||||
type HealthServer interface {
|
type HealthServer interface {
|
||||||
// Check gets the health of the specified service. If the requested service
|
// Check gets the health of the specified service. If the requested service
|
||||||
// is unknown, the call will fail with status NOT_FOUND. If the caller does
|
// is unknown, the call will fail with status NOT_FOUND. If the caller does
|
||||||
|
|
|
@ -25,10 +25,10 @@ package backoff
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
grpcbackoff "google.golang.org/grpc/backoff"
|
grpcbackoff "google.golang.org/grpc/backoff"
|
||||||
"google.golang.org/grpc/internal/grpcrand"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Strategy defines the methodology for backing off after a grpc connection
|
// Strategy defines the methodology for backing off after a grpc connection
|
||||||
|
@ -67,7 +67,7 @@ func (bc Exponential) Backoff(retries int) time.Duration {
|
||||||
}
|
}
|
||||||
// Randomize backoff delays so that if a cluster of requests start at
|
// Randomize backoff delays so that if a cluster of requests start at
|
||||||
// the same time, they won't operate in lockstep.
|
// the same time, they won't operate in lockstep.
|
||||||
backoff *= 1 + bc.Config.Jitter*(grpcrand.Float64()*2-1)
|
backoff *= 1 + bc.Config.Jitter*(rand.Float64()*2-1)
|
||||||
if backoff < 0 {
|
if backoff < 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,12 @@ var (
|
||||||
// ALTSMaxConcurrentHandshakes is the maximum number of concurrent ALTS
|
// ALTSMaxConcurrentHandshakes is the maximum number of concurrent ALTS
|
||||||
// handshakes that can be performed.
|
// handshakes that can be performed.
|
||||||
ALTSMaxConcurrentHandshakes = uint64FromEnv("GRPC_ALTS_MAX_CONCURRENT_HANDSHAKES", 100, 1, 100)
|
ALTSMaxConcurrentHandshakes = uint64FromEnv("GRPC_ALTS_MAX_CONCURRENT_HANDSHAKES", 100, 1, 100)
|
||||||
|
// EnforceALPNEnabled is set if TLS connections to servers with ALPN disabled
|
||||||
|
// should be rejected. The HTTP/2 protocol requires ALPN to be enabled, this
|
||||||
|
// option is present for backward compatibility. This option may be overridden
|
||||||
|
// by setting the environment variable "GRPC_ENFORCE_ALPN_ENABLED" to "true"
|
||||||
|
// or "false".
|
||||||
|
EnforceALPNEnabled = boolFromEnv("GRPC_ENFORCE_ALPN_ENABLED", false)
|
||||||
)
|
)
|
||||||
|
|
||||||
func boolFromEnv(envVar string, def bool) bool {
|
func boolFromEnv(envVar string, def bool) bool {
|
||||||
|
|
|
@ -1,100 +0,0 @@
|
||||||
//go:build !go1.21
|
|
||||||
|
|
||||||
// TODO: when this file is deleted (after Go 1.20 support is dropped), delete
|
|
||||||
// all of grpcrand and call the rand package directly.
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Copyright 2018 gRPC authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Package grpcrand implements math/rand functions in a concurrent-safe way
|
|
||||||
// with a global random source, independent of math/rand's global source.
|
|
||||||
package grpcrand
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/rand"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
r = rand.New(rand.NewSource(time.Now().UnixNano()))
|
|
||||||
mu sync.Mutex
|
|
||||||
)
|
|
||||||
|
|
||||||
// Int implements rand.Int on the grpcrand global source.
|
|
||||||
func Int() int {
|
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
return r.Int()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Int63n implements rand.Int63n on the grpcrand global source.
|
|
||||||
func Int63n(n int64) int64 {
|
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
return r.Int63n(n)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Intn implements rand.Intn on the grpcrand global source.
|
|
||||||
func Intn(n int) int {
|
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
return r.Intn(n)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Int31n implements rand.Int31n on the grpcrand global source.
|
|
||||||
func Int31n(n int32) int32 {
|
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
return r.Int31n(n)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float64 implements rand.Float64 on the grpcrand global source.
|
|
||||||
func Float64() float64 {
|
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
return r.Float64()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uint64 implements rand.Uint64 on the grpcrand global source.
|
|
||||||
func Uint64() uint64 {
|
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
return r.Uint64()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uint32 implements rand.Uint32 on the grpcrand global source.
|
|
||||||
func Uint32() uint32 {
|
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
return r.Uint32()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExpFloat64 implements rand.ExpFloat64 on the grpcrand global source.
|
|
||||||
func ExpFloat64() float64 {
|
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
return r.ExpFloat64()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shuffle implements rand.Shuffle on the grpcrand global source.
|
|
||||||
var Shuffle = func(n int, f func(int, int)) {
|
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
r.Shuffle(n, f)
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
//go:build go1.21
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Copyright 2024 gRPC authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Package grpcrand implements math/rand functions in a concurrent-safe way
|
|
||||||
// with a global random source, independent of math/rand's global source.
|
|
||||||
package grpcrand
|
|
||||||
|
|
||||||
import "math/rand"
|
|
||||||
|
|
||||||
// This implementation will be used for Go version 1.21 or newer.
|
|
||||||
// For older versions, the original implementation with mutex will be used.
|
|
||||||
|
|
||||||
// Int implements rand.Int on the grpcrand global source.
|
|
||||||
func Int() int {
|
|
||||||
return rand.Int()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Int63n implements rand.Int63n on the grpcrand global source.
|
|
||||||
func Int63n(n int64) int64 {
|
|
||||||
return rand.Int63n(n)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Intn implements rand.Intn on the grpcrand global source.
|
|
||||||
func Intn(n int) int {
|
|
||||||
return rand.Intn(n)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Int31n implements rand.Int31n on the grpcrand global source.
|
|
||||||
func Int31n(n int32) int32 {
|
|
||||||
return rand.Int31n(n)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float64 implements rand.Float64 on the grpcrand global source.
|
|
||||||
func Float64() float64 {
|
|
||||||
return rand.Float64()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uint64 implements rand.Uint64 on the grpcrand global source.
|
|
||||||
func Uint64() uint64 {
|
|
||||||
return rand.Uint64()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uint32 implements rand.Uint32 on the grpcrand global source.
|
|
||||||
func Uint32() uint32 {
|
|
||||||
return rand.Uint32()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExpFloat64 implements rand.ExpFloat64 on the grpcrand global source.
|
|
||||||
func ExpFloat64() float64 {
|
|
||||||
return rand.ExpFloat64()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shuffle implements rand.Shuffle on the grpcrand global source.
|
|
||||||
var Shuffle = func(n int, f func(int, int)) {
|
|
||||||
rand.Shuffle(n, f)
|
|
||||||
}
|
|
|
@ -106,6 +106,14 @@ var (
|
||||||
// This is used in the 1.0 release of gcp/observability, and thus must not be
|
// This is used in the 1.0 release of gcp/observability, and thus must not be
|
||||||
// deleted or changed.
|
// deleted or changed.
|
||||||
ClearGlobalDialOptions func()
|
ClearGlobalDialOptions func()
|
||||||
|
|
||||||
|
// AddGlobalPerTargetDialOptions adds a PerTargetDialOption that will be
|
||||||
|
// configured for newly created ClientConns.
|
||||||
|
AddGlobalPerTargetDialOptions any // func (opt any)
|
||||||
|
// ClearGlobalPerTargetDialOptions clears the slice of global late apply
|
||||||
|
// dial options.
|
||||||
|
ClearGlobalPerTargetDialOptions func()
|
||||||
|
|
||||||
// JoinDialOptions combines the dial options passed as arguments into a
|
// JoinDialOptions combines the dial options passed as arguments into a
|
||||||
// single dial option.
|
// single dial option.
|
||||||
JoinDialOptions any // func(...grpc.DialOption) grpc.DialOption
|
JoinDialOptions any // func(...grpc.DialOption) grpc.DialOption
|
||||||
|
@ -126,7 +134,8 @@ var (
|
||||||
// deleted or changed.
|
// deleted or changed.
|
||||||
BinaryLogger any // func(binarylog.Logger) grpc.ServerOption
|
BinaryLogger any // func(binarylog.Logger) grpc.ServerOption
|
||||||
|
|
||||||
// SubscribeToConnectivityStateChanges adds a grpcsync.Subscriber to a provided grpc.ClientConn
|
// SubscribeToConnectivityStateChanges adds a grpcsync.Subscriber to a
|
||||||
|
// provided grpc.ClientConn.
|
||||||
SubscribeToConnectivityStateChanges any // func(*grpc.ClientConn, grpcsync.Subscriber)
|
SubscribeToConnectivityStateChanges any // func(*grpc.ClientConn, grpcsync.Subscriber)
|
||||||
|
|
||||||
// NewXDSResolverWithConfigForTesting creates a new xds resolver builder using
|
// NewXDSResolverWithConfigForTesting creates a new xds resolver builder using
|
||||||
|
@ -184,25 +193,25 @@ var (
|
||||||
|
|
||||||
ChannelzTurnOffForTesting func()
|
ChannelzTurnOffForTesting func()
|
||||||
|
|
||||||
// TriggerXDSResourceNameNotFoundForTesting triggers the resource-not-found
|
// TriggerXDSResourceNotFoundForTesting causes the provided xDS Client to
|
||||||
// error for a given resource type and name. This is usually triggered when
|
// invoke resource-not-found error for the given resource type and name.
|
||||||
// the associated watch timer fires. For testing purposes, having this
|
TriggerXDSResourceNotFoundForTesting any // func(xdsclient.XDSClient, xdsresource.Type, string) error
|
||||||
// function makes events more predictable than relying on timer events.
|
|
||||||
TriggerXDSResourceNameNotFoundForTesting any // func(func(xdsresource.Type, string), string, string) error
|
|
||||||
|
|
||||||
// TriggerXDSResourceNameNotFoundClient invokes the testing xDS Client
|
// FromOutgoingContextRaw returns the un-merged, intermediary contents of
|
||||||
// singleton to invoke resource not found for a resource type name and
|
// metadata.rawMD.
|
||||||
// resource name.
|
|
||||||
TriggerXDSResourceNameNotFoundClient any // func(string, string) error
|
|
||||||
|
|
||||||
// FromOutgoingContextRaw returns the un-merged, intermediary contents of metadata.rawMD.
|
|
||||||
FromOutgoingContextRaw any // func(context.Context) (metadata.MD, [][]string, bool)
|
FromOutgoingContextRaw any // func(context.Context) (metadata.MD, [][]string, bool)
|
||||||
|
|
||||||
// UserSetDefaultScheme is set to true if the user has overridden the default resolver scheme.
|
// UserSetDefaultScheme is set to true if the user has overridden the
|
||||||
|
// default resolver scheme.
|
||||||
UserSetDefaultScheme bool = false
|
UserSetDefaultScheme bool = false
|
||||||
|
|
||||||
|
// ShuffleAddressListForTesting pseudo-randomizes the order of addresses. n
|
||||||
|
// is the number of elements. swap swaps the elements with indexes i and j.
|
||||||
|
ShuffleAddressListForTesting any // func(n int, swap func(i, j int))
|
||||||
)
|
)
|
||||||
|
|
||||||
// HealthChecker defines the signature of the client-side LB channel health checking function.
|
// HealthChecker defines the signature of the client-side LB channel health
|
||||||
|
// checking function.
|
||||||
//
|
//
|
||||||
// The implementation is expected to create a health checking RPC stream by
|
// The implementation is expected to create a health checking RPC stream by
|
||||||
// calling newStream(), watch for the health status of serviceName, and report
|
// calling newStream(), watch for the health status of serviceName, and report
|
||||||
|
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -35,7 +36,6 @@ import (
|
||||||
"google.golang.org/grpc/grpclog"
|
"google.golang.org/grpc/grpclog"
|
||||||
"google.golang.org/grpc/internal/backoff"
|
"google.golang.org/grpc/internal/backoff"
|
||||||
"google.golang.org/grpc/internal/envconfig"
|
"google.golang.org/grpc/internal/envconfig"
|
||||||
"google.golang.org/grpc/internal/grpcrand"
|
|
||||||
"google.golang.org/grpc/internal/resolver/dns/internal"
|
"google.golang.org/grpc/internal/resolver/dns/internal"
|
||||||
"google.golang.org/grpc/resolver"
|
"google.golang.org/grpc/resolver"
|
||||||
"google.golang.org/grpc/serviceconfig"
|
"google.golang.org/grpc/serviceconfig"
|
||||||
|
@ -63,6 +63,8 @@ var (
|
||||||
func init() {
|
func init() {
|
||||||
resolver.Register(NewBuilder())
|
resolver.Register(NewBuilder())
|
||||||
internal.TimeAfterFunc = time.After
|
internal.TimeAfterFunc = time.After
|
||||||
|
internal.TimeNowFunc = time.Now
|
||||||
|
internal.TimeUntilFunc = time.Until
|
||||||
internal.NewNetResolver = newNetResolver
|
internal.NewNetResolver = newNetResolver
|
||||||
internal.AddressDialer = addressDialer
|
internal.AddressDialer = addressDialer
|
||||||
}
|
}
|
||||||
|
@ -209,12 +211,12 @@ func (d *dnsResolver) watcher() {
|
||||||
err = d.cc.UpdateState(*state)
|
err = d.cc.UpdateState(*state)
|
||||||
}
|
}
|
||||||
|
|
||||||
var waitTime time.Duration
|
var nextResolutionTime time.Time
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// Success resolving, wait for the next ResolveNow. However, also wait 30
|
// Success resolving, wait for the next ResolveNow. However, also wait 30
|
||||||
// seconds at the very least to prevent constantly re-resolving.
|
// seconds at the very least to prevent constantly re-resolving.
|
||||||
backoffIndex = 1
|
backoffIndex = 1
|
||||||
waitTime = MinResolutionInterval
|
nextResolutionTime = internal.TimeNowFunc().Add(MinResolutionInterval)
|
||||||
select {
|
select {
|
||||||
case <-d.ctx.Done():
|
case <-d.ctx.Done():
|
||||||
return
|
return
|
||||||
|
@ -223,13 +225,13 @@ func (d *dnsResolver) watcher() {
|
||||||
} else {
|
} else {
|
||||||
// Poll on an error found in DNS Resolver or an error received from
|
// Poll on an error found in DNS Resolver or an error received from
|
||||||
// ClientConn.
|
// ClientConn.
|
||||||
waitTime = backoff.DefaultExponential.Backoff(backoffIndex)
|
nextResolutionTime = internal.TimeNowFunc().Add(backoff.DefaultExponential.Backoff(backoffIndex))
|
||||||
backoffIndex++
|
backoffIndex++
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case <-d.ctx.Done():
|
case <-d.ctx.Done():
|
||||||
return
|
return
|
||||||
case <-internal.TimeAfterFunc(waitTime):
|
case <-internal.TimeAfterFunc(internal.TimeUntilFunc(nextResolutionTime)):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -423,7 +425,7 @@ func chosenByPercentage(a *int) bool {
|
||||||
if a == nil {
|
if a == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return grpcrand.Intn(100)+1 <= *a
|
return rand.Intn(100)+1 <= *a
|
||||||
}
|
}
|
||||||
|
|
||||||
func canaryingSC(js string) string {
|
func canaryingSC(js string) string {
|
||||||
|
|
|
@ -51,11 +51,22 @@ var (
|
||||||
// The following vars are overridden from tests.
|
// The following vars are overridden from tests.
|
||||||
var (
|
var (
|
||||||
// TimeAfterFunc is used by the DNS resolver to wait for the given duration
|
// TimeAfterFunc is used by the DNS resolver to wait for the given duration
|
||||||
// to elapse. In non-test code, this is implemented by time.After. In test
|
// to elapse. In non-test code, this is implemented by time.After. In test
|
||||||
// code, this can be used to control the amount of time the resolver is
|
// code, this can be used to control the amount of time the resolver is
|
||||||
// blocked waiting for the duration to elapse.
|
// blocked waiting for the duration to elapse.
|
||||||
TimeAfterFunc func(time.Duration) <-chan time.Time
|
TimeAfterFunc func(time.Duration) <-chan time.Time
|
||||||
|
|
||||||
|
// TimeNowFunc is used by the DNS resolver to get the current time.
|
||||||
|
// In non-test code, this is implemented by time.Now. In test code,
|
||||||
|
// this can be used to control the current time for the resolver.
|
||||||
|
TimeNowFunc func() time.Time
|
||||||
|
|
||||||
|
// TimeUntilFunc is used by the DNS resolver to calculate the remaining
|
||||||
|
// wait time for re-resolution. In non-test code, this is implemented by
|
||||||
|
// time.Until. In test code, this can be used to control the remaining
|
||||||
|
// time for resolver to wait for re-resolution.
|
||||||
|
TimeUntilFunc func(time.Time) time.Duration
|
||||||
|
|
||||||
// NewNetResolver returns the net.Resolver instance for the given target.
|
// NewNetResolver returns the net.Resolver instance for the given target.
|
||||||
NewNetResolver func(string) (NetResolver, error)
|
NewNetResolver func(string) (NetResolver, error)
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -43,7 +44,6 @@ import (
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/credentials"
|
"google.golang.org/grpc/credentials"
|
||||||
"google.golang.org/grpc/internal/channelz"
|
"google.golang.org/grpc/internal/channelz"
|
||||||
"google.golang.org/grpc/internal/grpcrand"
|
|
||||||
"google.golang.org/grpc/internal/grpcsync"
|
"google.golang.org/grpc/internal/grpcsync"
|
||||||
"google.golang.org/grpc/keepalive"
|
"google.golang.org/grpc/keepalive"
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
|
@ -1440,7 +1440,7 @@ func getJitter(v time.Duration) time.Duration {
|
||||||
}
|
}
|
||||||
// Generate a jitter between +/- 10% of the value.
|
// Generate a jitter between +/- 10% of the value.
|
||||||
r := int64(v / 10)
|
r := int64(v / 10)
|
||||||
j := grpcrand.Int63n(2*r) - r
|
j := rand.Int63n(2*r) - r
|
||||||
return time.Duration(j)
|
return time.Duration(j)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,21 +90,6 @@ func Pairs(kv ...string) MD {
|
||||||
return md
|
return md
|
||||||
}
|
}
|
||||||
|
|
||||||
// String implements the Stringer interface for pretty-printing a MD.
|
|
||||||
// Ordering of the values is non-deterministic as it ranges over a map.
|
|
||||||
func (md MD) String() string {
|
|
||||||
var sb strings.Builder
|
|
||||||
fmt.Fprintf(&sb, "MD{")
|
|
||||||
for k, v := range md {
|
|
||||||
if sb.Len() > 3 {
|
|
||||||
fmt.Fprintf(&sb, ", ")
|
|
||||||
}
|
|
||||||
fmt.Fprintf(&sb, "%s=[%s]", k, strings.Join(v, ", "))
|
|
||||||
}
|
|
||||||
fmt.Fprintf(&sb, "}")
|
|
||||||
return sb.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Len returns the number of items in md.
|
// Len returns the number of items in md.
|
||||||
func (md MD) Len() int {
|
func (md MD) Len() int {
|
||||||
return len(md)
|
return len(md)
|
||||||
|
|
|
@ -22,7 +22,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"sync"
|
"sync/atomic"
|
||||||
|
|
||||||
"google.golang.org/grpc/balancer"
|
"google.golang.org/grpc/balancer"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
|
@ -33,35 +33,43 @@ import (
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// pickerGeneration stores a picker and a channel used to signal that a picker
|
||||||
|
// newer than this one is available.
|
||||||
|
type pickerGeneration struct {
|
||||||
|
// picker is the picker produced by the LB policy. May be nil if a picker
|
||||||
|
// has never been produced.
|
||||||
|
picker balancer.Picker
|
||||||
|
// blockingCh is closed when the picker has been invalidated because there
|
||||||
|
// is a new one available.
|
||||||
|
blockingCh chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
// pickerWrapper is a wrapper of balancer.Picker. It blocks on certain pick
|
// pickerWrapper is a wrapper of balancer.Picker. It blocks on certain pick
|
||||||
// actions and unblock when there's a picker update.
|
// actions and unblock when there's a picker update.
|
||||||
type pickerWrapper struct {
|
type pickerWrapper struct {
|
||||||
mu sync.Mutex
|
// If pickerGen holds a nil pointer, the pickerWrapper is closed.
|
||||||
done bool
|
pickerGen atomic.Pointer[pickerGeneration]
|
||||||
blockingCh chan struct{}
|
|
||||||
picker balancer.Picker
|
|
||||||
statsHandlers []stats.Handler // to record blocking picker calls
|
statsHandlers []stats.Handler // to record blocking picker calls
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPickerWrapper(statsHandlers []stats.Handler) *pickerWrapper {
|
func newPickerWrapper(statsHandlers []stats.Handler) *pickerWrapper {
|
||||||
return &pickerWrapper{
|
pw := &pickerWrapper{
|
||||||
blockingCh: make(chan struct{}),
|
|
||||||
statsHandlers: statsHandlers,
|
statsHandlers: statsHandlers,
|
||||||
}
|
}
|
||||||
|
pw.pickerGen.Store(&pickerGeneration{
|
||||||
|
blockingCh: make(chan struct{}),
|
||||||
|
})
|
||||||
|
return pw
|
||||||
}
|
}
|
||||||
|
|
||||||
// updatePicker is called by UpdateBalancerState. It unblocks all blocked pick.
|
// updatePicker is called by UpdateState calls from the LB policy. It
|
||||||
|
// unblocks all blocked pick.
|
||||||
func (pw *pickerWrapper) updatePicker(p balancer.Picker) {
|
func (pw *pickerWrapper) updatePicker(p balancer.Picker) {
|
||||||
pw.mu.Lock()
|
old := pw.pickerGen.Swap(&pickerGeneration{
|
||||||
if pw.done {
|
picker: p,
|
||||||
pw.mu.Unlock()
|
blockingCh: make(chan struct{}),
|
||||||
return
|
})
|
||||||
}
|
close(old.blockingCh)
|
||||||
pw.picker = p
|
|
||||||
// pw.blockingCh should never be nil.
|
|
||||||
close(pw.blockingCh)
|
|
||||||
pw.blockingCh = make(chan struct{})
|
|
||||||
pw.mu.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// doneChannelzWrapper performs the following:
|
// doneChannelzWrapper performs the following:
|
||||||
|
@ -98,20 +106,17 @@ func (pw *pickerWrapper) pick(ctx context.Context, failfast bool, info balancer.
|
||||||
var lastPickErr error
|
var lastPickErr error
|
||||||
|
|
||||||
for {
|
for {
|
||||||
pw.mu.Lock()
|
pg := pw.pickerGen.Load()
|
||||||
if pw.done {
|
if pg == nil {
|
||||||
pw.mu.Unlock()
|
|
||||||
return nil, balancer.PickResult{}, ErrClientConnClosing
|
return nil, balancer.PickResult{}, ErrClientConnClosing
|
||||||
}
|
}
|
||||||
|
if pg.picker == nil {
|
||||||
if pw.picker == nil {
|
ch = pg.blockingCh
|
||||||
ch = pw.blockingCh
|
|
||||||
}
|
}
|
||||||
if ch == pw.blockingCh {
|
if ch == pg.blockingCh {
|
||||||
// This could happen when either:
|
// This could happen when either:
|
||||||
// - pw.picker is nil (the previous if condition), or
|
// - pw.picker is nil (the previous if condition), or
|
||||||
// - has called pick on the current picker.
|
// - we have already called pick on the current picker.
|
||||||
pw.mu.Unlock()
|
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
var errStr string
|
var errStr string
|
||||||
|
@ -145,9 +150,8 @@ func (pw *pickerWrapper) pick(ctx context.Context, failfast bool, info balancer.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ch = pw.blockingCh
|
ch = pg.blockingCh
|
||||||
p := pw.picker
|
p := pg.picker
|
||||||
pw.mu.Unlock()
|
|
||||||
|
|
||||||
pickResult, err := p.Pick(info)
|
pickResult, err := p.Pick(info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -197,24 +201,15 @@ func (pw *pickerWrapper) pick(ctx context.Context, failfast bool, info balancer.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pw *pickerWrapper) close() {
|
func (pw *pickerWrapper) close() {
|
||||||
pw.mu.Lock()
|
old := pw.pickerGen.Swap(nil)
|
||||||
defer pw.mu.Unlock()
|
close(old.blockingCh)
|
||||||
if pw.done {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
pw.done = true
|
|
||||||
close(pw.blockingCh)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset clears the pickerWrapper and prepares it for being used again when idle
|
// reset clears the pickerWrapper and prepares it for being used again when idle
|
||||||
// mode is exited.
|
// mode is exited.
|
||||||
func (pw *pickerWrapper) reset() {
|
func (pw *pickerWrapper) reset() {
|
||||||
pw.mu.Lock()
|
old := pw.pickerGen.Swap(&pickerGeneration{blockingCh: make(chan struct{})})
|
||||||
defer pw.mu.Unlock()
|
close(old.blockingCh)
|
||||||
if pw.done {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
pw.blockingCh = make(chan struct{})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// dropError is a wrapper error that indicates the LB policy wishes to drop the
|
// dropError is a wrapper error that indicates the LB policy wishes to drop the
|
||||||
|
|
|
@ -171,7 +171,7 @@ func (ccr *ccResolverWrapper) NewAddress(addrs []resolver.Address) {
|
||||||
// ParseServiceConfig is called by resolver implementations to parse a JSON
|
// ParseServiceConfig is called by resolver implementations to parse a JSON
|
||||||
// representation of the service config.
|
// representation of the service config.
|
||||||
func (ccr *ccResolverWrapper) ParseServiceConfig(scJSON string) *serviceconfig.ParseResult {
|
func (ccr *ccResolverWrapper) ParseServiceConfig(scJSON string) *serviceconfig.ParseResult {
|
||||||
return parseServiceConfig(scJSON)
|
return parseServiceConfig(scJSON, ccr.cc.dopts.maxCallAttempts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// addChannelzTraceEvent adds a channelz trace event containing the new
|
// addChannelzTraceEvent adds a channelz trace event containing the new
|
||||||
|
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"google.golang.org/grpc/balancer"
|
"google.golang.org/grpc/balancer"
|
||||||
|
"google.golang.org/grpc/balancer/pickfirst"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/internal"
|
"google.golang.org/grpc/internal"
|
||||||
"google.golang.org/grpc/internal/balancer/gracefulswitch"
|
"google.golang.org/grpc/internal/balancer/gracefulswitch"
|
||||||
|
@ -163,9 +164,11 @@ type jsonSC struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
internal.ParseServiceConfig = parseServiceConfig
|
internal.ParseServiceConfig = func(js string) *serviceconfig.ParseResult {
|
||||||
|
return parseServiceConfig(js, defaultMaxCallAttempts)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
func parseServiceConfig(js string) *serviceconfig.ParseResult {
|
func parseServiceConfig(js string, maxAttempts int) *serviceconfig.ParseResult {
|
||||||
if len(js) == 0 {
|
if len(js) == 0 {
|
||||||
return &serviceconfig.ParseResult{Err: fmt.Errorf("no JSON service config provided")}
|
return &serviceconfig.ParseResult{Err: fmt.Errorf("no JSON service config provided")}
|
||||||
}
|
}
|
||||||
|
@ -183,12 +186,12 @@ func parseServiceConfig(js string) *serviceconfig.ParseResult {
|
||||||
}
|
}
|
||||||
c := rsc.LoadBalancingConfig
|
c := rsc.LoadBalancingConfig
|
||||||
if c == nil {
|
if c == nil {
|
||||||
name := PickFirstBalancerName
|
name := pickfirst.Name
|
||||||
if rsc.LoadBalancingPolicy != nil {
|
if rsc.LoadBalancingPolicy != nil {
|
||||||
name = *rsc.LoadBalancingPolicy
|
name = *rsc.LoadBalancingPolicy
|
||||||
}
|
}
|
||||||
if balancer.Get(name) == nil {
|
if balancer.Get(name) == nil {
|
||||||
name = PickFirstBalancerName
|
name = pickfirst.Name
|
||||||
}
|
}
|
||||||
cfg := []map[string]any{{name: struct{}{}}}
|
cfg := []map[string]any{{name: struct{}{}}}
|
||||||
strCfg, err := json.Marshal(cfg)
|
strCfg, err := json.Marshal(cfg)
|
||||||
|
@ -218,7 +221,7 @@ func parseServiceConfig(js string) *serviceconfig.ParseResult {
|
||||||
WaitForReady: m.WaitForReady,
|
WaitForReady: m.WaitForReady,
|
||||||
Timeout: (*time.Duration)(m.Timeout),
|
Timeout: (*time.Duration)(m.Timeout),
|
||||||
}
|
}
|
||||||
if mc.RetryPolicy, err = convertRetryPolicy(m.RetryPolicy); err != nil {
|
if mc.RetryPolicy, err = convertRetryPolicy(m.RetryPolicy, maxAttempts); err != nil {
|
||||||
logger.Warningf("grpc: unmarshalling service config %s: %v", js, err)
|
logger.Warningf("grpc: unmarshalling service config %s: %v", js, err)
|
||||||
return &serviceconfig.ParseResult{Err: err}
|
return &serviceconfig.ParseResult{Err: err}
|
||||||
}
|
}
|
||||||
|
@ -264,7 +267,7 @@ func parseServiceConfig(js string) *serviceconfig.ParseResult {
|
||||||
return &serviceconfig.ParseResult{Config: &sc}
|
return &serviceconfig.ParseResult{Config: &sc}
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertRetryPolicy(jrp *jsonRetryPolicy) (p *internalserviceconfig.RetryPolicy, err error) {
|
func convertRetryPolicy(jrp *jsonRetryPolicy, maxAttempts int) (p *internalserviceconfig.RetryPolicy, err error) {
|
||||||
if jrp == nil {
|
if jrp == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -278,17 +281,16 @@ func convertRetryPolicy(jrp *jsonRetryPolicy) (p *internalserviceconfig.RetryPol
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if jrp.MaxAttempts < maxAttempts {
|
||||||
|
maxAttempts = jrp.MaxAttempts
|
||||||
|
}
|
||||||
rp := &internalserviceconfig.RetryPolicy{
|
rp := &internalserviceconfig.RetryPolicy{
|
||||||
MaxAttempts: jrp.MaxAttempts,
|
MaxAttempts: maxAttempts,
|
||||||
InitialBackoff: time.Duration(jrp.InitialBackoff),
|
InitialBackoff: time.Duration(jrp.InitialBackoff),
|
||||||
MaxBackoff: time.Duration(jrp.MaxBackoff),
|
MaxBackoff: time.Duration(jrp.MaxBackoff),
|
||||||
BackoffMultiplier: jrp.BackoffMultiplier,
|
BackoffMultiplier: jrp.BackoffMultiplier,
|
||||||
RetryableStatusCodes: make(map[codes.Code]bool),
|
RetryableStatusCodes: make(map[codes.Code]bool),
|
||||||
}
|
}
|
||||||
if rp.MaxAttempts > 5 {
|
|
||||||
// TODO(retry): Make the max maxAttempts configurable.
|
|
||||||
rp.MaxAttempts = 5
|
|
||||||
}
|
|
||||||
for _, code := range jrp.RetryableStatusCodes {
|
for _, code := range jrp.RetryableStatusCodes {
|
||||||
rp.RetryableStatusCodes[code] = true
|
rp.RetryableStatusCodes[code] = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
|
"math/rand"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -34,7 +35,6 @@ import (
|
||||||
"google.golang.org/grpc/internal/balancerload"
|
"google.golang.org/grpc/internal/balancerload"
|
||||||
"google.golang.org/grpc/internal/binarylog"
|
"google.golang.org/grpc/internal/binarylog"
|
||||||
"google.golang.org/grpc/internal/channelz"
|
"google.golang.org/grpc/internal/channelz"
|
||||||
"google.golang.org/grpc/internal/grpcrand"
|
|
||||||
"google.golang.org/grpc/internal/grpcutil"
|
"google.golang.org/grpc/internal/grpcutil"
|
||||||
imetadata "google.golang.org/grpc/internal/metadata"
|
imetadata "google.golang.org/grpc/internal/metadata"
|
||||||
iresolver "google.golang.org/grpc/internal/resolver"
|
iresolver "google.golang.org/grpc/internal/resolver"
|
||||||
|
@ -699,7 +699,7 @@ func (a *csAttempt) shouldRetry(err error) (bool, error) {
|
||||||
if max := float64(rp.MaxBackoff); cur > max {
|
if max := float64(rp.MaxBackoff); cur > max {
|
||||||
cur = max
|
cur = max
|
||||||
}
|
}
|
||||||
dur = time.Duration(grpcrand.Int63n(int64(cur)))
|
dur = time.Duration(rand.Int63n(int64(cur)))
|
||||||
cs.numRetriesSincePushback++
|
cs.numRetriesSincePushback++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,4 +19,4 @@
|
||||||
package grpc
|
package grpc
|
||||||
|
|
||||||
// Version is the current grpc version.
|
// Version is the current grpc version.
|
||||||
const Version = "1.64.0"
|
const Version = "1.65.0"
|
||||||
|
|
|
@ -24,7 +24,7 @@ github.com/census-instrumentation/opencensus-proto/gen-go/agent/trace/v1
|
||||||
github.com/census-instrumentation/opencensus-proto/gen-go/metrics/v1
|
github.com/census-instrumentation/opencensus-proto/gen-go/metrics/v1
|
||||||
github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1
|
github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1
|
||||||
github.com/census-instrumentation/opencensus-proto/gen-go/trace/v1
|
github.com/census-instrumentation/opencensus-proto/gen-go/trace/v1
|
||||||
# github.com/cespare/xxhash/v2 v2.2.0
|
# github.com/cespare/xxhash/v2 v2.3.0
|
||||||
## explicit; go 1.11
|
## explicit; go 1.11
|
||||||
github.com/cespare/xxhash/v2
|
github.com/cespare/xxhash/v2
|
||||||
# github.com/davecgh/go-spew v1.1.1
|
# github.com/davecgh/go-spew v1.1.1
|
||||||
|
@ -305,14 +305,15 @@ google.golang.org/genproto/googleapis/api/httpbody
|
||||||
# google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157
|
# google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157
|
||||||
## explicit; go 1.20
|
## explicit; go 1.20
|
||||||
google.golang.org/genproto/googleapis/rpc/status
|
google.golang.org/genproto/googleapis/rpc/status
|
||||||
# google.golang.org/grpc v1.64.0
|
# google.golang.org/grpc v1.65.0
|
||||||
## explicit; go 1.19
|
## explicit; go 1.21
|
||||||
google.golang.org/grpc
|
google.golang.org/grpc
|
||||||
google.golang.org/grpc/attributes
|
google.golang.org/grpc/attributes
|
||||||
google.golang.org/grpc/backoff
|
google.golang.org/grpc/backoff
|
||||||
google.golang.org/grpc/balancer
|
google.golang.org/grpc/balancer
|
||||||
google.golang.org/grpc/balancer/base
|
google.golang.org/grpc/balancer/base
|
||||||
google.golang.org/grpc/balancer/grpclb/state
|
google.golang.org/grpc/balancer/grpclb/state
|
||||||
|
google.golang.org/grpc/balancer/pickfirst
|
||||||
google.golang.org/grpc/balancer/roundrobin
|
google.golang.org/grpc/balancer/roundrobin
|
||||||
google.golang.org/grpc/binarylog/grpc_binarylog_v1
|
google.golang.org/grpc/binarylog/grpc_binarylog_v1
|
||||||
google.golang.org/grpc/channelz
|
google.golang.org/grpc/channelz
|
||||||
|
@ -334,7 +335,6 @@ google.golang.org/grpc/internal/channelz
|
||||||
google.golang.org/grpc/internal/credentials
|
google.golang.org/grpc/internal/credentials
|
||||||
google.golang.org/grpc/internal/envconfig
|
google.golang.org/grpc/internal/envconfig
|
||||||
google.golang.org/grpc/internal/grpclog
|
google.golang.org/grpc/internal/grpclog
|
||||||
google.golang.org/grpc/internal/grpcrand
|
|
||||||
google.golang.org/grpc/internal/grpcsync
|
google.golang.org/grpc/internal/grpcsync
|
||||||
google.golang.org/grpc/internal/grpcutil
|
google.golang.org/grpc/internal/grpcutil
|
||||||
google.golang.org/grpc/internal/idle
|
google.golang.org/grpc/internal/idle
|
||||||
|
|
Loading…
Reference in New Issue