vendor: update buildkit to v0.30.0-rc1
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
+698
-232
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright 2025 Google LLC
|
||||
// Copyright 2026 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright 2025 Google LLC
|
||||
// Copyright 2026 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright 2025 Google LLC
|
||||
// Copyright 2026 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright 2025 Google LLC
|
||||
// Copyright 2026 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
||||
+8
-4
@@ -1,4 +1,4 @@
|
||||
// Copyright 2025 Google LLC
|
||||
// Copyright 2026 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -66,9 +66,13 @@ const (
|
||||
// app_profile_id: profiles/prof_qux
|
||||
// }
|
||||
//
|
||||
// The routing header consists of one or multiple key-value pairs. Every key
|
||||
// and value must be percent-encoded, and joined together in the format of
|
||||
// `key1=value1&key2=value2`.
|
||||
// The routing header consists of one or multiple key-value pairs. The order of
|
||||
// the key-value pairs is undefined, the order of the `routing_parameters` in
|
||||
// the `RoutingRule` only matters for the evaluation order of the path
|
||||
// templates when `field` is the same. See the examples below for more details.
|
||||
//
|
||||
// Every key and value in the routing header must be percent-encoded,
|
||||
// and joined together in the following format: `key1=value1&key2=value2`.
|
||||
// The examples below skip the percent-encoding for readability.
|
||||
//
|
||||
// # Example 1
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright 2025 Google LLC
|
||||
// Copyright 2026 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright 2025 Google LLC
|
||||
// Copyright 2026 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
// Copyright 2025 Google LLC
|
||||
// Copyright 2026 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -957,17 +957,17 @@ type BadRequest_FieldViolation struct {
|
||||
// In this example, in proto `field` could take one of the following values:
|
||||
//
|
||||
// - `full_name` for a violation in the `full_name` value
|
||||
// - `email_addresses[1].email` for a violation in the `email` field of the
|
||||
// - `email_addresses[0].email` for a violation in the `email` field of the
|
||||
// first `email_addresses` message
|
||||
// - `email_addresses[3].type[2]` for a violation in the second `type`
|
||||
// - `email_addresses[2].type[1]` for a violation in the second `type`
|
||||
// value in the third `email_addresses` message.
|
||||
//
|
||||
// In JSON, the same values are represented as:
|
||||
//
|
||||
// - `fullName` for a violation in the `fullName` value
|
||||
// - `emailAddresses[1].email` for a violation in the `email` field of the
|
||||
// - `emailAddresses[0].email` for a violation in the `email` field of the
|
||||
// first `emailAddresses` message
|
||||
// - `emailAddresses[3].type[2]` for a violation in the second `type`
|
||||
// - `emailAddresses[2].type[1]` for a violation in the second `type`
|
||||
// value in the third `emailAddresses` message.
|
||||
Field string `protobuf:"bytes,1,opt,name=field,proto3" json:"field,omitempty"`
|
||||
// A description of why the request element is bad.
|
||||
|
||||
+3
-4
@@ -1,4 +1,4 @@
|
||||
// Copyright 2025 Google LLC
|
||||
// Copyright 2026 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -127,14 +127,13 @@ var file_google_rpc_status_proto_rawDesc = []byte{
|
||||
0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x64, 0x65, 0x74, 0x61,
|
||||
0x69, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
|
||||
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52,
|
||||
0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x42, 0x61, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e,
|
||||
0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x42, 0x5e, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e,
|
||||
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x70, 0x63, 0x42, 0x0b, 0x53, 0x74, 0x61, 0x74,
|
||||
0x75, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x37, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
||||
0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73,
|
||||
0x2f, 0x72, 0x70, 0x63, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x3b, 0x73, 0x74, 0x61, 0x74,
|
||||
0x75, 0x73, 0xf8, 0x01, 0x01, 0xa2, 0x02, 0x03, 0x52, 0x50, 0x43, 0x62, 0x06, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x33,
|
||||
0x75, 0x73, 0xa2, 0x02, 0x03, 0x52, 0x50, 0x43, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
+55
-22
@@ -27,6 +27,8 @@ package attributes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"iter"
|
||||
"maps"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -37,37 +39,46 @@ import (
|
||||
// any) bool', it will be called by (*Attributes).Equal to determine whether
|
||||
// two values with the same key should be considered equal.
|
||||
type Attributes struct {
|
||||
m map[any]any
|
||||
parent *Attributes
|
||||
key, value any
|
||||
}
|
||||
|
||||
// New returns a new Attributes containing the key/value pair.
|
||||
func New(key, value any) *Attributes {
|
||||
return &Attributes{m: map[any]any{key: value}}
|
||||
return &Attributes{
|
||||
key: key,
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
|
||||
// WithValue returns a new Attributes containing the previous keys and values
|
||||
// and the new key/value pair. If the same key appears multiple times, the
|
||||
// last value overwrites all previous values for that key. To remove an
|
||||
// existing key, use a nil value. value should not be modified later.
|
||||
// last value overwrites all previous values for that key. value should not be
|
||||
// modified later.
|
||||
//
|
||||
// Note that Attributes do not support deletion. Avoid using untyped nil values.
|
||||
// Since the Value method returns an untyped nil when a key is absent, it is
|
||||
// impossible to distinguish between a missing key and a key explicitly set to
|
||||
// an untyped nil. If you need to represent a value being unset, consider
|
||||
// storing a specific sentinel type or a wrapper struct with a boolean field
|
||||
// indicating presence.
|
||||
func (a *Attributes) WithValue(key, value any) *Attributes {
|
||||
if a == nil {
|
||||
return New(key, value)
|
||||
return &Attributes{
|
||||
parent: a,
|
||||
key: key,
|
||||
value: value,
|
||||
}
|
||||
n := &Attributes{m: make(map[any]any, len(a.m)+1)}
|
||||
for k, v := range a.m {
|
||||
n.m[k] = v
|
||||
}
|
||||
n.m[key] = value
|
||||
return n
|
||||
}
|
||||
|
||||
// Value returns the value associated with these attributes for key, or nil if
|
||||
// no value is associated with key. The returned value should not be modified.
|
||||
func (a *Attributes) Value(key any) any {
|
||||
if a == nil {
|
||||
return nil
|
||||
for cur := a; cur != nil; cur = cur.parent {
|
||||
if cur.key == key {
|
||||
return cur.value
|
||||
}
|
||||
}
|
||||
return a.m[key]
|
||||
return nil
|
||||
}
|
||||
|
||||
// Equal returns whether a and o are equivalent. If 'Equal(o any) bool' is
|
||||
@@ -83,11 +94,15 @@ func (a *Attributes) Equal(o *Attributes) bool {
|
||||
if a == nil || o == nil {
|
||||
return false
|
||||
}
|
||||
if len(a.m) != len(o.m) {
|
||||
return false
|
||||
if a == o {
|
||||
return true
|
||||
}
|
||||
for k, v := range a.m {
|
||||
ov, ok := o.m[k]
|
||||
m := maps.Collect(o.all())
|
||||
lenA := 0
|
||||
|
||||
for k, v := range a.all() {
|
||||
lenA++
|
||||
ov, ok := m[k]
|
||||
if !ok {
|
||||
// o missing element of a
|
||||
return false
|
||||
@@ -101,7 +116,7 @@ func (a *Attributes) Equal(o *Attributes) bool {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
return lenA == len(m)
|
||||
}
|
||||
|
||||
// String prints the attribute map. If any key or values throughout the map
|
||||
@@ -110,11 +125,11 @@ func (a *Attributes) String() string {
|
||||
var sb strings.Builder
|
||||
sb.WriteString("{")
|
||||
first := true
|
||||
for k, v := range a.m {
|
||||
for k, v := range a.all() {
|
||||
if !first {
|
||||
sb.WriteString(", ")
|
||||
}
|
||||
sb.WriteString(fmt.Sprintf("%q: %q ", str(k), str(v)))
|
||||
fmt.Fprintf(&sb, "%q: %q ", str(k), str(v))
|
||||
first = false
|
||||
}
|
||||
sb.WriteString("}")
|
||||
@@ -139,3 +154,21 @@ func str(x any) (s string) {
|
||||
func (a *Attributes) MarshalJSON() ([]byte, error) {
|
||||
return []byte(a.String()), nil
|
||||
}
|
||||
|
||||
// all returns an iterator that yields all key-value pairs in the Attributes
|
||||
// chain. If a key appears multiple times, only the most recently added value
|
||||
// is yielded.
|
||||
func (a *Attributes) all() iter.Seq2[any, any] {
|
||||
return func(yield func(any, any) bool) {
|
||||
seen := map[any]bool{}
|
||||
for cur := a; cur != nil; cur = cur.parent {
|
||||
if seen[cur.key] {
|
||||
continue
|
||||
}
|
||||
if !yield(cur.key, cur.value) {
|
||||
return
|
||||
}
|
||||
seen[cur.key] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
-15
@@ -33,6 +33,7 @@ import (
|
||||
estats "google.golang.org/grpc/experimental/stats"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
"google.golang.org/grpc/internal"
|
||||
"google.golang.org/grpc/internal/envconfig"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/resolver"
|
||||
"google.golang.org/grpc/serviceconfig"
|
||||
@@ -46,8 +47,8 @@ var (
|
||||
)
|
||||
|
||||
// Register registers the balancer builder to the balancer map. b.Name
|
||||
// (lowercased) will be used as the name registered with this builder. If the
|
||||
// Builder implements ConfigParser, ParseConfig will be called when new service
|
||||
// will be used as the name registered with this builder. If the Builder
|
||||
// implements ConfigParser, ParseConfig will be called when new service
|
||||
// configs are received by the resolver, and the result will be provided to the
|
||||
// Balancer in UpdateClientConnState.
|
||||
//
|
||||
@@ -55,12 +56,12 @@ var (
|
||||
// an init() function), and is not thread-safe. If multiple Balancers are
|
||||
// registered with the same name, the one registered last will take effect.
|
||||
func Register(b Builder) {
|
||||
name := strings.ToLower(b.Name())
|
||||
if name != b.Name() {
|
||||
// TODO: Skip the use of strings.ToLower() to index the map after v1.59
|
||||
// is released to switch to case sensitive balancer registry. Also,
|
||||
// remove this warning and update the docstrings for Register and Get.
|
||||
logger.Warningf("Balancer registered with name %q. grpc-go will be switching to case sensitive balancer registries soon", b.Name())
|
||||
name := b.Name()
|
||||
if !envconfig.CaseSensitiveBalancerRegistries {
|
||||
name = strings.ToLower(name)
|
||||
if name != b.Name() {
|
||||
logger.Warningf("Balancer registered with name %q. grpc-go will be switching to case sensitive balancer registries soon. After 2 releases, we will enable the env var by default.", b.Name())
|
||||
}
|
||||
}
|
||||
m[name] = b
|
||||
}
|
||||
@@ -78,16 +79,17 @@ func init() {
|
||||
}
|
||||
|
||||
// Get returns the resolver builder registered with the given name.
|
||||
// Note that the compare is done in a case-insensitive fashion.
|
||||
// Note that the compare is done in a case-sensitive fashion.
|
||||
// If no builder is register with the name, nil will be returned.
|
||||
func Get(name string) Builder {
|
||||
if strings.ToLower(name) != name {
|
||||
// TODO: Skip the use of strings.ToLower() to index the map after v1.59
|
||||
// is released to switch to case sensitive balancer registry. Also,
|
||||
// remove this warning and update the docstrings for Register and Get.
|
||||
logger.Warningf("Balancer retrieved for name %q. grpc-go will be switching to case sensitive balancer registries soon", name)
|
||||
if !envconfig.CaseSensitiveBalancerRegistries {
|
||||
lowerName := strings.ToLower(name)
|
||||
if lowerName != name {
|
||||
logger.Warningf("Balancer retrieved for name %q. grpc-go will be switching to case sensitive balancer registries soon. After 2 releases, we will enable the env var by default.", name)
|
||||
}
|
||||
name = lowerName
|
||||
}
|
||||
if b, ok := m[strings.ToLower(name)]; ok {
|
||||
if b, ok := m[name]; ok {
|
||||
return b
|
||||
}
|
||||
return nil
|
||||
|
||||
+2
-4
@@ -121,8 +121,7 @@ func (b *baseBalancer) UpdateClientConnState(s balancer.ClientConnState) error {
|
||||
sc.Connect()
|
||||
}
|
||||
}
|
||||
for _, a := range b.subConns.Keys() {
|
||||
sc, _ := b.subConns.Get(a)
|
||||
for a, sc := range b.subConns.All() {
|
||||
// a was removed by resolver.
|
||||
if _, ok := addrsSet.Get(a); !ok {
|
||||
sc.Shutdown()
|
||||
@@ -171,8 +170,7 @@ func (b *baseBalancer) regeneratePicker() {
|
||||
readySCs := make(map[balancer.SubConn]SubConnInfo)
|
||||
|
||||
// Filter out all ready SCs from full subConn map.
|
||||
for _, addr := range b.subConns.Keys() {
|
||||
sc, _ := b.subConns.Get(addr)
|
||||
for addr, sc := range b.subConns.All() {
|
||||
if st, ok := b.scStates[sc]; ok && st == connectivity.Ready {
|
||||
readySCs[sc] = SubConnInfo{Address: addr}
|
||||
}
|
||||
|
||||
+5
-6
@@ -187,8 +187,7 @@ func (es *endpointSharding) UpdateClientConnState(state balancer.ClientConnState
|
||||
}
|
||||
}
|
||||
// Delete old children that are no longer present.
|
||||
for _, e := range children.Keys() {
|
||||
child, _ := children.Get(e)
|
||||
for e, child := range children.All() {
|
||||
if _, ok := newChildren.Get(e); !ok {
|
||||
child.closeLocked()
|
||||
}
|
||||
@@ -212,7 +211,7 @@ func (es *endpointSharding) ResolverError(err error) {
|
||||
es.updateState()
|
||||
}()
|
||||
children := es.children.Load()
|
||||
for _, child := range children.Values() {
|
||||
for _, child := range children.All() {
|
||||
child.resolverErrorLocked(err)
|
||||
}
|
||||
}
|
||||
@@ -225,7 +224,7 @@ func (es *endpointSharding) Close() {
|
||||
es.childMu.Lock()
|
||||
defer es.childMu.Unlock()
|
||||
children := es.children.Load()
|
||||
for _, child := range children.Values() {
|
||||
for _, child := range children.All() {
|
||||
child.closeLocked()
|
||||
}
|
||||
}
|
||||
@@ -233,7 +232,7 @@ func (es *endpointSharding) Close() {
|
||||
func (es *endpointSharding) ExitIdle() {
|
||||
es.childMu.Lock()
|
||||
defer es.childMu.Unlock()
|
||||
for _, bw := range es.children.Load().Values() {
|
||||
for _, bw := range es.children.Load().All() {
|
||||
if !bw.isClosed {
|
||||
bw.child.ExitIdle()
|
||||
}
|
||||
@@ -255,7 +254,7 @@ func (es *endpointSharding) updateState() {
|
||||
children := es.children.Load()
|
||||
childStates := make([]ChildState, 0, children.Len())
|
||||
|
||||
for _, child := range children.Values() {
|
||||
for _, child := range children.All() {
|
||||
childState := child.childState
|
||||
childStates = append(childStates, childState)
|
||||
childPicker := childState.State.Picker
|
||||
|
||||
+6
-6
@@ -399,14 +399,14 @@ func (b *pickfirstBalancer) startFirstPassLocked() {
|
||||
b.firstPass = true
|
||||
b.numTF = 0
|
||||
// Reset the connection attempt record for existing SubConns.
|
||||
for _, sd := range b.subConns.Values() {
|
||||
for _, sd := range b.subConns.All() {
|
||||
sd.connectionFailedInFirstPass = false
|
||||
}
|
||||
b.requestConnectionLocked()
|
||||
}
|
||||
|
||||
func (b *pickfirstBalancer) closeSubConnsLocked() {
|
||||
for _, sd := range b.subConns.Values() {
|
||||
for _, sd := range b.subConns.All() {
|
||||
sd.subConn.Shutdown()
|
||||
}
|
||||
b.subConns = resolver.NewAddressMapV2[*scData]()
|
||||
@@ -506,7 +506,7 @@ func (b *pickfirstBalancer) reconcileSubConnsLocked(newAddrs []resolver.Address)
|
||||
newAddrsMap.Set(addr, true)
|
||||
}
|
||||
|
||||
for _, oldAddr := range b.subConns.Keys() {
|
||||
for oldAddr := range b.subConns.All() {
|
||||
if _, ok := newAddrsMap.Get(oldAddr); ok {
|
||||
continue
|
||||
}
|
||||
@@ -520,7 +520,7 @@ func (b *pickfirstBalancer) reconcileSubConnsLocked(newAddrs []resolver.Address)
|
||||
// becomes ready, which means that all other subConn must be shutdown.
|
||||
func (b *pickfirstBalancer) shutdownRemainingLocked(selected *scData) {
|
||||
b.cancelConnectionTimer()
|
||||
for _, sd := range b.subConns.Values() {
|
||||
for _, sd := range b.subConns.All() {
|
||||
if sd.subConn != selected.subConn {
|
||||
sd.subConn.Shutdown()
|
||||
}
|
||||
@@ -771,7 +771,7 @@ func (b *pickfirstBalancer) endFirstPassIfPossibleLocked(lastErr error) {
|
||||
}
|
||||
// Connect() has been called on all the SubConns. The first pass can be
|
||||
// ended if all the SubConns have reported a failure.
|
||||
for _, sd := range b.subConns.Values() {
|
||||
for _, sd := range b.subConns.All() {
|
||||
if !sd.connectionFailedInFirstPass {
|
||||
return
|
||||
}
|
||||
@@ -782,7 +782,7 @@ func (b *pickfirstBalancer) endFirstPassIfPossibleLocked(lastErr error) {
|
||||
Picker: &picker{err: lastErr},
|
||||
})
|
||||
// Start re-connecting all the SubConns that are already in IDLE.
|
||||
for _, sd := range b.subConns.Values() {
|
||||
for _, sd := range b.subConns.All() {
|
||||
if sd.rawConnectivityState == connectivity.Idle {
|
||||
sd.subConn.Connect()
|
||||
}
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.10
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v5.27.1
|
||||
// source: grpc/binlog/v1/binarylog.proto
|
||||
|
||||
|
||||
+8
-10
@@ -22,7 +22,6 @@ import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
@@ -52,22 +51,21 @@ func (t TLSInfo) AuthType() string {
|
||||
}
|
||||
|
||||
// ValidateAuthority validates the provided authority being used to override the
|
||||
// :authority header by verifying it against the peer certificates. It returns a
|
||||
// :authority header by verifying it against the peer certificate. It returns a
|
||||
// non-nil error if the validation fails.
|
||||
func (t TLSInfo) ValidateAuthority(authority string) error {
|
||||
var errs []error
|
||||
host, _, err := net.SplitHostPort(authority)
|
||||
if err != nil {
|
||||
host = authority
|
||||
}
|
||||
for _, cert := range t.State.PeerCertificates {
|
||||
var err error
|
||||
if err = cert.VerifyHostname(host); err == nil {
|
||||
return nil
|
||||
}
|
||||
errs = append(errs, err)
|
||||
|
||||
// Verify authority against the leaf certificate.
|
||||
if len(t.State.PeerCertificates) == 0 {
|
||||
// This is not expected to happen as the TLS handshake has already
|
||||
// completed and should have populated PeerCertificates.
|
||||
return fmt.Errorf("credentials: no peer certificates found to verify authority %q", host)
|
||||
}
|
||||
return fmt.Errorf("credentials: invalid authority %q: %v", authority, errors.Join(errs...))
|
||||
return t.State.PeerCertificates[0].VerifyHostname(host)
|
||||
}
|
||||
|
||||
// cipherSuiteLookup returns the string version of a TLS cipher suite ID.
|
||||
|
||||
+5
-4
@@ -705,10 +705,11 @@ func WithDisableHealthCheck() DialOption {
|
||||
func defaultDialOptions() dialOptions {
|
||||
return dialOptions{
|
||||
copts: transport.ConnectOptions{
|
||||
ReadBufferSize: defaultReadBufSize,
|
||||
WriteBufferSize: defaultWriteBufSize,
|
||||
UserAgent: grpcUA,
|
||||
BufferPool: mem.DefaultBufferPool(),
|
||||
ReadBufferSize: defaultReadBufSize,
|
||||
WriteBufferSize: defaultWriteBufSize,
|
||||
SharedWriteBuffer: true,
|
||||
UserAgent: grpcUA,
|
||||
BufferPool: mem.DefaultBufferPool(),
|
||||
},
|
||||
bs: internalbackoff.DefaultExponential,
|
||||
idleTimeout: 30 * time.Minute,
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.10
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v5.27.1
|
||||
// source: grpc/health/v1/health.proto
|
||||
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.0
|
||||
// - protoc-gen-go-grpc v1.6.1
|
||||
// - protoc v5.27.1
|
||||
// source: grpc/health/v1/health.proto
|
||||
|
||||
|
||||
+30
-8
@@ -54,17 +54,16 @@ var (
|
||||
|
||||
// XDSEndpointHashKeyBackwardCompat controls the parsing of the endpoint hash
|
||||
// key from EDS LbEndpoint metadata. Endpoint hash keys can be disabled by
|
||||
// setting "GRPC_XDS_ENDPOINT_HASH_KEY_BACKWARD_COMPAT" to "true". When the
|
||||
// implementation of A76 is stable, we will flip the default value to false
|
||||
// in a subsequent release. A final release will remove this environment
|
||||
// variable, enabling the new behavior unconditionally.
|
||||
XDSEndpointHashKeyBackwardCompat = boolFromEnv("GRPC_XDS_ENDPOINT_HASH_KEY_BACKWARD_COMPAT", true)
|
||||
// setting "GRPC_XDS_ENDPOINT_HASH_KEY_BACKWARD_COMPAT" to "true". A future
|
||||
// release will remove this environment variable, enabling the new behavior
|
||||
// unconditionally.
|
||||
XDSEndpointHashKeyBackwardCompat = boolFromEnv("GRPC_XDS_ENDPOINT_HASH_KEY_BACKWARD_COMPAT", false)
|
||||
|
||||
// RingHashSetRequestHashKey is set if the ring hash balancer can get the
|
||||
// request hash header by setting the "requestHashHeader" field, according
|
||||
// to gRFC A76. It can be enabled by setting the environment variable
|
||||
// "GRPC_EXPERIMENTAL_RING_HASH_SET_REQUEST_HASH_KEY" to "true".
|
||||
RingHashSetRequestHashKey = boolFromEnv("GRPC_EXPERIMENTAL_RING_HASH_SET_REQUEST_HASH_KEY", false)
|
||||
// to gRFC A76. It can be disabled by setting the environment variable
|
||||
// "GRPC_EXPERIMENTAL_RING_HASH_SET_REQUEST_HASH_KEY" to "false".
|
||||
RingHashSetRequestHashKey = boolFromEnv("GRPC_EXPERIMENTAL_RING_HASH_SET_REQUEST_HASH_KEY", true)
|
||||
|
||||
// ALTSHandshakerKeepaliveParams is set if we should add the
|
||||
// KeepaliveParams when dial the ALTS handshaker service.
|
||||
@@ -78,6 +77,14 @@ var (
|
||||
// - The DNS resolver is being used.
|
||||
EnableDefaultPortForProxyTarget = boolFromEnv("GRPC_EXPERIMENTAL_ENABLE_DEFAULT_PORT_FOR_PROXY_TARGET", true)
|
||||
|
||||
// CaseSensitiveBalancerRegistries is set if the balancer registry should be
|
||||
// case-sensitive. This is disabled by default, but can be enabled by setting
|
||||
// the env variable "GRPC_GO_EXPERIMENTAL_CASE_SENSITIVE_BALANCER_REGISTRIES"
|
||||
// to "true".
|
||||
//
|
||||
// TODO: After 2 releases, we will enable the env var by default.
|
||||
CaseSensitiveBalancerRegistries = boolFromEnv("GRPC_GO_EXPERIMENTAL_CASE_SENSITIVE_BALANCER_REGISTRIES", false)
|
||||
|
||||
// XDSAuthorityRewrite indicates whether xDS authority rewriting is enabled.
|
||||
// This feature is defined in gRFC A81 and is enabled by setting the
|
||||
// environment variable GRPC_EXPERIMENTAL_XDS_AUTHORITY_REWRITE to "true".
|
||||
@@ -89,6 +96,14 @@ var (
|
||||
// GRPC_EXPERIMENTAL_PF_WEIGHTED_SHUFFLING to "false".
|
||||
PickFirstWeightedShuffling = boolFromEnv("GRPC_EXPERIMENTAL_PF_WEIGHTED_SHUFFLING", true)
|
||||
|
||||
// XDSRecoverPanicInResourceParsing indicates whether the xdsclient should
|
||||
// recover from panics while parsing xDS resources.
|
||||
//
|
||||
// This feature can be disabled (e.g. for fuzz testing) by setting the
|
||||
// environment variable "GRPC_GO_EXPERIMENTAL_XDS_RESOURCE_PANIC_RECOVERY"
|
||||
// to "false".
|
||||
XDSRecoverPanicInResourceParsing = boolFromEnv("GRPC_GO_EXPERIMENTAL_XDS_RESOURCE_PANIC_RECOVERY", true)
|
||||
|
||||
// DisableStrictPathChecking indicates whether strict path checking is
|
||||
// disabled. This feature can be disabled by setting the environment
|
||||
// variable GRPC_GO_EXPERIMENTAL_DISABLE_STRICT_PATH_CHECKING to "true".
|
||||
@@ -104,6 +119,13 @@ var (
|
||||
// A future release will remove this environment variable, enabling strict
|
||||
// path checking behavior unconditionally.
|
||||
DisableStrictPathChecking = boolFromEnv("GRPC_GO_EXPERIMENTAL_DISABLE_STRICT_PATH_CHECKING", false)
|
||||
|
||||
// EnablePriorityLBChildPolicyCache controls whether the priority balancer
|
||||
// should cache child balancers that are removed from the LB policy config,
|
||||
// for a period of 15 minutes. This is disabled by default, but can be
|
||||
// enabled by setting the env variable
|
||||
// GRPC_EXPERIMENTAL_ENABLE_PRIORITY_LB_CHILD_POLICY_CACHE to true.
|
||||
EnablePriorityLBChildPolicyCache = boolFromEnv("GRPC_EXPERIMENTAL_ENABLE_PRIORITY_LB_CHILD_POLICY_CACHE", false)
|
||||
)
|
||||
|
||||
func boolFromEnv(envVar string, def bool) bool {
|
||||
|
||||
+338
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2026 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 mem provides utilities that facilitate memory reuse in byte slices
|
||||
// that are used as buffers.
|
||||
package mem
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/bits"
|
||||
"slices"
|
||||
"sort"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
goPageSize = 4 * 1024 // 4KiB. N.B. this must be a power of 2.
|
||||
)
|
||||
|
||||
var uintSize = bits.UintSize // use a variable for mocking during tests.
|
||||
|
||||
// bufferPool is a copy of the public bufferPool interface used to avoid
|
||||
// circular dependencies.
|
||||
type bufferPool interface {
|
||||
// Get returns a buffer with specified length from the pool.
|
||||
Get(length int) *[]byte
|
||||
|
||||
// Put returns a buffer to the pool.
|
||||
//
|
||||
// The provided pointer must hold a prefix of the buffer obtained via
|
||||
// BufferPool.Get to ensure the buffer's entire capacity can be re-used.
|
||||
Put(*[]byte)
|
||||
}
|
||||
|
||||
// BinaryTieredBufferPool is a buffer pool that uses multiple sub-pools with
|
||||
// power-of-two sizes.
|
||||
type BinaryTieredBufferPool struct {
|
||||
// exponentToNextLargestPoolMap maps a power-of-two exponent (e.g., 12 for
|
||||
// 4KB) to the index of the next largest sizedBufferPool. This is used by
|
||||
// Get() to find the smallest pool that can satisfy a request for a given
|
||||
// size.
|
||||
exponentToNextLargestPoolMap []int
|
||||
// exponentToPreviousLargestPoolMap maps a power-of-two exponent to the
|
||||
// index of the previous largest sizedBufferPool. This is used by Put()
|
||||
// to return a buffer to the most appropriate pool based on its capacity.
|
||||
exponentToPreviousLargestPoolMap []int
|
||||
sizedPools []bufferPool
|
||||
fallbackPool bufferPool
|
||||
maxPoolCap int // Optimization: Cache max capacity
|
||||
}
|
||||
|
||||
// NewBinaryTieredBufferPool returns a BufferPool backed by multiple sub-pools.
|
||||
// This structure enables O(1) lookup time for Get and Put operations.
|
||||
//
|
||||
// The arguments provided are the exponents for the buffer capacities (powers
|
||||
// of 2), not the raw byte sizes. For example, to create a pool of 16KB buffers
|
||||
// (2^14 bytes), pass 14 as the argument.
|
||||
func NewBinaryTieredBufferPool(powerOfTwoExponents ...uint8) (*BinaryTieredBufferPool, error) {
|
||||
return newBinaryTiered(func(size int) bufferPool {
|
||||
return newSizedBufferPool(size, true)
|
||||
}, &simpleBufferPool{shouldZero: true}, powerOfTwoExponents...)
|
||||
}
|
||||
|
||||
// NewDirtyBinaryTieredBufferPool returns a BufferPool backed by multiple
|
||||
// sub-pools. It is similar to NewBinaryTieredBufferPool but it does not
|
||||
// initialize the buffers before returning them.
|
||||
func NewDirtyBinaryTieredBufferPool(powerOfTwoExponents ...uint8) (*BinaryTieredBufferPool, error) {
|
||||
return newBinaryTiered(func(size int) bufferPool {
|
||||
return newSizedBufferPool(size, false)
|
||||
}, &simpleBufferPool{shouldZero: false}, powerOfTwoExponents...)
|
||||
}
|
||||
|
||||
func newBinaryTiered(sizedPoolFactory func(int) bufferPool, fallbackPool bufferPool, powerOfTwoExponents ...uint8) (*BinaryTieredBufferPool, error) {
|
||||
slices.Sort(powerOfTwoExponents)
|
||||
powerOfTwoExponents = slices.Compact(powerOfTwoExponents)
|
||||
|
||||
// Determine the maximum exponent we need to support. This depends on the
|
||||
// word size (32-bit vs 64-bit).
|
||||
maxExponent := uintSize - 2
|
||||
indexOfNextLargestBit := slices.Repeat([]int{-1}, maxExponent+1)
|
||||
indexOfPreviousLargestBit := slices.Repeat([]int{-1}, maxExponent+1)
|
||||
|
||||
maxTier := 0
|
||||
pools := make([]bufferPool, 0, len(powerOfTwoExponents))
|
||||
|
||||
for i, exp := range powerOfTwoExponents {
|
||||
// Allocating slices of size > 2^maxExponent isn't possible on
|
||||
// maxExponent-bit machines.
|
||||
if int(exp) > maxExponent {
|
||||
return nil, fmt.Errorf("mem: allocating slice of size 2^%d is not possible", exp)
|
||||
}
|
||||
tierSize := 1 << exp
|
||||
pools = append(pools, sizedPoolFactory(tierSize))
|
||||
maxTier = max(maxTier, tierSize)
|
||||
|
||||
// Map the exact power of 2 to this pool index.
|
||||
indexOfNextLargestBit[exp] = i
|
||||
indexOfPreviousLargestBit[exp] = i
|
||||
}
|
||||
|
||||
// Fill gaps for Get() (Next Largest)
|
||||
// We iterate backwards. If current is empty, take the value from the right (larger).
|
||||
for i := maxExponent - 1; i >= 0; i-- {
|
||||
if indexOfNextLargestBit[i] == -1 {
|
||||
indexOfNextLargestBit[i] = indexOfNextLargestBit[i+1]
|
||||
}
|
||||
}
|
||||
|
||||
// Fill gaps for Put() (Previous Largest)
|
||||
// We iterate forwards. If current is empty, take the value from the left (smaller).
|
||||
for i := 1; i <= maxExponent; i++ {
|
||||
if indexOfPreviousLargestBit[i] == -1 {
|
||||
indexOfPreviousLargestBit[i] = indexOfPreviousLargestBit[i-1]
|
||||
}
|
||||
}
|
||||
|
||||
return &BinaryTieredBufferPool{
|
||||
exponentToNextLargestPoolMap: indexOfNextLargestBit,
|
||||
exponentToPreviousLargestPoolMap: indexOfPreviousLargestBit,
|
||||
sizedPools: pools,
|
||||
maxPoolCap: maxTier,
|
||||
fallbackPool: fallbackPool,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Get returns a buffer with specified length from the pool.
|
||||
func (b *BinaryTieredBufferPool) Get(size int) *[]byte {
|
||||
return b.poolForGet(size).Get(size)
|
||||
}
|
||||
|
||||
func (b *BinaryTieredBufferPool) poolForGet(size int) bufferPool {
|
||||
if size == 0 || size > b.maxPoolCap {
|
||||
return b.fallbackPool
|
||||
}
|
||||
|
||||
// Calculate the exponent of the smallest power of 2 >= size.
|
||||
// We subtract 1 from size to handle exact powers of 2 correctly.
|
||||
//
|
||||
// Examples:
|
||||
// size=16 (0b10000) -> size-1=15 (0b01111) -> bits.Len=4 -> Pool for 2^4
|
||||
// size=17 (0b10001) -> size-1=16 (0b10000) -> bits.Len=5 -> Pool for 2^5
|
||||
querySize := uint(size - 1)
|
||||
poolIdx := b.exponentToNextLargestPoolMap[bits.Len(querySize)]
|
||||
|
||||
return b.sizedPools[poolIdx]
|
||||
}
|
||||
|
||||
// Put returns a buffer to the pool.
|
||||
func (b *BinaryTieredBufferPool) Put(buf *[]byte) {
|
||||
// We pass the capacity of the buffer, and not the size of the buffer here.
|
||||
// If we did the latter, all buffers would eventually move to the smallest
|
||||
// pool.
|
||||
b.poolForPut(cap(*buf)).Put(buf)
|
||||
}
|
||||
|
||||
func (b *BinaryTieredBufferPool) poolForPut(bCap int) bufferPool {
|
||||
if bCap == 0 {
|
||||
return NopBufferPool{}
|
||||
}
|
||||
if bCap > b.maxPoolCap {
|
||||
return b.fallbackPool
|
||||
}
|
||||
// Find the pool with the largest capacity <= bCap.
|
||||
//
|
||||
// We calculate the exponent of the largest power of 2 <= bCap.
|
||||
// bits.Len(x) returns the minimum number of bits required to represent x;
|
||||
// i.e. the number of bits up to and including the most significant bit.
|
||||
// Subtracting 1 gives the 0-based index of the most significant bit,
|
||||
// which is the exponent of the largest power of 2 <= bCap.
|
||||
//
|
||||
// Examples:
|
||||
// cap=16 (0b10000) -> Len=5 -> 5-1=4 -> 2^4
|
||||
// cap=15 (0b01111) -> Len=4 -> 4-1=3 -> 2^3
|
||||
largestPowerOfTwo := bits.Len(uint(bCap)) - 1
|
||||
poolIdx := b.exponentToPreviousLargestPoolMap[largestPowerOfTwo]
|
||||
// The buffer is smaller than the smallest power of 2, discard it.
|
||||
if poolIdx == -1 {
|
||||
// Buffer is smaller than our smallest pool bucket.
|
||||
return NopBufferPool{}
|
||||
}
|
||||
return b.sizedPools[poolIdx]
|
||||
}
|
||||
|
||||
// NopBufferPool is a buffer pool that returns new buffers without pooling.
|
||||
type NopBufferPool struct{}
|
||||
|
||||
// Get returns a buffer with specified length from the pool.
|
||||
func (NopBufferPool) Get(length int) *[]byte {
|
||||
b := make([]byte, length)
|
||||
return &b
|
||||
}
|
||||
|
||||
// Put returns a buffer to the pool.
|
||||
func (NopBufferPool) Put(*[]byte) {
|
||||
}
|
||||
|
||||
// sizedBufferPool is a BufferPool implementation that is optimized for specific
|
||||
// buffer sizes. For example, HTTP/2 frames within gRPC have a default max size
|
||||
// of 16kb and a sizedBufferPool can be configured to only return buffers with a
|
||||
// capacity of 16kb. Note that however it does not support returning larger
|
||||
// buffers and in fact panics if such a buffer is requested. Because of this,
|
||||
// this BufferPool implementation is not meant to be used on its own and rather
|
||||
// is intended to be embedded in a TieredBufferPool such that Get is only
|
||||
// invoked when the required size is smaller than or equal to defaultSize.
|
||||
type sizedBufferPool struct {
|
||||
pool sync.Pool
|
||||
defaultSize int
|
||||
shouldZero bool
|
||||
}
|
||||
|
||||
func (p *sizedBufferPool) Get(size int) *[]byte {
|
||||
buf, ok := p.pool.Get().(*[]byte)
|
||||
if !ok {
|
||||
buf := make([]byte, size, p.defaultSize)
|
||||
return &buf
|
||||
}
|
||||
b := *buf
|
||||
if p.shouldZero {
|
||||
clear(b[:cap(b)])
|
||||
}
|
||||
*buf = b[:size]
|
||||
return buf
|
||||
}
|
||||
|
||||
func (p *sizedBufferPool) Put(buf *[]byte) {
|
||||
if cap(*buf) < p.defaultSize {
|
||||
// Ignore buffers that are too small to fit in the pool. Otherwise, when
|
||||
// Get is called it will panic as it tries to index outside the bounds
|
||||
// of the buffer.
|
||||
return
|
||||
}
|
||||
p.pool.Put(buf)
|
||||
}
|
||||
|
||||
func newSizedBufferPool(size int, zero bool) *sizedBufferPool {
|
||||
return &sizedBufferPool{
|
||||
defaultSize: size,
|
||||
shouldZero: zero,
|
||||
}
|
||||
}
|
||||
|
||||
// TieredBufferPool implements the BufferPool interface with multiple tiers of
|
||||
// buffer pools for different sizes of buffers.
|
||||
type TieredBufferPool struct {
|
||||
sizedPools []*sizedBufferPool
|
||||
fallbackPool simpleBufferPool
|
||||
}
|
||||
|
||||
// NewTieredBufferPool returns a BufferPool implementation that uses multiple
|
||||
// underlying pools of the given pool sizes.
|
||||
func NewTieredBufferPool(poolSizes ...int) *TieredBufferPool {
|
||||
sort.Ints(poolSizes)
|
||||
pools := make([]*sizedBufferPool, len(poolSizes))
|
||||
for i, s := range poolSizes {
|
||||
pools[i] = newSizedBufferPool(s, true)
|
||||
}
|
||||
return &TieredBufferPool{
|
||||
sizedPools: pools,
|
||||
fallbackPool: simpleBufferPool{shouldZero: true},
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns a buffer with specified length from the pool.
|
||||
func (p *TieredBufferPool) Get(size int) *[]byte {
|
||||
return p.getPool(size).Get(size)
|
||||
}
|
||||
|
||||
// Put returns a buffer to the pool.
|
||||
func (p *TieredBufferPool) Put(buf *[]byte) {
|
||||
p.getPool(cap(*buf)).Put(buf)
|
||||
}
|
||||
|
||||
func (p *TieredBufferPool) getPool(size int) bufferPool {
|
||||
poolIdx := sort.Search(len(p.sizedPools), func(i int) bool {
|
||||
return p.sizedPools[i].defaultSize >= size
|
||||
})
|
||||
|
||||
if poolIdx == len(p.sizedPools) {
|
||||
return &p.fallbackPool
|
||||
}
|
||||
|
||||
return p.sizedPools[poolIdx]
|
||||
}
|
||||
|
||||
// simpleBufferPool is an implementation of the BufferPool interface that
|
||||
// attempts to pool buffers with a sync.Pool. When Get is invoked, it tries to
|
||||
// acquire a buffer from the pool but if that buffer is too small, it returns it
|
||||
// to the pool and creates a new one.
|
||||
type simpleBufferPool struct {
|
||||
pool sync.Pool
|
||||
shouldZero bool
|
||||
}
|
||||
|
||||
func (p *simpleBufferPool) Get(size int) *[]byte {
|
||||
bs, ok := p.pool.Get().(*[]byte)
|
||||
if ok && cap(*bs) >= size {
|
||||
if p.shouldZero {
|
||||
clear((*bs)[:cap(*bs)])
|
||||
}
|
||||
*bs = (*bs)[:size]
|
||||
return bs
|
||||
}
|
||||
|
||||
// A buffer was pulled from the pool, but it is too small. Put it back in
|
||||
// the pool and create one large enough.
|
||||
if ok {
|
||||
p.pool.Put(bs)
|
||||
}
|
||||
|
||||
// If we're going to allocate, round up to the nearest page. This way if
|
||||
// requests frequently arrive with small variation we don't allocate
|
||||
// repeatedly if we get unlucky and they increase over time. By default we
|
||||
// only allocate here if size > 1MiB. Because goPageSize is a power of 2, we
|
||||
// can round up efficiently.
|
||||
allocSize := (size + goPageSize - 1) & ^(goPageSize - 1)
|
||||
|
||||
b := make([]byte, size, allocSize)
|
||||
return &b
|
||||
}
|
||||
|
||||
func (p *simpleBufferPool) Put(buf *[]byte) {
|
||||
p.pool.Put(buf)
|
||||
}
|
||||
+1
@@ -46,6 +46,7 @@ const (
|
||||
defaultWriteQuota = 64 * 1024
|
||||
defaultClientMaxHeaderListSize = uint32(16 << 20)
|
||||
defaultServerMaxHeaderListSize = uint32(16 << 20)
|
||||
upcomingDefaultHeaderListSize = uint32(8 << 10)
|
||||
)
|
||||
|
||||
// MaxStreamID is the upper bound for the stream ID before the current
|
||||
|
||||
+5
-1
@@ -871,11 +871,15 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr, handler s
|
||||
}
|
||||
var sz int64
|
||||
for _, f := range hdr.hf {
|
||||
if sz += int64(f.Size()); sz > int64(*t.maxSendHeaderListSize) {
|
||||
sz += int64(f.Size())
|
||||
if sz > int64(*t.maxSendHeaderListSize) {
|
||||
hdrListSizeErr = status.Errorf(codes.Internal, "header list size to send violates the maximum size (%d bytes) set by server", *t.maxSendHeaderListSize)
|
||||
return false
|
||||
}
|
||||
}
|
||||
if sz > int64(upcomingDefaultHeaderListSize) {
|
||||
t.logger.Warningf("Header list size to send (%d bytes) is larger than the upcoming default limit (%d bytes). In a future release, this will be restricted to %d bytes.", sz, upcomingDefaultHeaderListSize, upcomingDefaultHeaderListSize)
|
||||
}
|
||||
return true
|
||||
}
|
||||
for {
|
||||
|
||||
+5
-1
@@ -940,13 +940,17 @@ func (t *http2Server) checkForHeaderListSize(hf []hpack.HeaderField) bool {
|
||||
}
|
||||
var sz int64
|
||||
for _, f := range hf {
|
||||
if sz += int64(f.Size()); sz > int64(*t.maxSendHeaderListSize) {
|
||||
sz += int64(f.Size())
|
||||
if sz > int64(*t.maxSendHeaderListSize) {
|
||||
if t.logger.V(logLevel) {
|
||||
t.logger.Infof("Header list size to send violates the maximum size (%d bytes) set by client", *t.maxSendHeaderListSize)
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
if sz > int64(upcomingDefaultHeaderListSize) {
|
||||
t.logger.Warningf("Header list size to send (%d bytes) is larger than the upcoming default limit (%d bytes). In a future release, this will be restricted to %d bytes.", sz, upcomingDefaultHeaderListSize, upcomingDefaultHeaderListSize)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
+29
-138
@@ -19,10 +19,10 @@
|
||||
package mem
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"sync"
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/grpc/internal"
|
||||
"google.golang.org/grpc/internal/mem"
|
||||
)
|
||||
|
||||
// BufferPool is a pool of buffers that can be shared and reused, resulting in
|
||||
@@ -38,20 +38,23 @@ type BufferPool interface {
|
||||
Put(*[]byte)
|
||||
}
|
||||
|
||||
const goPageSize = 4 << 10 // 4KiB. N.B. this must be a power of 2.
|
||||
|
||||
var defaultBufferPoolSizes = []int{
|
||||
256,
|
||||
goPageSize,
|
||||
16 << 10, // 16KB (max HTTP/2 frame size used by gRPC)
|
||||
32 << 10, // 32KB (default buffer size for io.Copy)
|
||||
1 << 20, // 1MB
|
||||
}
|
||||
|
||||
var defaultBufferPool BufferPool
|
||||
var (
|
||||
defaultBufferPoolSizeExponents = []uint8{
|
||||
8,
|
||||
12, // Go page size, 4KB
|
||||
14, // 16KB (max HTTP/2 frame size used by gRPC)
|
||||
15, // 32KB (default buffer size for io.Copy)
|
||||
20, // 1MB
|
||||
}
|
||||
defaultBufferPool BufferPool
|
||||
)
|
||||
|
||||
func init() {
|
||||
defaultBufferPool = NewTieredBufferPool(defaultBufferPoolSizes...)
|
||||
var err error
|
||||
defaultBufferPool, err = NewBinaryTieredBufferPool(defaultBufferPoolSizeExponents...)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Failed to create default buffer pool: %v", err))
|
||||
}
|
||||
|
||||
internal.SetDefaultBufferPool = func(pool BufferPool) {
|
||||
defaultBufferPool = pool
|
||||
@@ -72,134 +75,22 @@ func DefaultBufferPool() BufferPool {
|
||||
// NewTieredBufferPool returns a BufferPool implementation that uses multiple
|
||||
// underlying pools of the given pool sizes.
|
||||
func NewTieredBufferPool(poolSizes ...int) BufferPool {
|
||||
sort.Ints(poolSizes)
|
||||
pools := make([]*sizedBufferPool, len(poolSizes))
|
||||
for i, s := range poolSizes {
|
||||
pools[i] = newSizedBufferPool(s)
|
||||
}
|
||||
return &tieredBufferPool{
|
||||
sizedPools: pools,
|
||||
}
|
||||
return mem.NewTieredBufferPool(poolSizes...)
|
||||
}
|
||||
|
||||
// tieredBufferPool implements the BufferPool interface with multiple tiers of
|
||||
// buffer pools for different sizes of buffers.
|
||||
type tieredBufferPool struct {
|
||||
sizedPools []*sizedBufferPool
|
||||
fallbackPool simpleBufferPool
|
||||
// NewBinaryTieredBufferPool returns a BufferPool backed by multiple sub-pools.
|
||||
// This structure enables O(1) lookup time for Get and Put operations.
|
||||
//
|
||||
// The arguments provided are the exponents for the buffer capacities (powers
|
||||
// of 2), not the raw byte sizes. For example, to create a pool of 16KB buffers
|
||||
// (2^14 bytes), pass 14 as the argument.
|
||||
func NewBinaryTieredBufferPool(powerOfTwoExponents ...uint8) (BufferPool, error) {
|
||||
return mem.NewBinaryTieredBufferPool(powerOfTwoExponents...)
|
||||
}
|
||||
|
||||
func (p *tieredBufferPool) Get(size int) *[]byte {
|
||||
return p.getPool(size).Get(size)
|
||||
}
|
||||
|
||||
func (p *tieredBufferPool) Put(buf *[]byte) {
|
||||
p.getPool(cap(*buf)).Put(buf)
|
||||
}
|
||||
|
||||
func (p *tieredBufferPool) getPool(size int) BufferPool {
|
||||
poolIdx := sort.Search(len(p.sizedPools), func(i int) bool {
|
||||
return p.sizedPools[i].defaultSize >= size
|
||||
})
|
||||
|
||||
if poolIdx == len(p.sizedPools) {
|
||||
return &p.fallbackPool
|
||||
}
|
||||
|
||||
return p.sizedPools[poolIdx]
|
||||
}
|
||||
|
||||
// sizedBufferPool is a BufferPool implementation that is optimized for specific
|
||||
// buffer sizes. For example, HTTP/2 frames within gRPC have a default max size
|
||||
// of 16kb and a sizedBufferPool can be configured to only return buffers with a
|
||||
// capacity of 16kb. Note that however it does not support returning larger
|
||||
// buffers and in fact panics if such a buffer is requested. Because of this,
|
||||
// this BufferPool implementation is not meant to be used on its own and rather
|
||||
// is intended to be embedded in a tieredBufferPool such that Get is only
|
||||
// invoked when the required size is smaller than or equal to defaultSize.
|
||||
type sizedBufferPool struct {
|
||||
pool sync.Pool
|
||||
defaultSize int
|
||||
}
|
||||
|
||||
func (p *sizedBufferPool) Get(size int) *[]byte {
|
||||
buf, ok := p.pool.Get().(*[]byte)
|
||||
if !ok {
|
||||
buf := make([]byte, size, p.defaultSize)
|
||||
return &buf
|
||||
}
|
||||
b := *buf
|
||||
clear(b[:cap(b)])
|
||||
*buf = b[:size]
|
||||
return buf
|
||||
}
|
||||
|
||||
func (p *sizedBufferPool) Put(buf *[]byte) {
|
||||
if cap(*buf) < p.defaultSize {
|
||||
// Ignore buffers that are too small to fit in the pool. Otherwise, when
|
||||
// Get is called it will panic as it tries to index outside the bounds
|
||||
// of the buffer.
|
||||
return
|
||||
}
|
||||
p.pool.Put(buf)
|
||||
}
|
||||
|
||||
func newSizedBufferPool(size int) *sizedBufferPool {
|
||||
return &sizedBufferPool{
|
||||
defaultSize: size,
|
||||
}
|
||||
}
|
||||
|
||||
var _ BufferPool = (*simpleBufferPool)(nil)
|
||||
|
||||
// simpleBufferPool is an implementation of the BufferPool interface that
|
||||
// attempts to pool buffers with a sync.Pool. When Get is invoked, it tries to
|
||||
// acquire a buffer from the pool but if that buffer is too small, it returns it
|
||||
// to the pool and creates a new one.
|
||||
type simpleBufferPool struct {
|
||||
pool sync.Pool
|
||||
}
|
||||
|
||||
func (p *simpleBufferPool) Get(size int) *[]byte {
|
||||
bs, ok := p.pool.Get().(*[]byte)
|
||||
if ok && cap(*bs) >= size {
|
||||
clear((*bs)[:cap(*bs)])
|
||||
*bs = (*bs)[:size]
|
||||
return bs
|
||||
}
|
||||
|
||||
// A buffer was pulled from the pool, but it is too small. Put it back in
|
||||
// the pool and create one large enough.
|
||||
if ok {
|
||||
p.pool.Put(bs)
|
||||
}
|
||||
|
||||
// If we're going to allocate, round up to the nearest page. This way if
|
||||
// requests frequently arrive with small variation we don't allocate
|
||||
// repeatedly if we get unlucky and they increase over time. By default we
|
||||
// only allocate here if size > 1MiB. Because goPageSize is a power of 2, we
|
||||
// can round up efficiently.
|
||||
allocSize := (size + goPageSize - 1) & ^(goPageSize - 1)
|
||||
|
||||
b := make([]byte, size, allocSize)
|
||||
return &b
|
||||
}
|
||||
|
||||
func (p *simpleBufferPool) Put(buf *[]byte) {
|
||||
p.pool.Put(buf)
|
||||
// NopBufferPool is a buffer pool that returns new buffers without pooling.
|
||||
type NopBufferPool struct {
|
||||
mem.NopBufferPool
|
||||
}
|
||||
|
||||
var _ BufferPool = NopBufferPool{}
|
||||
|
||||
// NopBufferPool is a buffer pool that returns new buffers without pooling.
|
||||
type NopBufferPool struct{}
|
||||
|
||||
// Get returns a buffer with specified length from the pool.
|
||||
func (NopBufferPool) Get(length int) *[]byte {
|
||||
b := make([]byte, length)
|
||||
return &b
|
||||
}
|
||||
|
||||
// Put returns a buffer to the pool.
|
||||
func (NopBufferPool) Put(*[]byte) {
|
||||
}
|
||||
|
||||
+3
-1
@@ -192,7 +192,9 @@ func (pw *pickerWrapper) pick(ctx context.Context, failfast bool, info balancer.
|
||||
// DoneInfo with default value works.
|
||||
pickResult.Done(balancer.DoneInfo{})
|
||||
}
|
||||
logger.Infof("blockingPicker: the picked transport is not ready, loop back to repick")
|
||||
if logger.V(2) {
|
||||
logger.Infof("blockingPicker: the picked transport is not ready, loop back to repick")
|
||||
}
|
||||
// If ok == false, ac.state is not READY.
|
||||
// A valid picker always returns READY subConn. This means the state of ac
|
||||
// just changed, and picker will be updated shortly.
|
||||
|
||||
+34
@@ -20,6 +20,7 @@ package resolver
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"iter"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
@@ -135,6 +136,7 @@ func (a *AddressMapV2[T]) Len() int {
|
||||
}
|
||||
|
||||
// Keys returns a slice of all current map keys.
|
||||
// Deprecated: Use AddressMapV2.All() instead.
|
||||
func (a *AddressMapV2[T]) Keys() []Address {
|
||||
ret := make([]Address, 0, a.Len())
|
||||
for _, entryList := range a.m {
|
||||
@@ -146,6 +148,7 @@ func (a *AddressMapV2[T]) Keys() []Address {
|
||||
}
|
||||
|
||||
// Values returns a slice of all current map values.
|
||||
// Deprecated: Use AddressMapV2.All() instead.
|
||||
func (a *AddressMapV2[T]) Values() []T {
|
||||
ret := make([]T, 0, a.Len())
|
||||
for _, entryList := range a.m {
|
||||
@@ -156,6 +159,19 @@ func (a *AddressMapV2[T]) Values() []T {
|
||||
return ret
|
||||
}
|
||||
|
||||
// All returns an iterator over all elements.
|
||||
func (a *AddressMapV2[T]) All() iter.Seq2[Address, T] {
|
||||
return func(yield func(Address, T) bool) {
|
||||
for _, entryList := range a.m {
|
||||
for _, entry := range entryList {
|
||||
if !yield(entry.addr, entry.value) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type endpointMapKey string
|
||||
|
||||
// EndpointMap is a map of endpoints to arbitrary values keyed on only the
|
||||
@@ -223,6 +239,7 @@ func (em *EndpointMap[T]) Len() int {
|
||||
// the unordered set of addresses. Thus, endpoint information returned is not
|
||||
// the full endpoint data (drops duplicated addresses and attributes) but can be
|
||||
// used for EndpointMap accesses.
|
||||
// Deprecated: Use EndpointMap.All() instead.
|
||||
func (em *EndpointMap[T]) Keys() []Endpoint {
|
||||
ret := make([]Endpoint, 0, len(em.endpoints))
|
||||
for _, en := range em.endpoints {
|
||||
@@ -232,6 +249,7 @@ func (em *EndpointMap[T]) Keys() []Endpoint {
|
||||
}
|
||||
|
||||
// Values returns a slice of all current map values.
|
||||
// Deprecated: Use EndpointMap.All() instead.
|
||||
func (em *EndpointMap[T]) Values() []T {
|
||||
ret := make([]T, 0, len(em.endpoints))
|
||||
for _, val := range em.endpoints {
|
||||
@@ -240,6 +258,22 @@ func (em *EndpointMap[T]) Values() []T {
|
||||
return ret
|
||||
}
|
||||
|
||||
// All returns an iterator over all elements.
|
||||
// The map keys are endpoints specifying the addresses present in the endpoint
|
||||
// map, in which uniqueness is determined by the unordered set of addresses.
|
||||
// Thus, endpoint information returned is not the full endpoint data (drops
|
||||
// duplicated addresses and attributes) but can be used for EndpointMap
|
||||
// accesses.
|
||||
func (em *EndpointMap[T]) All() iter.Seq2[Endpoint, T] {
|
||||
return func(yield func(Endpoint, T) bool) {
|
||||
for _, en := range em.endpoints {
|
||||
if !yield(en.decodedKey, en.value) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete removes the specified endpoint from the map.
|
||||
func (em *EndpointMap[T]) Delete(e Endpoint) {
|
||||
en := encodeEndpoint(e)
|
||||
|
||||
+16
-6
@@ -961,24 +961,32 @@ func recvAndDecompress(p *parser, s recvCompressor, dc Decompressor, maxReceiveM
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// decompress processes the given data by decompressing it using either a custom decompressor or a standard compressor.
|
||||
// If a custom decompressor is provided, it takes precedence. The function validates that the decompressed data
|
||||
// does not exceed the specified maximum size and returns an error if this limit is exceeded.
|
||||
// On success, it returns the decompressed data. Otherwise, it returns an error if decompression fails or the data exceeds the size limit.
|
||||
// decompress processes the given data by decompressing it using either
|
||||
// a custom decompressor or a standard compressor. If a custom decompressor
|
||||
// is provided, it takes precedence. The function validates that
|
||||
// the decompressed data does not exceed the specified maximum size and returns
|
||||
// an error if this limit is exceeded. On success, it returns the decompressed
|
||||
// data. Otherwise, it returns an error if decompression fails or the data
|
||||
// exceeds the size limit.
|
||||
func decompress(compressor encoding.Compressor, d mem.BufferSlice, dc Decompressor, maxReceiveMessageSize int, pool mem.BufferPool) (mem.BufferSlice, error) {
|
||||
if dc != nil {
|
||||
uncompressed, err := dc.Do(d.Reader())
|
||||
r := d.Reader()
|
||||
uncompressed, err := dc.Do(r)
|
||||
if err != nil {
|
||||
r.Close() // ensure buffers are reused
|
||||
return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the received message: %v", err)
|
||||
}
|
||||
if len(uncompressed) > maxReceiveMessageSize {
|
||||
r.Close() // ensure buffers are reused
|
||||
return nil, status.Errorf(codes.ResourceExhausted, "grpc: message after decompression larger than max (%d vs. %d)", len(uncompressed), maxReceiveMessageSize)
|
||||
}
|
||||
return mem.BufferSlice{mem.SliceBuffer(uncompressed)}, nil
|
||||
}
|
||||
if compressor != nil {
|
||||
dcReader, err := compressor.Decompress(d.Reader())
|
||||
r := d.Reader()
|
||||
dcReader, err := compressor.Decompress(r)
|
||||
if err != nil {
|
||||
r.Close() // ensure buffers are reused
|
||||
return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the message: %v", err)
|
||||
}
|
||||
|
||||
@@ -990,11 +998,13 @@ func decompress(compressor encoding.Compressor, d mem.BufferSlice, dc Decompress
|
||||
}
|
||||
out, err := mem.ReadAll(dcReader, pool)
|
||||
if err != nil {
|
||||
r.Close() // ensure buffers are reused
|
||||
out.Free()
|
||||
return nil, status.Errorf(codes.Internal, "grpc: failed to read decompressed data: %v", err)
|
||||
}
|
||||
|
||||
if out.Len() > maxReceiveMessageSize {
|
||||
r.Close() // ensure buffers are reused
|
||||
out.Free()
|
||||
return nil, status.Errorf(codes.ResourceExhausted, "grpc: received message after decompression larger than max %d", maxReceiveMessageSize)
|
||||
}
|
||||
|
||||
+1
@@ -192,6 +192,7 @@ var defaultServerOptions = serverOptions{
|
||||
maxSendMessageSize: defaultServerMaxSendMessageSize,
|
||||
connectionTimeout: 120 * time.Second,
|
||||
writeBufferSize: defaultWriteBufSize,
|
||||
sharedWriteBuffer: true,
|
||||
readBufferSize: defaultReadBufSize,
|
||||
bufferPool: mem.DefaultBufferPool(),
|
||||
}
|
||||
|
||||
+1
-1
@@ -19,4 +19,4 @@
|
||||
package grpc
|
||||
|
||||
// Version is the current grpc version.
|
||||
const Version = "1.79.3"
|
||||
const Version = "1.80.0"
|
||||
|
||||
Reference in New Issue
Block a user