diff --git a/app/App.go b/app/App.go
index 95a0d104..34b387f0 100644
--- a/app/App.go
+++ b/app/App.go
@@ -20,7 +20,8 @@ import (
"context"
"fmt"
"github.com/caarlos0/env"
- constants "github.com/devtron-labs/common-lib/constants"
+ "github.com/devtron-labs/common-lib/constants"
+ "github.com/devtron-labs/common-lib/middlewares"
pubsub "github.com/devtron-labs/common-lib/pubsub-lib"
"github.com/devtron-labs/git-sensor/api"
"github.com/devtron-labs/git-sensor/bean"
@@ -29,6 +30,7 @@ import (
pb "github.com/devtron-labs/protos/gitSensor"
"github.com/go-pg/pg"
"github.com/gorilla/handlers"
+ "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging"
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/recovery"
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
"go.uber.org/zap"
@@ -54,10 +56,11 @@ type App struct {
pubSubClient *pubsub.PubSubClientServiceImpl
GrpcControllerImpl *api.GrpcHandlerImpl
StartupConfig *bean.StartupConfig
+ LoggerConfig *LoggerConfig
}
-func NewApp(MuxRouter *api.MuxRouter, Logger *zap.SugaredLogger, impl *git.GitWatcherImpl, db *pg.DB, pubSubClient *pubsub.PubSubClientServiceImpl, GrpcControllerImpl *api.GrpcHandlerImpl) *App {
- return &App{
+func NewApp(MuxRouter *api.MuxRouter, Logger *zap.SugaredLogger, impl *git.GitWatcherImpl, db *pg.DB, pubSubClient *pubsub.PubSubClientServiceImpl, GrpcControllerImpl *api.GrpcHandlerImpl) (*App, error) {
+ app := &App{
MuxRouter: MuxRouter,
Logger: Logger,
watcher: impl,
@@ -65,6 +68,22 @@ func NewApp(MuxRouter *api.MuxRouter, Logger *zap.SugaredLogger, impl *git.GitWa
pubSubClient: pubSubClient,
GrpcControllerImpl: GrpcControllerImpl,
}
+ cfg, err := GetLoggerConfig()
+ if err != nil {
+ return nil, err
+ }
+ app.LoggerConfig = cfg
+ return app, err
+}
+
+type LoggerConfig struct {
+ EnableLogger bool `env:"FEATURE_LOGGER_MIDDLEWARE_ENABLE" envDefault:"false"`
+}
+
+func GetLoggerConfig() (*LoggerConfig, error) {
+ cfg := &LoggerConfig{}
+ err := env.Parse(cfg)
+ return cfg, err
}
type PanicLogger struct {
@@ -137,9 +156,13 @@ func (app *App) initGrpcServer(port int) error {
}),
grpc.ChainStreamInterceptor(
grpc_prometheus.StreamServerInterceptor,
+ logging.StreamServerInterceptor(middlewares.InterceptorLogger(app.LoggerConfig.EnableLogger, app.Logger),
+ logging.WithLogOnEvents(logging.PayloadReceived)),
recovery.StreamServerInterceptor(recoveryOption)), // panic interceptor, should be at last
grpc.ChainUnaryInterceptor(
grpc_prometheus.UnaryServerInterceptor,
+ logging.UnaryServerInterceptor(middlewares.InterceptorLogger(app.LoggerConfig.EnableLogger, app.Logger),
+ logging.WithLogOnEvents(logging.PayloadReceived)),
recovery.UnaryServerInterceptor(recoveryOption)), // panic interceptor, should be at last
}
// create a new gRPC grpcServer
diff --git a/go.mod b/go.mod
index 73ac9f07..a6b1c62b 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.20
require (
github.com/caarlos0/env v3.5.0+incompatible
- github.com/devtron-labs/common-lib v0.0.16-0.20240318063710-69cb957d019a
+ github.com/devtron-labs/common-lib v0.0.16-0.20240418060324-b414ea7c74a3
github.com/devtron-labs/protos v0.0.3-0.20240130061723-7b2e12ab0abb
github.com/gammazero/workerpool v0.0.0-20200206003619-019d125201ab
github.com/go-git/go-git/v5 v5.11.0
@@ -12,15 +12,15 @@ require (
github.com/google/wire v0.4.0
github.com/gorilla/handlers v1.4.2
github.com/gorilla/mux v1.8.0
- github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1
+ github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
github.com/prometheus/client_golang v1.14.0
- github.com/robfig/cron/v3 v3.0.0
+ github.com/robfig/cron/v3 v3.0.1
github.com/stretchr/testify v1.8.4
github.com/tidwall/gjson v1.9.3
go.uber.org/zap v1.21.0
- golang.org/x/sys v0.15.0
- google.golang.org/grpc v1.56.3
+ golang.org/x/sys v0.17.0
+ google.golang.org/grpc v1.61.1
google.golang.org/protobuf v1.33.0
gopkg.in/src-d/go-billy.v4 v4.3.2
)
@@ -68,12 +68,13 @@ require (
github.com/xanzy/ssh-agent v0.3.3 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
- golang.org/x/crypto v0.17.0 // indirect
- golang.org/x/mod v0.12.0 // indirect
- golang.org/x/net v0.19.0 // indirect
+ golang.org/x/crypto v0.19.0 // indirect
+ golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect
+ golang.org/x/mod v0.15.0 // indirect
+ golang.org/x/net v0.21.0 // indirect
golang.org/x/text v0.14.0 // indirect
- golang.org/x/tools v0.13.0 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
+ golang.org/x/tools v0.18.0 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 // indirect
gopkg.in/fsnotify.v1 v1.4.7 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
diff --git a/go.sum b/go.sum
index 78d550bb..95b1d9a0 100644
--- a/go.sum
+++ b/go.sum
@@ -27,8 +27,8 @@ github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxG
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/devtron-labs/common-lib v0.0.16-0.20240318063710-69cb957d019a h1:6ik5mwqPW3/zNGCsV0kRh2zFQbECpOfeldflYQaRoVo=
-github.com/devtron-labs/common-lib v0.0.16-0.20240318063710-69cb957d019a/go.mod h1:6QrrtLoLnuEdHkrx5HqkEVwMxEmnhAH1R/SJVMswuCc=
+github.com/devtron-labs/common-lib v0.0.16-0.20240418060324-b414ea7c74a3 h1:aVxyjK5ZhtF6Xt7EL5us01BNff4xbGs/Rxc7LVArGeI=
+github.com/devtron-labs/common-lib v0.0.16-0.20240418060324-b414ea7c74a3/go.mod h1:1Zn+pXIj7ZOKHRe/AVfj2EdKjk+480wpSyYvu/v3ibY=
github.com/devtron-labs/protos v0.0.3-0.20240130061723-7b2e12ab0abb h1:CkfQQgZc950/hTPqtQSiHV2RmZgkBLGCzwR02FZYjAU=
github.com/devtron-labs/protos v0.0.3-0.20240130061723-7b2e12ab0abb/go.mod h1:pjLjgoa1GzbkOkvbMyP4SAKsaiK7eG6GoQCNauG03JA=
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
@@ -68,8 +68,8 @@ github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1 h1:HcUWd006luQPljE73d5sk+/VgYPGUReEVz2y1/qylwY=
-github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1/go.mod h1:w9Y7gY31krpLmrVU5ZPG9H7l9fZuRu5/3R3S3FMtVQ4=
+github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk=
+github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
@@ -120,8 +120,8 @@ github.com/prometheus/common v0.38.0 h1:VTQitp6mXTdUoCmDMugDVOJ1opi6ADftKfp/yeqT
github.com/prometheus/common v0.38.0/go.mod h1:MBXfmBQZrK5XpbCkjofnXs96LD2QQ7fEq4C0xjC/yec=
github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=
github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=
-github.com/robfig/cron/v3 v3.0.0 h1:kQ6Cb7aHOHTSzNVNEhmp8EcWKLb4CbiMW9h9VyIhO4E=
-github.com/robfig/cron/v3 v3.0.0/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
+github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
+github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
@@ -166,14 +166,16 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
-golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
-golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
+golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
+golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
+golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
+golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
-golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
+golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -184,14 +186,14 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
-golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
-golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
+golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
+golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
+golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -210,14 +212,14 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
-golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
+golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
-golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
+golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -227,7 +229,7 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
+golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
@@ -235,16 +237,16 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
-golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
-golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
+golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
+golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
-google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc=
-google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 h1:hZB7eLIaYlW9qXRfCq/qDaPdbeY3757uARz5Vvfv+cY=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:YUWgXUFRPfoYK1IHMuxH5K6nPEXSCzIMljnQ59lLRCk=
+google.golang.org/grpc v1.61.1 h1:kLAiWrZs7YeDM6MumDe7m3y4aM6wacLzM1Y/wiLP9XY=
+google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
diff --git a/vendor/github.com/devtron-labs/common-lib/middlewares/logger.go b/vendor/github.com/devtron-labs/common-lib/middlewares/logger.go
new file mode 100644
index 00000000..04780a9b
--- /dev/null
+++ b/vendor/github.com/devtron-labs/common-lib/middlewares/logger.go
@@ -0,0 +1,39 @@
+package middlewares
+
+import (
+ "context"
+ "fmt"
+ "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging"
+ "go.uber.org/zap"
+ "golang.org/x/exp/slices"
+)
+
+const (
+ RequestFieldKey = "grpc.request.content"
+ MethodFieldKey = "grpc.method"
+)
+
+// InterceptorLogger adapts go-kit logger to interceptor logger.
+func InterceptorLogger(enableLogger bool, lg *zap.SugaredLogger) logging.Logger {
+ return logging.LoggerFunc(func(ctx context.Context, lvl logging.Level, msg string, fields ...any) {
+ if !enableLogger {
+ return
+ }
+ reqPayload := extractFromFields(fields, RequestFieldKey)
+ reqMethodName := extractFromFields(fields, MethodFieldKey)
+ message := fmt.Sprintf("AUDIT_LOG: requestMethod: %s, requestPayload: %s", reqMethodName, reqPayload)
+ lg.Info(message)
+ })
+}
+
+func getIndex(fields []any, fieldKey any) int {
+ return slices.Index(fields, fieldKey)
+}
+
+func extractFromFields(fields []any, key string) any {
+ index := getIndex(fields, key)
+ if index == -1 || index == len(fields) {
+ return ""
+ }
+ return fields[index+1]
+}
diff --git a/vendor/github.com/devtron-labs/common-lib/middlewares/recovery.go b/vendor/github.com/devtron-labs/common-lib/middlewares/recovery.go
new file mode 100644
index 00000000..6834f617
--- /dev/null
+++ b/vendor/github.com/devtron-labs/common-lib/middlewares/recovery.go
@@ -0,0 +1,28 @@
+package middlewares
+
+import (
+ "encoding/json"
+ "github.com/devtron-labs/common-lib/constants"
+ "log"
+ "net/http"
+ "runtime/debug"
+)
+
+func Recovery(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+
+ defer func() {
+ err := recover()
+ if err != nil {
+ log.Print(constants.PanicLogIdentifier, "recovered from panic", "err", err, "stack", string(debug.Stack()))
+ jsonBody, _ := json.Marshal(map[string]string{
+ "error": "internal server error",
+ })
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusInternalServerError)
+ w.Write(jsonBody)
+ }
+ }()
+ next.ServeHTTP(w, r)
+ })
+}
diff --git a/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go b/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go
index 9dcfc422..b1220be8 100644
--- a/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go
+++ b/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go
@@ -46,6 +46,9 @@ const (
CI_COMPLETE_TOPIC string = "CI-COMPLETE"
CI_COMPLETE_GROUP string = "CI-COMPLETE_GROUP-1"
CI_COMPLETE_DURABLE string = "CI-COMPLETE_DURABLE-1"
+ IMAGE_SCANNING_SUCCESS_TOPIC string = "IMAGE-SCANNING-SUCCESS"
+ IMAGE_SCANNING_SUCCESS_GROUP string = "IMAGE-SCANNING-SUCCESS-GROUP"
+ IMAGE_SCANNING_SUCCESS_DURABLE string = "IMAGE-SCANNING-SUCCESS-DURABLE"
APPLICATION_STATUS_UPDATE_TOPIC string = "APPLICATION_STATUS_UPDATE"
APPLICATION_STATUS_UPDATE_GROUP string = "APPLICATION_STATUS_UPDATE_GROUP-1"
APPLICATION_STATUS_UPDATE_DURABLE string = "APPLICATION_STATUS_UPDATE_DURABLE-1"
@@ -95,6 +98,9 @@ const (
CD_STAGE_SUCCESS_EVENT_TOPIC string = "CD-STAGE-SUCCESS-EVENT"
CD_STAGE_SUCCESS_EVENT_GROUP string = "CD-STAGE-SUCCESS-EVENT-GROUP"
CD_STAGE_SUCCESS_EVENT_DURABLE string = "CD-STAGE-SUCCESS-EVENT-DURABLE"
+ CD_PIPELINE_DELETE_EVENT_TOPIC string = "CD-PIPELINE-DELETE-EVENT"
+ CD_PIPELINE_DELETE_EVENT_GROUP string = "CD-PIPELINE-DELETE-EVENT-GROUP"
+ CD_PIPELINE_DELETE_EVENT_DURABLE string = "CD-PIPELINE-DELETE-EVENT-DURABLE"
)
type NatsTopic struct {
@@ -120,8 +126,9 @@ var natsTopicMapping = map[string]NatsTopic{
WEBHOOK_EVENT_TOPIC: {topicName: WEBHOOK_EVENT_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: WEBHOOK_EVENT_GROUP, consumerName: WEBHOOK_EVENT_DURABLE},
CD_BULK_DEPLOY_TRIGGER_TOPIC: {topicName: CD_BULK_DEPLOY_TRIGGER_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: CD_BULK_DEPLOY_TRIGGER_GROUP, consumerName: CD_BULK_DEPLOY_TRIGGER_DURABLE},
- CI_COMPLETE_TOPIC: {topicName: CI_COMPLETE_TOPIC, streamName: CI_RUNNER_STREAM, queueName: CI_COMPLETE_GROUP, consumerName: CI_COMPLETE_DURABLE},
- CD_STAGE_COMPLETE_TOPIC: {topicName: CD_STAGE_COMPLETE_TOPIC, streamName: CI_RUNNER_STREAM, queueName: CD_COMPLETE_GROUP, consumerName: CD_COMPLETE_DURABLE},
+ CI_COMPLETE_TOPIC: {topicName: CI_COMPLETE_TOPIC, streamName: CI_RUNNER_STREAM, queueName: CI_COMPLETE_GROUP, consumerName: CI_COMPLETE_DURABLE},
+ CD_STAGE_COMPLETE_TOPIC: {topicName: CD_STAGE_COMPLETE_TOPIC, streamName: CI_RUNNER_STREAM, queueName: CD_COMPLETE_GROUP, consumerName: CD_COMPLETE_DURABLE},
+ IMAGE_SCANNING_SUCCESS_TOPIC: {topicName: IMAGE_SCANNING_SUCCESS_TOPIC, streamName: CI_RUNNER_STREAM, queueName: IMAGE_SCANNING_SUCCESS_GROUP, consumerName: IMAGE_SCANNING_SUCCESS_DURABLE},
APPLICATION_STATUS_UPDATE_TOPIC: {topicName: APPLICATION_STATUS_UPDATE_TOPIC, streamName: KUBEWATCH_STREAM, queueName: APPLICATION_STATUS_UPDATE_GROUP, consumerName: APPLICATION_STATUS_UPDATE_DURABLE},
APPLICATION_STATUS_DELETE_TOPIC: {topicName: APPLICATION_STATUS_DELETE_TOPIC, streamName: KUBEWATCH_STREAM, queueName: APPLICATION_STATUS_DELETE_GROUP, consumerName: APPLICATION_STATUS_DELETE_DURABLE},
@@ -138,6 +145,8 @@ var natsTopicMapping = map[string]NatsTopic{
DEVTRON_CHART_INSTALL_TOPIC: {topicName: DEVTRON_CHART_INSTALL_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: DEVTRON_CHART_INSTALL_GROUP, consumerName: DEVTRON_CHART_INSTALL_DURABLE},
PANIC_ON_PROCESSING_TOPIC: {topicName: PANIC_ON_PROCESSING_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: PANIC_ON_PROCESSING_GROUP, consumerName: PANIC_ON_PROCESSING_DURABLE},
CD_STAGE_SUCCESS_EVENT_TOPIC: {topicName: CD_STAGE_SUCCESS_EVENT_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: CD_STAGE_SUCCESS_EVENT_GROUP, consumerName: CD_STAGE_SUCCESS_EVENT_DURABLE},
+
+ CD_PIPELINE_DELETE_EVENT_TOPIC: {topicName: CD_PIPELINE_DELETE_EVENT_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: CD_PIPELINE_DELETE_EVENT_GROUP, consumerName: CD_PIPELINE_DELETE_EVENT_DURABLE},
}
var NatsStreamWiseConfigMapping = map[string]NatsStreamConfig{
@@ -160,6 +169,7 @@ var NatsConsumerWiseConfigMapping = map[string]NatsConsumerConfig{
APPLICATION_STATUS_DELETE_DURABLE: {},
CD_COMPLETE_DURABLE: {},
CI_COMPLETE_DURABLE: {},
+ IMAGE_SCANNING_SUCCESS_DURABLE: {},
WEBHOOK_EVENT_DURABLE: {},
CD_TRIGGER_DURABLE: {},
BULK_HIBERNATE_DURABLE: {},
@@ -170,6 +180,8 @@ var NatsConsumerWiseConfigMapping = map[string]NatsConsumerConfig{
DEVTRON_CHART_INSTALL_DURABLE: {},
PANIC_ON_PROCESSING_DURABLE: {},
DEVTRON_TEST_CONSUMER: {},
+ CD_STAGE_SUCCESS_EVENT_DURABLE: {},
+ CD_PIPELINE_DELETE_EVENT_DURABLE: {},
}
// getConsumerConfigMap will fetch the consumer wise config from the json string
@@ -236,6 +248,20 @@ func ParseAndFillStreamWiseAndConsumerWiseConfigMaps() {
defaultConsumerConfigVal := defaultConfig.GetDefaultNatsConsumerConfig()
// initialise all the consumer wise config with default values or user defined values
+ updateNatsConsumerConfigMapping(defaultConsumerConfigVal, consumerConfigMap)
+
+ // initialise all the stream wise config with default values or user defined values
+ updateNatsStreamConfigMapping(defaultStreamConfigVal, streamConfigMap)
+}
+
+func updateNatsConsumerConfigMapping(defaultConsumerConfigVal NatsConsumerConfig, consumerConfigMap map[string]NatsConsumerConfig) {
+ //iterating through all nats topic mappings (assuming source of truth) to update any consumers if not present in consumer mapping
+ for _, natsTopic := range natsTopicMapping {
+ if _, ok := NatsConsumerWiseConfigMapping[natsTopic.consumerName]; !ok {
+ NatsConsumerWiseConfigMapping[natsTopic.consumerName] = NatsConsumerConfig{}
+ }
+ }
+ //initialise all the consumer wise config with default values or user defined values
for key, _ := range NatsConsumerWiseConfigMapping {
consumerConfig := defaultConsumerConfigVal
if _, ok := consumerConfigMap[key]; ok {
@@ -243,8 +269,9 @@ func ParseAndFillStreamWiseAndConsumerWiseConfigMaps() {
}
NatsConsumerWiseConfigMapping[key] = consumerConfig
}
+}
- // initialise all the consumer wise config with default values or user defined values
+func updateNatsStreamConfigMapping(defaultStreamConfigVal NatsStreamConfig, streamConfigMap map[string]NatsStreamConfig) {
for key, _ := range NatsStreamWiseConfigMapping {
streamConfig := defaultStreamConfigVal
if _, ok := streamConfigMap[key]; ok {
@@ -252,7 +279,6 @@ func ParseAndFillStreamWiseAndConsumerWiseConfigMaps() {
}
NatsStreamWiseConfigMapping[key] = streamConfig
}
-
}
func GetNatsTopic(topicName string) NatsTopic {
diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/callmeta.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/callmeta.go
new file mode 100644
index 00000000..16a18288
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/callmeta.go
@@ -0,0 +1,66 @@
+// Copyright (c) The go-grpc-middleware Authors.
+// Licensed under the Apache License 2.0.
+
+package interceptors
+
+import (
+ "fmt"
+ "strings"
+
+ "google.golang.org/grpc"
+)
+
+func splitFullMethodName(fullMethod string) (string, string) {
+ fullMethod = strings.TrimPrefix(fullMethod, "/") // remove leading slash
+ if i := strings.Index(fullMethod, "/"); i >= 0 {
+ return fullMethod[:i], fullMethod[i+1:]
+ }
+ return "unknown", "unknown"
+}
+
+type CallMeta struct {
+ ReqOrNil any
+ Typ GRPCType
+ Service string
+ Method string
+ IsClient bool
+}
+
+func NewClientCallMeta(fullMethod string, streamDesc *grpc.StreamDesc, reqOrNil any) CallMeta {
+ c := CallMeta{IsClient: true, ReqOrNil: reqOrNil, Typ: Unary}
+ if streamDesc != nil {
+ c.Typ = clientStreamType(streamDesc)
+ }
+ c.Service, c.Method = splitFullMethodName(fullMethod)
+ return c
+}
+
+func NewServerCallMeta(fullMethod string, streamInfo *grpc.StreamServerInfo, reqOrNil any) CallMeta {
+ c := CallMeta{IsClient: false, ReqOrNil: reqOrNil, Typ: Unary}
+ if streamInfo != nil {
+ c.Typ = serverStreamType(streamInfo)
+ }
+ c.Service, c.Method = splitFullMethodName(fullMethod)
+ return c
+}
+func (c CallMeta) FullMethod() string {
+ return fmt.Sprintf("/%s/%s", c.Service, c.Method)
+}
+
+func clientStreamType(desc *grpc.StreamDesc) GRPCType {
+ if desc.ClientStreams && !desc.ServerStreams {
+ return ClientStream
+ } else if !desc.ClientStreams && desc.ServerStreams {
+ return ServerStream
+ }
+ return BidiStream
+}
+
+func serverStreamType(info *grpc.StreamServerInfo) GRPCType {
+ if info.IsClientStream && !info.IsServerStream {
+ return ClientStream
+ } else if !info.IsClientStream && info.IsServerStream {
+ return ServerStream
+ }
+ return BidiStream
+}
diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/client.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/client.go
new file mode 100644
index 00000000..571e826e
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/client.go
@@ -0,0 +1,74 @@
+// Copyright (c) The go-grpc-middleware Authors.
+// Licensed under the Apache License 2.0.
+
+// Go gRPC Middleware monitoring interceptors for client-side gRPC.
+
+package interceptors
+
+import (
+ "context"
+ "io"
+ "time"
+
+ "google.golang.org/grpc"
+)
+
+// UnaryClientInterceptor is a gRPC client-side interceptor that provides reporting for Unary RPCs.
+func UnaryClientInterceptor(reportable ClientReportable) grpc.UnaryClientInterceptor {
+ return func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
+ r := newReport(NewClientCallMeta(method, nil, req))
+ reporter, newCtx := reportable.ClientReporter(ctx, r.callMeta)
+
+ reporter.PostMsgSend(req, nil, time.Since(r.startTime))
+ err := invoker(newCtx, method, req, reply, cc, opts...)
+ reporter.PostMsgReceive(reply, err, time.Since(r.startTime))
+ reporter.PostCall(err, time.Since(r.startTime))
+ return err
+ }
+}
+
+// StreamClientInterceptor is a gRPC client-side interceptor that provides reporting for Stream RPCs.
+func StreamClientInterceptor(reportable ClientReportable) grpc.StreamClientInterceptor {
+ return func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
+ r := newReport(NewClientCallMeta(method, desc, nil))
+ reporter, newCtx := reportable.ClientReporter(ctx, r.callMeta)
+
+ clientStream, err := streamer(newCtx, desc, cc, method, opts...)
+ if err != nil {
+ reporter.PostCall(err, time.Since(r.startTime))
+ return nil, err
+ }
+ return &monitoredClientStream{ClientStream: clientStream, startTime: r.startTime, reporter: reporter}, nil
+ }
+}
+
+// monitoredClientStream wraps grpc.ClientStream allowing each Sent/Recv of message to report.
+type monitoredClientStream struct {
+ grpc.ClientStream
+
+ startTime time.Time
+ reporter Reporter
+}
+
+func (s *monitoredClientStream) SendMsg(m any) error {
+ start := time.Now()
+ err := s.ClientStream.SendMsg(m)
+ s.reporter.PostMsgSend(m, err, time.Since(start))
+ return err
+}
+
+func (s *monitoredClientStream) RecvMsg(m any) error {
+ start := time.Now()
+ err := s.ClientStream.RecvMsg(m)
+ s.reporter.PostMsgReceive(m, err, time.Since(start))
+
+ if err == nil {
+ return nil
+ }
+ var postErr error
+ if err != io.EOF {
+ postErr = err
+ }
+ s.reporter.PostCall(postErr, time.Since(s.startTime))
+ return err
+}
diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/doc.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/doc.go
new file mode 100644
index 00000000..2608b9a4
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/doc.go
@@ -0,0 +1,12 @@
+// Copyright (c) The go-grpc-middleware Authors.
+// Licensed under the Apache License 2.0.
+
+//
+/*
+interceptor is an internal package used by higher level middlewares. It allows injecting custom code in various
+places of the gRPC lifecycle.
+
+This particular package is intended for use by other middleware, metric, logging or otherwise.
+This allows code to be shared between different implementations.
+*/
+package interceptors
diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging/doc.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging/doc.go
new file mode 100644
index 00000000..fcefda6d
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging/doc.go
@@ -0,0 +1,36 @@
+// Copyright (c) The go-grpc-middleware Authors.
+// Licensed under the Apache License 2.0.
+
+/*
+Package logging is a "parent" package for gRPC logging middlewares.
+
+The gRPC logging middleware populates request-scoped data to `logging.Fields` that relate to the current gRPC call
+(e.g. service and method names). You can extract/inject data in the propagated context using `logging.ExtractFields` and `logging.InjectFields`.
+
+Once the gRPC logging middleware has added the gRPC specific Fields to the ctx they will then be written with the log lines.
+
+All logging middleware will emit a final log statement. It is based on the error returned by the handler function,
+the gRPC status code, an error (if any) and it emits at a level controlled via `WithLevels`. You can control this behavior
+using `WithDecider`.
+
+# This parent package
+
+This particular package is intended for use by other middleware, logging or otherwise. It contains interfaces that other
+logging middlewares *could* share. This allows code to be shared between different implementations.
+
+# Field names
+
+All field names of loggers follow the OpenTracing semantics definitions, with `grpc.` prefix if needed:
+https://github.com/opentracing/specification/blob/master/semantic_conventions.md
+
+Implementations:
+
+* providers/kit
+* providers/logr
+* providers/logrus
+* providers/phuslog
+* providers/slog
+* providers/zap
+* providers/zerolog
+*/
+package logging
diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging/interceptors.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging/interceptors.go
new file mode 100644
index 00000000..45a546b7
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging/interceptors.go
@@ -0,0 +1,211 @@
+// Copyright (c) The go-grpc-middleware Authors.
+// Licensed under the Apache License 2.0.
+
+package logging
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "time"
+
+ "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/peer"
+ "google.golang.org/protobuf/proto"
+)
+
+type reporter struct {
+ interceptors.CallMeta
+
+ ctx context.Context
+ kind string
+ startCallLogged bool
+
+ opts *options
+ fields Fields
+ logger Logger
+}
+
+func (c *reporter) PostCall(err error, duration time.Duration) {
+ if !has(c.opts.loggableEvents, FinishCall) {
+ return
+ }
+ if err == io.EOF {
+ err = nil
+ }
+
+ code := c.opts.codeFunc(err)
+ fields := c.fields.WithUnique(ExtractFields(c.ctx))
+ fields = fields.AppendUnique(Fields{"grpc.code", code.String()})
+ if err != nil {
+ fields = fields.AppendUnique(Fields{"grpc.error", fmt.Sprintf("%v", err)})
+ }
+ c.logger.Log(c.ctx, c.opts.levelFunc(code), "finished call", fields.AppendUnique(c.opts.durationFieldFunc(duration))...)
+}
+
+func (c *reporter) PostMsgSend(payload any, err error, duration time.Duration) {
+ logLvl := c.opts.levelFunc(c.opts.codeFunc(err))
+ fields := c.fields.WithUnique(ExtractFields(c.ctx))
+ if err != nil {
+ fields = fields.AppendUnique(Fields{"grpc.error", fmt.Sprintf("%v", err)})
+ }
+ if !c.startCallLogged && has(c.opts.loggableEvents, StartCall) {
+ c.startCallLogged = true
+ c.logger.Log(c.ctx, logLvl, "started call", fields.AppendUnique(c.opts.durationFieldFunc(duration))...)
+ }
+
+ if err != nil || !has(c.opts.loggableEvents, PayloadSent) {
+ return
+ }
+ if c.CallMeta.IsClient {
+ p, ok := payload.(proto.Message)
+ if !ok {
+ c.logger.Log(
+ c.ctx,
+ LevelError,
+ "payload is not a google.golang.org/protobuf/proto.Message; programmatic error?",
+ fields.AppendUnique(Fields{"grpc.request.type", fmt.Sprintf("%T", payload)})...,
+ )
+ return
+ }
+
+ fields = fields.AppendUnique(Fields{"grpc.send.duration", duration.String(), "grpc.request.content", p})
+ fields = fields.AppendUnique(c.opts.durationFieldFunc(duration))
+ c.logger.Log(c.ctx, logLvl, "request sent", fields...)
+ } else {
+ p, ok := payload.(proto.Message)
+ if !ok {
+ c.logger.Log(
+ c.ctx,
+ LevelError,
+ "payload is not a google.golang.org/protobuf/proto.Message; programmatic error?",
+ fields.AppendUnique(Fields{"grpc.response.type", fmt.Sprintf("%T", payload)})...,
+ )
+ return
+ }
+
+ fields = fields.AppendUnique(Fields{"grpc.send.duration", duration.String(), "grpc.response.content", p})
+ fields = fields.AppendUnique(c.opts.durationFieldFunc(duration))
+ c.logger.Log(c.ctx, logLvl, "response sent", fields...)
+ }
+}
+
+func (c *reporter) PostMsgReceive(payload any, err error, duration time.Duration) {
+ logLvl := c.opts.levelFunc(c.opts.codeFunc(err))
+ fields := c.fields.WithUnique(ExtractFields(c.ctx))
+ if err != nil {
+ fields = fields.AppendUnique(Fields{"grpc.error", fmt.Sprintf("%v", err)})
+ }
+ if !c.startCallLogged && has(c.opts.loggableEvents, StartCall) {
+ c.startCallLogged = true
+ c.logger.Log(c.ctx, logLvl, "started call", fields.AppendUnique(c.opts.durationFieldFunc(duration))...)
+ }
+
+ if err != nil || !has(c.opts.loggableEvents, PayloadReceived) {
+ return
+ }
+ if !c.CallMeta.IsClient {
+ p, ok := payload.(proto.Message)
+ if !ok {
+ c.logger.Log(
+ c.ctx,
+ LevelError,
+ "payload is not a google.golang.org/protobuf/proto.Message; programmatic error?",
+ fields.AppendUnique(Fields{"grpc.request.type", fmt.Sprintf("%T", payload)})...,
+ )
+ return
+ }
+
+ fields = fields.AppendUnique(Fields{"grpc.recv.duration", duration.String(), "grpc.request.content", p})
+ fields = fields.AppendUnique(c.opts.durationFieldFunc(duration))
+ c.logger.Log(c.ctx, logLvl, "request received", fields...)
+ } else {
+ p, ok := payload.(proto.Message)
+ if !ok {
+ c.logger.Log(
+ c.ctx,
+ LevelError,
+ "payload is not a google.golang.org/protobuf/proto.Message; programmatic error?",
+ fields.AppendUnique(Fields{"grpc.response.type", fmt.Sprintf("%T", payload)})...,
+ )
+ return
+ }
+
+ fields = fields.AppendUnique(Fields{"grpc.recv.duration", duration.String(), "grpc.response.content", p})
+ fields = fields.AppendUnique(c.opts.durationFieldFunc(duration))
+ c.logger.Log(c.ctx, logLvl, "response received", fields...)
+ }
+}
+
+func reportable(logger Logger, opts *options) interceptors.CommonReportableFunc {
+ return func(ctx context.Context, c interceptors.CallMeta) (interceptors.Reporter, context.Context) {
+ kind := KindServerFieldValue
+ if c.IsClient {
+ kind = KindClientFieldValue
+ }
+
+ // Field dups from context override the common fields.
+ fields := newCommonFields(kind, c)
+ if opts.disableGrpcLogFields != nil {
+ fields = disableCommonLoggingFields(kind, c, opts.disableGrpcLogFields)
+ }
+ fields = fields.WithUnique(ExtractFields(ctx))
+
+ if !c.IsClient {
+ if peer, ok := peer.FromContext(ctx); ok {
+ fields = append(fields, "peer.address", peer.Addr.String())
+ }
+ }
+ if opts.fieldsFromCtxCallMetaFn != nil {
+ // fieldsFromCtxFn dups override the existing fields.
+ fields = opts.fieldsFromCtxCallMetaFn(ctx, c).AppendUnique(fields)
+ }
+
+ singleUseFields := Fields{"grpc.start_time", time.Now().Format(opts.timestampFormat)}
+ if d, ok := ctx.Deadline(); ok {
+ singleUseFields = singleUseFields.AppendUnique(Fields{"grpc.request.deadline", d.Format(opts.timestampFormat)})
+ }
+ return &reporter{
+ CallMeta: c,
+ ctx: ctx,
+ startCallLogged: false,
+ opts: opts,
+ fields: fields.WithUnique(singleUseFields),
+ logger: logger,
+ kind: kind,
+ }, InjectFields(ctx, fields)
+ }
+}
+
+// UnaryClientInterceptor returns a new unary client interceptor that optionally logs the execution of external gRPC calls.
+// Logger will read existing and write new logging.Fields available in current context.
+// See `ExtractFields` and `InjectFields` for details.
+func UnaryClientInterceptor(logger Logger, opts ...Option) grpc.UnaryClientInterceptor {
+ o := evaluateClientOpt(opts)
+ return interceptors.UnaryClientInterceptor(reportable(logger, o))
+}
+
+// StreamClientInterceptor returns a new streaming client interceptor that optionally logs the execution of external gRPC calls.
+// Logger will read existing and write new logging.Fields available in current context.
+// See `ExtractFields` and `InjectFields` for details.
+func StreamClientInterceptor(logger Logger, opts ...Option) grpc.StreamClientInterceptor {
+ o := evaluateClientOpt(opts)
+ return interceptors.StreamClientInterceptor(reportable(logger, o))
+}
+
+// UnaryServerInterceptor returns a new unary server interceptors that optionally logs endpoint handling.
+// Logger will read existing and write new logging.Fields available in current context.
+// See `ExtractFields` and `InjectFields` for details.
+func UnaryServerInterceptor(logger Logger, opts ...Option) grpc.UnaryServerInterceptor {
+ o := evaluateServerOpt(opts)
+ return interceptors.UnaryServerInterceptor(reportable(logger, o))
+}
+
+// StreamServerInterceptor returns a new stream server interceptors that optionally logs endpoint handling.
+// Logger will read existing and write new logging.Fields available in current context.
+// See `ExtractFields` and `InjectFields` for details..
+func StreamServerInterceptor(logger Logger, opts ...Option) grpc.StreamServerInterceptor {
+ o := evaluateServerOpt(opts)
+ return interceptors.StreamServerInterceptor(reportable(logger, o))
+}
diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging/logging.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging/logging.go
new file mode 100644
index 00000000..510344fd
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging/logging.go
@@ -0,0 +1,203 @@
+// Copyright (c) The go-grpc-middleware Authors.
+// Licensed under the Apache License 2.0.
+
+package logging
+
+import (
+ "context"
+
+ "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors"
+)
+
+var (
+ // SystemTag is tag representing an event inside gRPC call.
+ SystemTag = []string{"protocol", "grpc"}
+ // ComponentFieldKey is a tag representing the client/server that is calling.
+ ComponentFieldKey = "grpc.component"
+ KindServerFieldValue = "server"
+ KindClientFieldValue = "client"
+ ServiceFieldKey = "grpc.service"
+ MethodFieldKey = "grpc.method"
+ MethodTypeFieldKey = "grpc.method_type"
+)
+
+type fieldsCtxMarker struct{}
+
+var (
+ // fieldsCtxMarkerKey is the Context value marker that is used by logging middleware to read and write logging fields into context.
+ fieldsCtxMarkerKey = &fieldsCtxMarker{}
+)
+
+func newCommonFields(kind string, c interceptors.CallMeta) Fields {
+ return Fields{
+ SystemTag[0], SystemTag[1],
+ ComponentFieldKey, kind,
+ ServiceFieldKey, c.Service,
+ MethodFieldKey, c.Method,
+ MethodTypeFieldKey, string(c.Typ),
+ }
+}
+
+// disableCommonLoggingFields returns copy of newCommonFields with disabled fields removed from the following
+// default list. The following are the default logging fields:
+// - SystemTag[0]
+// - ComponentFieldKey
+// - ServiceFieldKey
+// - MethodFieldKey
+// - MethodTypeFieldKey
+func disableCommonLoggingFields(kind string, c interceptors.CallMeta, disableFields []string) Fields {
+ commonFields := newCommonFields(kind, c)
+ for _, key := range disableFields {
+ commonFields.Delete(key)
+ }
+ return commonFields
+}
+
+// Fields loosely represents key value pairs that adds context to log lines. The key has to be type of string, whereas
+// value can be an arbitrary object.
+type Fields []any
+
+// Iterator returns iterator that allows iterating over pair of elements representing field.
+// If number of elements is uneven, last element won't be included will be assumed as key with empty string value.
+// If key is not string, At will panic.
+func (f Fields) Iterator() *iter {
+ // We start from -2 as we iterate over two items per iteration and first iteration will advance iterator to 0.
+ return &iter{i: -2, f: f}
+}
+
+type iter struct {
+ f Fields
+ i int
+}
+
+func (i *iter) Next() bool {
+ if i.i >= len(i.f) {
+ return false
+ }
+
+ i.i += 2
+ return i.i < len(i.f)
+}
+
+func (i *iter) At() (k string, v any) {
+ if i.i < 0 || i.i >= len(i.f) {
+ return "", ""
+ }
+
+ if i.i+1 == len(i.f) {
+ // Non even number of elements, add empty string.
+ return i.f[i.i].(string), ""
+ }
+ return i.f[i.i].(string), i.f[i.i+1]
+}
+
+func (f *Fields) Delete(key string) {
+ i := f.Iterator()
+ for i.Next() {
+ k, _ := i.At()
+ if k != key {
+ continue
+ }
+ *f = append((*f)[:i.i], (*f)[i.i+2:]...)
+ return
+ }
+}
+
+// WithUnique returns copy of fields which is the union of all unique keys.
+// Any duplicates in the added or current fields will be deduplicated where first occurrence takes precedence.
+func (f Fields) WithUnique(add Fields) Fields {
+ if len(add) == 0 {
+ n := make(Fields, len(f))
+ copy(n, f)
+ return n
+ }
+
+ existing := map[any]struct{}{}
+ i := f.Iterator()
+ for i.Next() {
+ k, _ := i.At()
+ existing[k] = struct{}{}
+ }
+
+ n := make(Fields, len(f), len(f)+len(add))
+ copy(n, f)
+
+ a := add.Iterator()
+ for a.Next() {
+ k, v := a.At()
+ if _, ok := existing[k]; ok {
+ continue
+ }
+ n = append(n, k, v)
+ }
+ return n
+}
+
+// AppendUnique appends (can reuse array!) fields which does not occur in existing fields slice.
+func (f Fields) AppendUnique(add Fields) Fields {
+ if len(add) == 0 {
+ return f
+ }
+
+ a := add.Iterator()
+NextAddField:
+ for a.Next() {
+ k, v := a.At()
+ i := f.Iterator()
+ for i.Next() {
+ fk, _ := i.At()
+ if fk == k {
+ continue NextAddField
+ }
+ }
+ f = append(f, k, v)
+ }
+ return f
+}
+
+// ExtractFields returns logging fields from the context.
+// Fields can be added from the context using InjectFields. For example logging interceptor adds some (base) fields
+// into context when used.
+// If there are no fields in the context, it returns an empty Fields value.
+// Extracted fields are useful to construct your own logger that has fields from gRPC interceptors.
+func ExtractFields(ctx context.Context) Fields {
+ t, ok := ctx.Value(fieldsCtxMarkerKey).(Fields)
+ if !ok {
+ return nil
+ }
+ n := make(Fields, len(t))
+ copy(n, t)
+ return n
+}
+
+// InjectFields allows adding fields to any existing Fields that will be used by the logging interceptor or can be
+// extracted further in ExtractFields.
+// For explicitness, in case of duplicates, the newest field occurrence wins. This allows nested components to update
+// popular fields like grpc.component (e.g. server invoking gRPC client).
+//
+// Don't overuse mutation of fields to avoid surprises.
+func InjectFields(ctx context.Context, f Fields) context.Context {
+ return context.WithValue(ctx, fieldsCtxMarkerKey, f.WithUnique(ExtractFields(ctx)))
+}
+
+// InjectLogField is like InjectFields, just for one field.
+func InjectLogField(ctx context.Context, key string, val any) context.Context {
+ return InjectFields(ctx, Fields{key, val})
+}
+
+// Logger requires Log method, similar to experimental slog, allowing logging interceptor to be interoperable. Official
+// adapters for popular loggers are in `provider/` directory (separate modules). It's totally ok to copy simple function
+// implementation over.
+// TODO(bwplotka): Once slog is official, we could use slog method directly. Currently level is copied over, so we don't
+// depend on experimental module.
+// interface used for all our interceptors.
+type Logger interface {
+ Log(ctx context.Context, level Level, msg string, fields ...any)
+}
+
+// LoggerFunc is a function that also implements Logger interface.
+type LoggerFunc func(ctx context.Context, level Level, msg string, fields ...any)
+
+func (f LoggerFunc) Log(ctx context.Context, level Level, msg string, fields ...any) {
+ f(ctx, level, msg, fields...)
+}
diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging/options.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging/options.go
new file mode 100644
index 00000000..9f4a1736
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging/options.go
@@ -0,0 +1,223 @@
+// Copyright (c) The go-grpc-middleware Authors.
+// Licensed under the Apache License 2.0.
+
+package logging
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+)
+
+// LoggableEvent defines the events a log line can be added on.
+type LoggableEvent uint
+
+const (
+ // StartCall is a loggable event representing start of the gRPC call.
+ StartCall LoggableEvent = iota
+ // FinishCall is a loggable event representing finish of the gRPC call.
+ FinishCall
+ // PayloadReceived is a loggable event representing received request (server) or response (client).
+ // Log line for this event also includes (potentially big) proto.Message of that payload in
+ // "grpc.request.content" (server) or "grpc.response.content" (client) field.
+ // NOTE: This can get quite verbose, especially for streaming calls, use with caution (e.g. debug only purposes).
+ PayloadReceived
+ // PayloadSent is a loggable event representing sent response (server) or request (client).
+ // Log line for this event also includes (potentially big) proto.Message of that payload in
+ // "grpc.response.content" (server) or "grpc.request.content" (client) field.
+ // NOTE: This can get quite verbose, especially for streaming calls, use with caution (e.g. debug only purposes).
+ PayloadSent
+)
+
+func has(events []LoggableEvent, event LoggableEvent) bool {
+ for _, e := range events {
+ if e == event {
+ return true
+ }
+ }
+ return false
+}
+
+var (
+ defaultOptions = &options{
+ loggableEvents: []LoggableEvent{StartCall, FinishCall},
+ codeFunc: DefaultErrorToCode,
+ durationFieldFunc: DefaultDurationToFields,
+ // levelFunc depends if it's client or server.
+ levelFunc: nil,
+ timestampFormat: time.RFC3339,
+ disableGrpcLogFields: nil,
+ }
+)
+
+type options struct {
+ levelFunc CodeToLevel
+ loggableEvents []LoggableEvent
+ codeFunc ErrorToCode
+ durationFieldFunc DurationToFields
+ timestampFormat string
+ fieldsFromCtxCallMetaFn fieldsFromCtxCallMetaFn
+ disableGrpcLogFields []string
+}
+
+type Option func(*options)
+
+func evaluateServerOpt(opts []Option) *options {
+ optCopy := &options{}
+ *optCopy = *defaultOptions
+ optCopy.levelFunc = DefaultServerCodeToLevel
+ for _, o := range opts {
+ o(optCopy)
+ }
+ return optCopy
+}
+
+func evaluateClientOpt(opts []Option) *options {
+ optCopy := &options{}
+ *optCopy = *defaultOptions
+ optCopy.levelFunc = DefaultClientCodeToLevel
+ for _, o := range opts {
+ o(optCopy)
+ }
+ return optCopy
+}
+
+// DurationToFields function defines how to produce duration fields for logging.
+type DurationToFields func(duration time.Duration) Fields
+
+// ErrorToCode function determines the error code of an error.
+// This makes using custom errors with grpc middleware easier.
+type ErrorToCode func(err error) codes.Code
+
+func DefaultErrorToCode(err error) codes.Code {
+ return status.Code(err)
+}
+
+// CodeToLevel function defines the mapping between gRPC return codes and interceptor log level.
+type CodeToLevel func(code codes.Code) Level
+
+// DefaultServerCodeToLevel is the helper mapper that maps gRPC return codes to log levels for server side.
+func DefaultServerCodeToLevel(code codes.Code) Level {
+ switch code {
+ case codes.OK, codes.NotFound, codes.Canceled, codes.AlreadyExists, codes.InvalidArgument, codes.Unauthenticated:
+ return LevelInfo
+
+ case codes.DeadlineExceeded, codes.PermissionDenied, codes.ResourceExhausted, codes.FailedPrecondition, codes.Aborted,
+ codes.OutOfRange, codes.Unavailable:
+ return LevelWarn
+
+ case codes.Unknown, codes.Unimplemented, codes.Internal, codes.DataLoss:
+ return LevelError
+
+ default:
+ return LevelError
+ }
+}
+
+// DefaultClientCodeToLevel is the helper mapper that maps gRPC return codes to log levels for client side.
+func DefaultClientCodeToLevel(code codes.Code) Level {
+ switch code {
+ case codes.OK, codes.Canceled, codes.InvalidArgument, codes.NotFound, codes.AlreadyExists, codes.ResourceExhausted,
+ codes.FailedPrecondition, codes.Aborted, codes.OutOfRange:
+ return LevelDebug
+ case codes.Unknown, codes.DeadlineExceeded, codes.PermissionDenied, codes.Unauthenticated:
+ return LevelInfo
+ case codes.Unimplemented, codes.Internal, codes.Unavailable, codes.DataLoss:
+ return LevelWarn
+ default:
+ return LevelInfo
+ }
+}
+
+type (
+ fieldsFromCtxFn func(ctx context.Context) Fields
+ fieldsFromCtxCallMetaFn func(ctx context.Context, c interceptors.CallMeta) Fields
+)
+
+// WithFieldsFromContext allows overriding existing or adding extra fields to all log messages per given context
+func WithFieldsFromContext(f fieldsFromCtxFn) Option {
+ return func(o *options) {
+ o.fieldsFromCtxCallMetaFn = func(ctx context.Context, _ interceptors.CallMeta) Fields {
+ return f(ctx)
+ }
+ }
+}
+
+// WithFieldsFromContextAndCallMeta allows overriding existing or adding extra fields to all log messages per given context and interceptor.CallMeta
+func WithFieldsFromContextAndCallMeta(f fieldsFromCtxCallMetaFn) Option {
+ return func(o *options) {
+ o.fieldsFromCtxCallMetaFn = f
+ }
+}
+
+// WithLogOnEvents customizes on what events the gRPC interceptor should log on.
+func WithLogOnEvents(events ...LoggableEvent) Option {
+ return func(o *options) {
+ o.loggableEvents = events
+ }
+}
+
+// WithLevels customizes the function for mapping gRPC return codes and interceptor log level statements.
+func WithLevels(f CodeToLevel) Option {
+ return func(o *options) {
+ o.levelFunc = f
+ }
+}
+
+// WithCodes customizes the function for mapping errors to error codes.
+func WithCodes(f ErrorToCode) Option {
+ return func(o *options) {
+ o.codeFunc = f
+ }
+}
+
+// WithDurationField customizes the function for mapping request durations to log fields.
+func WithDurationField(f DurationToFields) Option {
+ return func(o *options) {
+ o.durationFieldFunc = f
+ }
+}
+
+// DefaultDurationToFields is the default implementation of converting request duration to a field.
+var DefaultDurationToFields = DurationToTimeMillisFields
+
+// DurationToTimeMillisFields converts the duration to milliseconds and uses the key `grpc.time_ms`.
+func DurationToTimeMillisFields(duration time.Duration) Fields {
+ return Fields{"grpc.time_ms", fmt.Sprintf("%v", durationToMilliseconds(duration))}
+}
+
+// DurationToDurationField uses a Duration field to log the request duration
+// and leaves it up to Log's encoder settings to determine how that is output.
+func DurationToDurationField(duration time.Duration) Fields {
+ return Fields{"grpc.duration", duration.String()}
+}
+
+func durationToMilliseconds(duration time.Duration) float32 {
+ return float32(duration.Nanoseconds()/1000) / 1000
+}
+
+// WithTimestampFormat customizes the timestamps emitted in the log fields.
+func WithTimestampFormat(format string) Option {
+ return func(o *options) {
+ o.timestampFormat = format
+ }
+}
+
+// WithDisableLoggingFields disables logging of gRPC fields provided.
+// The following are the default logging fields:
+// - SystemTag[0]
+// - ComponentFieldKey
+// - ServiceFieldKey
+// - MethodFieldKey
+// - MethodTypeFieldKey
+//
+// Usage example - WithDisableLoggingFields(logging.MethodFieldKey, logging.MethodTypeFieldKey)
+func WithDisableLoggingFields(disableGrpcLogFields ...string) Option {
+ return func(o *options) {
+ o.disableGrpcLogFields = disableGrpcLogFields
+ }
+}
diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging/slog.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging/slog.go
new file mode 100644
index 00000000..8861e46b
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging/slog.go
@@ -0,0 +1,46 @@
+// Copyright (c) The go-grpc-middleware Authors.
+// Licensed under the Apache License 2.0.
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// Copied from https://cs.opensource.google/go/x/exp/+/10a50721:slog/level.go
+
+package logging
+
+// A Level is the importance or severity of a log event.
+// The higher the level, the more important or severe the event.
+type Level int
+
+// Level numbers are inherently arbitrary,
+// but we picked them to satisfy three constraints.
+// Any system can map them to another numbering scheme if it wishes.
+//
+// First, we wanted the default level to be Info, Since Levels are ints, Info is
+// the default value for int, zero.
+//
+
+// Second, we wanted to make it easy to use levels to specify logger verbosity.
+// Since a larger level means a more severe event, a logger that accepts events
+// with smaller (or more negative) level means a more verbose logger. Logger
+// verbosity is thus the negation of event severity, and the default verbosity
+// of 0 accepts all events at least as severe as INFO.
+//
+// Third, we wanted some room between levels to accommodate schemes with named
+// levels between ours. For example, Google Cloud Logging defines a Notice level
+// between Info and Warn. Since there are only a few of these intermediate
+// levels, the gap between the numbers need not be large. Our gap of 4 matches
+// OpenTelemetry's mapping. Subtracting 9 from an OpenTelemetry level in the
+// DEBUG, INFO, WARN and ERROR ranges converts it to the corresponding slog
+// Level range. OpenTelemetry also has the names TRACE and FATAL, which slog
+// does not. But those OpenTelemetry levels can still be represented as slog
+// Levels by using the appropriate integers.
+//
+// Names for common levels.
+const (
+ LevelDebug Level = -4
+ LevelInfo Level = 0
+ LevelWarn Level = 4
+ LevelError Level = 8
+)
diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/reporter.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/reporter.go
new file mode 100644
index 00000000..c93a3af7
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/reporter.go
@@ -0,0 +1,75 @@
+// Copyright (c) The go-grpc-middleware Authors.
+// Licensed under the Apache License 2.0.
+
+package interceptors
+
+import (
+ "context"
+ "time"
+
+ "google.golang.org/grpc/codes"
+)
+
+type GRPCType string
+
+const (
+ Unary GRPCType = "unary"
+ ClientStream GRPCType = "client_stream"
+ ServerStream GRPCType = "server_stream"
+ BidiStream GRPCType = "bidi_stream"
+)
+
+var (
+ AllCodes = []codes.Code{
+ codes.OK, codes.Canceled, codes.Unknown, codes.InvalidArgument, codes.DeadlineExceeded, codes.NotFound,
+ codes.AlreadyExists, codes.PermissionDenied, codes.Unauthenticated, codes.ResourceExhausted,
+ codes.FailedPrecondition, codes.Aborted, codes.OutOfRange, codes.Unimplemented, codes.Internal,
+ codes.Unavailable, codes.DataLoss,
+ }
+)
+
+type ClientReportable interface {
+ ClientReporter(context.Context, CallMeta) (Reporter, context.Context)
+}
+
+type ServerReportable interface {
+ ServerReporter(context.Context, CallMeta) (Reporter, context.Context)
+}
+
+// CommonReportableFunc helper allows an easy way to implement reporter with common client and server logic.
+type CommonReportableFunc func(ctx context.Context, c CallMeta) (Reporter, context.Context)
+
+func (f CommonReportableFunc) ClientReporter(ctx context.Context, c CallMeta) (Reporter, context.Context) {
+ return f(ctx, c)
+}
+
+func (f CommonReportableFunc) ServerReporter(ctx context.Context, c CallMeta) (Reporter, context.Context) {
+ return f(ctx, c)
+}
+
+type Reporter interface {
+ PostCall(err error, rpcDuration time.Duration)
+ PostMsgSend(reqProto any, err error, sendDuration time.Duration)
+ PostMsgReceive(replyProto any, err error, recvDuration time.Duration)
+}
+
+var _ Reporter = NoopReporter{}
+
+type NoopReporter struct{}
+
+func (NoopReporter) PostCall(error, time.Duration) {}
+func (NoopReporter) PostMsgSend(any, error, time.Duration) {}
+func (NoopReporter) PostMsgReceive(any, error, time.Duration) {}
+
+type report struct {
+ callMeta CallMeta
+ startTime time.Time
+}
+
+func newReport(callMeta CallMeta) report {
+ r := report{
+ startTime: time.Now(),
+ callMeta: callMeta,
+ }
+ return r
+}
diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/server.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/server.go
new file mode 100644
index 00000000..04841090
--- /dev/null
+++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/server.go
@@ -0,0 +1,65 @@
+// Copyright (c) The go-grpc-middleware Authors.
+// Licensed under the Apache License 2.0.
+
+// Go gRPC Middleware monitoring interceptors for server-side gRPC.
+
+package interceptors
+
+import (
+ "context"
+ "time"
+
+ "google.golang.org/grpc"
+)
+
+// UnaryServerInterceptor is a gRPC server-side interceptor that provides reporting for Unary RPCs.
+func UnaryServerInterceptor(reportable ServerReportable) grpc.UnaryServerInterceptor {
+ return func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
+ r := newReport(NewServerCallMeta(info.FullMethod, nil, req))
+ reporter, newCtx := reportable.ServerReporter(ctx, r.callMeta)
+
+ reporter.PostMsgReceive(req, nil, time.Since(r.startTime))
+ resp, err := handler(newCtx, req)
+ reporter.PostMsgSend(resp, err, time.Since(r.startTime))
+
+ reporter.PostCall(err, time.Since(r.startTime))
+ return resp, err
+ }
+}
+
+// StreamServerInterceptor is a gRPC server-side interceptor that provides reporting for Streaming RPCs.
+func StreamServerInterceptor(reportable ServerReportable) grpc.StreamServerInterceptor {
+ return func(srv any, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
+ r := newReport(NewServerCallMeta(info.FullMethod, info, nil))
+ reporter, newCtx := reportable.ServerReporter(ss.Context(), r.callMeta)
+ err := handler(srv, &monitoredServerStream{ServerStream: ss, newCtx: newCtx, reporter: reporter})
+ reporter.PostCall(err, time.Since(r.startTime))
+ return err
+ }
+}
+
+// monitoredStream wraps grpc.ServerStream allowing each Sent/Recv of message to report.
+type monitoredServerStream struct {
+ grpc.ServerStream
+
+ newCtx context.Context
+ reporter Reporter
+}
+
+func (s *monitoredServerStream) Context() context.Context {
+ return s.newCtx
+}
+
+func (s *monitoredServerStream) SendMsg(m any) error {
+ start := time.Now()
+ err := s.ServerStream.SendMsg(m)
+ s.reporter.PostMsgSend(m, err, time.Since(start))
+ return err
+}
+
+func (s *monitoredServerStream) RecvMsg(m any) error {
+ start := time.Now()
+ err := s.ServerStream.RecvMsg(m)
+ s.reporter.PostMsgReceive(m, err, time.Since(start))
+ return err
+}
diff --git a/vendor/github.com/robfig/cron/v3/README.md b/vendor/github.com/robfig/cron/v3/README.md
index 8db4f550..984c537c 100644
--- a/vendor/github.com/robfig/cron/v3/README.md
+++ b/vendor/github.com/robfig/cron/v3/README.md
@@ -72,7 +72,7 @@ It is backwards incompatible with both v1 and v2. These updates are required:
// Seconds field, optional
cron.New(
cron.WithParser(
- cron.SecondOptional | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor))
+ cron.SecondOptional | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor))
- The Cron type now accepts functional options on construction rather than the
previous ad-hoc behavior modification mechanisms (setting a field, calling a setter).
@@ -118,7 +118,7 @@ There are two cron spec formats in common usage:
jobs in Java software
[the Cron wikipedia page]: https://en.wikipedia.org/wiki/Cron
-[the Quartz Scheduler]: http://www.quartz-scheduler.org/documentation/quartz-2.x/tutorials/crontrigger.html
+[the Quartz Scheduler]: http://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/tutorial-lesson-06.html
The original version of this package included an optional "seconds" field, which
made it incompatible with both of these formats. Now, the "standard" format is
diff --git a/vendor/github.com/robfig/cron/v3/chain.go b/vendor/github.com/robfig/cron/v3/chain.go
index 118e5bbe..9565b418 100644
--- a/vendor/github.com/robfig/cron/v3/chain.go
+++ b/vendor/github.com/robfig/cron/v3/chain.go
@@ -76,9 +76,9 @@ func DelayIfStillRunning(logger Logger) JobWrapper {
// SkipIfStillRunning skips an invocation of the Job if a previous invocation is
// still running. It logs skips to the given logger at Info level.
func SkipIfStillRunning(logger Logger) JobWrapper {
- var ch = make(chan struct{}, 1)
- ch <- struct{}{}
return func(j Job) Job {
+ var ch = make(chan struct{}, 1)
+ ch <- struct{}{}
return FuncJob(func() {
select {
case v := <-ch:
diff --git a/vendor/github.com/robfig/cron/v3/cron.go b/vendor/github.com/robfig/cron/v3/cron.go
index f6e451db..c7e91766 100644
--- a/vendor/github.com/robfig/cron/v3/cron.go
+++ b/vendor/github.com/robfig/cron/v3/cron.go
@@ -21,11 +21,16 @@ type Cron struct {
logger Logger
runningMu sync.Mutex
location *time.Location
- parser Parser
+ parser ScheduleParser
nextID EntryID
jobWaiter sync.WaitGroup
}
+// ScheduleParser is an interface for schedule spec parsers that return a Schedule
+type ScheduleParser interface {
+ Parse(spec string) (Schedule, error)
+}
+
// Job is an interface for submitted cron jobs.
type Job interface {
Run()
diff --git a/vendor/github.com/robfig/cron/v3/doc.go b/vendor/github.com/robfig/cron/v3/doc.go
index ac6b4b07..fa5d08b4 100644
--- a/vendor/github.com/robfig/cron/v3/doc.go
+++ b/vendor/github.com/robfig/cron/v3/doc.go
@@ -1,6 +1,18 @@
/*
Package cron implements a cron spec parser and job runner.
+Installation
+
+To download the specific tagged release, run:
+
+ go get github.com/robfig/cron/v3@v3.0.0
+
+Import it in your program as:
+
+ import "github.com/robfig/cron/v3"
+
+It requires Go 1.11 or later due to usage of Go Modules.
+
Usage
Callers may register Funcs to be invoked on a given schedule. Cron will run
@@ -9,7 +21,7 @@ them in their own goroutines.
c := cron.New()
c.AddFunc("30 * * * *", func() { fmt.Println("Every hour on the half hour") })
c.AddFunc("30 3-6,20-23 * * *", func() { fmt.Println(".. in the range 3-6am, 8-11pm") })
- c.AddFunc("CRON_TZ=Asia/Tokyo 30 04 * * * *", func() { fmt.Println("Runs at 04:30 Tokyo time every day") })
+ c.AddFunc("CRON_TZ=Asia/Tokyo 30 04 * * *", func() { fmt.Println("Runs at 04:30 Tokyo time every day") })
c.AddFunc("@hourly", func() { fmt.Println("Every hour, starting an hour from now") })
c.AddFunc("@every 1h30m", func() { fmt.Println("Every hour thirty, starting an hour thirty from now") })
c.Start()
@@ -47,11 +59,18 @@ Alternative Formats
Alternative Cron expression formats support other fields like seconds. You can
implement that by creating a custom Parser as follows.
- cron.New(
- cron.WithParser(
- cron.SecondOptional | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor))
+ cron.New(
+ cron.WithParser(
+ cron.NewParser(
+ cron.SecondOptional | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor)))
+
+Since adding Seconds is the most common modification to the standard cron spec,
+cron provides a builtin function to do that, which is equivalent to the custom
+parser you saw earlier, except that its seconds field is REQUIRED:
+
+ cron.New(cron.WithSeconds())
-The most popular alternative Cron expression format is Quartz:
+That emulates Quartz, the most popular alternative Cron schedule format:
http://www.quartz-scheduler.org/documentation/quartz-2.x/tutorials/crontrigger.html
Special Characters
@@ -150,7 +169,7 @@ The prefix "TZ=(TIME ZONE)" is also supported for legacy compatibility.
Be aware that jobs scheduled during daylight-savings leap-ahead transitions will
not be run!
-Job Wrappers / Chain
+Job Wrappers
A Cron runner may be configured with a chain of job wrappers to add
cross-cutting functionality to all submitted jobs. For example, they may be used
diff --git a/vendor/github.com/robfig/cron/v3/option.go b/vendor/github.com/robfig/cron/v3/option.go
index 07638201..09e4278e 100644
--- a/vendor/github.com/robfig/cron/v3/option.go
+++ b/vendor/github.com/robfig/cron/v3/option.go
@@ -23,7 +23,7 @@ func WithSeconds() Option {
}
// WithParser overrides the parser used for interpreting job schedules.
-func WithParser(p Parser) Option {
+func WithParser(p ScheduleParser) Option {
return func(c *Cron) {
c.parser = p
}
diff --git a/vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go b/vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go
deleted file mode 100644
index d33c8890..00000000
--- a/vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build !go1.13
-
-package poly1305
-
-// Generic fallbacks for the math/bits intrinsics, copied from
-// src/math/bits/bits.go. They were added in Go 1.12, but Add64 and Sum64 had
-// variable time fallbacks until Go 1.13.
-
-func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) {
- sum = x + y + carry
- carryOut = ((x & y) | ((x | y) &^ sum)) >> 63
- return
-}
-
-func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) {
- diff = x - y - borrow
- borrowOut = ((^x & y) | (^(x ^ y) & diff)) >> 63
- return
-}
-
-func bitsMul64(x, y uint64) (hi, lo uint64) {
- const mask32 = 1<<32 - 1
- x0 := x & mask32
- x1 := x >> 32
- y0 := y & mask32
- y1 := y >> 32
- w0 := x0 * y0
- t := x1*y0 + w0>>32
- w1 := t & mask32
- w2 := t >> 32
- w1 += x0 * y1
- hi = x1*y1 + w2 + w1>>32
- lo = x * y
- return
-}
diff --git a/vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go b/vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go
deleted file mode 100644
index 495c1fa6..00000000
--- a/vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build go1.13
-
-package poly1305
-
-import "math/bits"
-
-func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) {
- return bits.Add64(x, y, carry)
-}
-
-func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) {
- return bits.Sub64(x, y, borrow)
-}
-
-func bitsMul64(x, y uint64) (hi, lo uint64) {
- return bits.Mul64(x, y)
-}
diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go b/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go
index e041da5e..ec2202bd 100644
--- a/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go
+++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go
@@ -7,7 +7,10 @@
package poly1305
-import "encoding/binary"
+import (
+ "encoding/binary"
+ "math/bits"
+)
// Poly1305 [RFC 7539] is a relatively simple algorithm: the authentication tag
// for a 64 bytes message is approximately
@@ -114,13 +117,13 @@ type uint128 struct {
}
func mul64(a, b uint64) uint128 {
- hi, lo := bitsMul64(a, b)
+ hi, lo := bits.Mul64(a, b)
return uint128{lo, hi}
}
func add128(a, b uint128) uint128 {
- lo, c := bitsAdd64(a.lo, b.lo, 0)
- hi, c := bitsAdd64(a.hi, b.hi, c)
+ lo, c := bits.Add64(a.lo, b.lo, 0)
+ hi, c := bits.Add64(a.hi, b.hi, c)
if c != 0 {
panic("poly1305: unexpected overflow")
}
@@ -155,8 +158,8 @@ func updateGeneric(state *macState, msg []byte) {
// hide leading zeroes. For full chunks, that's 1 << 128, so we can just
// add 1 to the most significant (2¹²⁸) limb, h2.
if len(msg) >= TagSize {
- h0, c = bitsAdd64(h0, binary.LittleEndian.Uint64(msg[0:8]), 0)
- h1, c = bitsAdd64(h1, binary.LittleEndian.Uint64(msg[8:16]), c)
+ h0, c = bits.Add64(h0, binary.LittleEndian.Uint64(msg[0:8]), 0)
+ h1, c = bits.Add64(h1, binary.LittleEndian.Uint64(msg[8:16]), c)
h2 += c + 1
msg = msg[TagSize:]
@@ -165,8 +168,8 @@ func updateGeneric(state *macState, msg []byte) {
copy(buf[:], msg)
buf[len(msg)] = 1
- h0, c = bitsAdd64(h0, binary.LittleEndian.Uint64(buf[0:8]), 0)
- h1, c = bitsAdd64(h1, binary.LittleEndian.Uint64(buf[8:16]), c)
+ h0, c = bits.Add64(h0, binary.LittleEndian.Uint64(buf[0:8]), 0)
+ h1, c = bits.Add64(h1, binary.LittleEndian.Uint64(buf[8:16]), c)
h2 += c
msg = nil
@@ -219,9 +222,9 @@ func updateGeneric(state *macState, msg []byte) {
m3 := h2r1
t0 := m0.lo
- t1, c := bitsAdd64(m1.lo, m0.hi, 0)
- t2, c := bitsAdd64(m2.lo, m1.hi, c)
- t3, _ := bitsAdd64(m3.lo, m2.hi, c)
+ t1, c := bits.Add64(m1.lo, m0.hi, 0)
+ t2, c := bits.Add64(m2.lo, m1.hi, c)
+ t3, _ := bits.Add64(m3.lo, m2.hi, c)
// Now we have the result as 4 64-bit limbs, and we need to reduce it
// modulo 2¹³⁰ - 5. The special shape of this Crandall prime lets us do
@@ -243,14 +246,14 @@ func updateGeneric(state *macState, msg []byte) {
// To add c * 5 to h, we first add cc = c * 4, and then add (cc >> 2) = c.
- h0, c = bitsAdd64(h0, cc.lo, 0)
- h1, c = bitsAdd64(h1, cc.hi, c)
+ h0, c = bits.Add64(h0, cc.lo, 0)
+ h1, c = bits.Add64(h1, cc.hi, c)
h2 += c
cc = shiftRightBy2(cc)
- h0, c = bitsAdd64(h0, cc.lo, 0)
- h1, c = bitsAdd64(h1, cc.hi, c)
+ h0, c = bits.Add64(h0, cc.lo, 0)
+ h1, c = bits.Add64(h1, cc.hi, c)
h2 += c
// h2 is at most 3 + 1 + 1 = 5, making the whole of h at most
@@ -287,9 +290,9 @@ func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) {
// in constant time, we compute t = h - (2¹³⁰ - 5), and select h as the
// result if the subtraction underflows, and t otherwise.
- hMinusP0, b := bitsSub64(h0, p0, 0)
- hMinusP1, b := bitsSub64(h1, p1, b)
- _, b = bitsSub64(h2, p2, b)
+ hMinusP0, b := bits.Sub64(h0, p0, 0)
+ hMinusP1, b := bits.Sub64(h1, p1, b)
+ _, b = bits.Sub64(h2, p2, b)
// h = h if h < p else h - p
h0 = select64(b, h0, hMinusP0)
@@ -301,8 +304,8 @@ func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) {
//
// by just doing a wide addition with the 128 low bits of h and discarding
// the overflow.
- h0, c := bitsAdd64(h0, s[0], 0)
- h1, _ = bitsAdd64(h1, s[1], c)
+ h0, c := bits.Add64(h0, s[0], 0)
+ h1, _ = bits.Add64(h1, s[1], c)
binary.LittleEndian.PutUint64(out[0:8], h0)
binary.LittleEndian.PutUint64(out[8:16], h1)
diff --git a/vendor/golang.org/x/exp/LICENSE b/vendor/golang.org/x/exp/LICENSE
new file mode 100644
index 00000000..6a66aea5
--- /dev/null
+++ b/vendor/golang.org/x/exp/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/golang.org/x/exp/PATENTS b/vendor/golang.org/x/exp/PATENTS
new file mode 100644
index 00000000..73309904
--- /dev/null
+++ b/vendor/golang.org/x/exp/PATENTS
@@ -0,0 +1,22 @@
+Additional IP Rights Grant (Patents)
+
+"This implementation" means the copyrightable works distributed by
+Google as part of the Go project.
+
+Google hereby grants to You a perpetual, worldwide, non-exclusive,
+no-charge, royalty-free, irrevocable (except as stated in this section)
+patent license to make, have made, use, offer to sell, sell, import,
+transfer and otherwise run, modify and propagate the contents of this
+implementation of Go, where such license applies only to those patent
+claims, both currently owned or controlled by Google and acquired in
+the future, licensable by Google that are necessarily infringed by this
+implementation of Go. This grant does not include claims that would be
+infringed only as a consequence of further modification of this
+implementation. If you or your agent or exclusive licensee institute or
+order or agree to the institution of patent litigation against any
+entity (including a cross-claim or counterclaim in a lawsuit) alleging
+that this implementation of Go or any code incorporated within this
+implementation of Go constitutes direct or contributory patent
+infringement, or inducement of patent infringement, then any patent
+rights granted to you under this License for this implementation of Go
+shall terminate as of the date such litigation is filed.
diff --git a/vendor/golang.org/x/exp/constraints/constraints.go b/vendor/golang.org/x/exp/constraints/constraints.go
new file mode 100644
index 00000000..2c033dff
--- /dev/null
+++ b/vendor/golang.org/x/exp/constraints/constraints.go
@@ -0,0 +1,50 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package constraints defines a set of useful constraints to be used
+// with type parameters.
+package constraints
+
+// Signed is a constraint that permits any signed integer type.
+// If future releases of Go add new predeclared signed integer types,
+// this constraint will be modified to include them.
+type Signed interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64
+}
+
+// Unsigned is a constraint that permits any unsigned integer type.
+// If future releases of Go add new predeclared unsigned integer types,
+// this constraint will be modified to include them.
+type Unsigned interface {
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
+}
+
+// Integer is a constraint that permits any integer type.
+// If future releases of Go add new predeclared integer types,
+// this constraint will be modified to include them.
+type Integer interface {
+ Signed | Unsigned
+}
+
+// Float is a constraint that permits any floating-point type.
+// If future releases of Go add new predeclared floating-point types,
+// this constraint will be modified to include them.
+type Float interface {
+ ~float32 | ~float64
+}
+
+// Complex is a constraint that permits any complex numeric type.
+// If future releases of Go add new predeclared complex numeric types,
+// this constraint will be modified to include them.
+type Complex interface {
+ ~complex64 | ~complex128
+}
+
+// Ordered is a constraint that permits any ordered type: any type
+// that supports the operators < <= >= >.
+// If future releases of Go add new ordered types,
+// this constraint will be modified to include them.
+type Ordered interface {
+ Integer | Float | ~string
+}
diff --git a/vendor/golang.org/x/exp/slices/cmp.go b/vendor/golang.org/x/exp/slices/cmp.go
new file mode 100644
index 00000000..fbf1934a
--- /dev/null
+++ b/vendor/golang.org/x/exp/slices/cmp.go
@@ -0,0 +1,44 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package slices
+
+import "golang.org/x/exp/constraints"
+
+// min is a version of the predeclared function from the Go 1.21 release.
+func min[T constraints.Ordered](a, b T) T {
+ if a < b || isNaN(a) {
+ return a
+ }
+ return b
+}
+
+// max is a version of the predeclared function from the Go 1.21 release.
+func max[T constraints.Ordered](a, b T) T {
+ if a > b || isNaN(a) {
+ return a
+ }
+ return b
+}
+
+// cmpLess is a copy of cmp.Less from the Go 1.21 release.
+func cmpLess[T constraints.Ordered](x, y T) bool {
+ return (isNaN(x) && !isNaN(y)) || x < y
+}
+
+// cmpCompare is a copy of cmp.Compare from the Go 1.21 release.
+func cmpCompare[T constraints.Ordered](x, y T) int {
+ xNaN := isNaN(x)
+ yNaN := isNaN(y)
+ if xNaN && yNaN {
+ return 0
+ }
+ if xNaN || x < y {
+ return -1
+ }
+ if yNaN || x > y {
+ return +1
+ }
+ return 0
+}
diff --git a/vendor/golang.org/x/exp/slices/slices.go b/vendor/golang.org/x/exp/slices/slices.go
new file mode 100644
index 00000000..46ceac34
--- /dev/null
+++ b/vendor/golang.org/x/exp/slices/slices.go
@@ -0,0 +1,515 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package slices defines various functions useful with slices of any type.
+package slices
+
+import (
+ "unsafe"
+
+ "golang.org/x/exp/constraints"
+)
+
+// Equal reports whether two slices are equal: the same length and all
+// elements equal. If the lengths are different, Equal returns false.
+// Otherwise, the elements are compared in increasing index order, and the
+// comparison stops at the first unequal pair.
+// Floating point NaNs are not considered equal.
+func Equal[S ~[]E, E comparable](s1, s2 S) bool {
+ if len(s1) != len(s2) {
+ return false
+ }
+ for i := range s1 {
+ if s1[i] != s2[i] {
+ return false
+ }
+ }
+ return true
+}
+
+// EqualFunc reports whether two slices are equal using an equality
+// function on each pair of elements. If the lengths are different,
+// EqualFunc returns false. Otherwise, the elements are compared in
+// increasing index order, and the comparison stops at the first index
+// for which eq returns false.
+func EqualFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, eq func(E1, E2) bool) bool {
+ if len(s1) != len(s2) {
+ return false
+ }
+ for i, v1 := range s1 {
+ v2 := s2[i]
+ if !eq(v1, v2) {
+ return false
+ }
+ }
+ return true
+}
+
+// Compare compares the elements of s1 and s2, using [cmp.Compare] on each pair
+// of elements. The elements are compared sequentially, starting at index 0,
+// until one element is not equal to the other.
+// The result of comparing the first non-matching elements is returned.
+// If both slices are equal until one of them ends, the shorter slice is
+// considered less than the longer one.
+// The result is 0 if s1 == s2, -1 if s1 < s2, and +1 if s1 > s2.
+func Compare[S ~[]E, E constraints.Ordered](s1, s2 S) int {
+ for i, v1 := range s1 {
+ if i >= len(s2) {
+ return +1
+ }
+ v2 := s2[i]
+ if c := cmpCompare(v1, v2); c != 0 {
+ return c
+ }
+ }
+ if len(s1) < len(s2) {
+ return -1
+ }
+ return 0
+}
+
+// CompareFunc is like [Compare] but uses a custom comparison function on each
+// pair of elements.
+// The result is the first non-zero result of cmp; if cmp always
+// returns 0 the result is 0 if len(s1) == len(s2), -1 if len(s1) < len(s2),
+// and +1 if len(s1) > len(s2).
+func CompareFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, cmp func(E1, E2) int) int {
+ for i, v1 := range s1 {
+ if i >= len(s2) {
+ return +1
+ }
+ v2 := s2[i]
+ if c := cmp(v1, v2); c != 0 {
+ return c
+ }
+ }
+ if len(s1) < len(s2) {
+ return -1
+ }
+ return 0
+}
+
+// Index returns the index of the first occurrence of v in s,
+// or -1 if not present.
+func Index[S ~[]E, E comparable](s S, v E) int {
+ for i := range s {
+ if v == s[i] {
+ return i
+ }
+ }
+ return -1
+}
+
+// IndexFunc returns the first index i satisfying f(s[i]),
+// or -1 if none do.
+func IndexFunc[S ~[]E, E any](s S, f func(E) bool) int {
+ for i := range s {
+ if f(s[i]) {
+ return i
+ }
+ }
+ return -1
+}
+
+// Contains reports whether v is present in s.
+func Contains[S ~[]E, E comparable](s S, v E) bool {
+ return Index(s, v) >= 0
+}
+
+// ContainsFunc reports whether at least one
+// element e of s satisfies f(e).
+func ContainsFunc[S ~[]E, E any](s S, f func(E) bool) bool {
+ return IndexFunc(s, f) >= 0
+}
+
+// Insert inserts the values v... into s at index i,
+// returning the modified slice.
+// The elements at s[i:] are shifted up to make room.
+// In the returned slice r, r[i] == v[0],
+// and r[i+len(v)] == value originally at r[i].
+// Insert panics if i is out of range.
+// This function is O(len(s) + len(v)).
+func Insert[S ~[]E, E any](s S, i int, v ...E) S {
+ m := len(v)
+ if m == 0 {
+ return s
+ }
+ n := len(s)
+ if i == n {
+ return append(s, v...)
+ }
+ if n+m > cap(s) {
+ // Use append rather than make so that we bump the size of
+ // the slice up to the next storage class.
+ // This is what Grow does but we don't call Grow because
+ // that might copy the values twice.
+ s2 := append(s[:i], make(S, n+m-i)...)
+ copy(s2[i:], v)
+ copy(s2[i+m:], s[i:])
+ return s2
+ }
+ s = s[:n+m]
+
+ // before:
+ // s: aaaaaaaabbbbccccccccdddd
+ // ^ ^ ^ ^
+ // i i+m n n+m
+ // after:
+ // s: aaaaaaaavvvvbbbbcccccccc
+ // ^ ^ ^ ^
+ // i i+m n n+m
+ //
+ // a are the values that don't move in s.
+ // v are the values copied in from v.
+ // b and c are the values from s that are shifted up in index.
+ // d are the values that get overwritten, never to be seen again.
+
+ if !overlaps(v, s[i+m:]) {
+ // Easy case - v does not overlap either the c or d regions.
+ // (It might be in some of a or b, or elsewhere entirely.)
+ // The data we copy up doesn't write to v at all, so just do it.
+
+ copy(s[i+m:], s[i:])
+
+ // Now we have
+ // s: aaaaaaaabbbbbbbbcccccccc
+ // ^ ^ ^ ^
+ // i i+m n n+m
+ // Note the b values are duplicated.
+
+ copy(s[i:], v)
+
+ // Now we have
+ // s: aaaaaaaavvvvbbbbcccccccc
+ // ^ ^ ^ ^
+ // i i+m n n+m
+ // That's the result we want.
+ return s
+ }
+
+ // The hard case - v overlaps c or d. We can't just shift up
+ // the data because we'd move or clobber the values we're trying
+ // to insert.
+ // So instead, write v on top of d, then rotate.
+ copy(s[n:], v)
+
+ // Now we have
+ // s: aaaaaaaabbbbccccccccvvvv
+ // ^ ^ ^ ^
+ // i i+m n n+m
+
+ rotateRight(s[i:], m)
+
+ // Now we have
+ // s: aaaaaaaavvvvbbbbcccccccc
+ // ^ ^ ^ ^
+ // i i+m n n+m
+ // That's the result we want.
+ return s
+}
+
+// clearSlice sets all elements up to the length of s to the zero value of E.
+// We may use the builtin clear func instead, and remove clearSlice, when upgrading
+// to Go 1.21+.
+func clearSlice[S ~[]E, E any](s S) {
+ var zero E
+ for i := range s {
+ s[i] = zero
+ }
+}
+
+// Delete removes the elements s[i:j] from s, returning the modified slice.
+// Delete panics if j > len(s) or s[i:j] is not a valid slice of s.
+// Delete is O(len(s)-i), so if many items must be deleted, it is better to
+// make a single call deleting them all together than to delete one at a time.
+// Delete zeroes the elements s[len(s)-(j-i):len(s)].
+func Delete[S ~[]E, E any](s S, i, j int) S {
+ _ = s[i:j:len(s)] // bounds check
+
+ if i == j {
+ return s
+ }
+
+ oldlen := len(s)
+ s = append(s[:i], s[j:]...)
+ clearSlice(s[len(s):oldlen]) // zero/nil out the obsolete elements, for GC
+ return s
+}
+
+// DeleteFunc removes any elements from s for which del returns true,
+// returning the modified slice.
+// DeleteFunc zeroes the elements between the new length and the original length.
+func DeleteFunc[S ~[]E, E any](s S, del func(E) bool) S {
+ i := IndexFunc(s, del)
+ if i == -1 {
+ return s
+ }
+ // Don't start copying elements until we find one to delete.
+ for j := i + 1; j < len(s); j++ {
+ if v := s[j]; !del(v) {
+ s[i] = v
+ i++
+ }
+ }
+ clearSlice(s[i:]) // zero/nil out the obsolete elements, for GC
+ return s[:i]
+}
+
+// Replace replaces the elements s[i:j] by the given v, and returns the
+// modified slice. Replace panics if s[i:j] is not a valid slice of s.
+// When len(v) < (j-i), Replace zeroes the elements between the new length and the original length.
+func Replace[S ~[]E, E any](s S, i, j int, v ...E) S {
+ _ = s[i:j] // verify that i:j is a valid subslice
+
+ if i == j {
+ return Insert(s, i, v...)
+ }
+ if j == len(s) {
+ return append(s[:i], v...)
+ }
+
+ tot := len(s[:i]) + len(v) + len(s[j:])
+ if tot > cap(s) {
+ // Too big to fit, allocate and copy over.
+ s2 := append(s[:i], make(S, tot-i)...) // See Insert
+ copy(s2[i:], v)
+ copy(s2[i+len(v):], s[j:])
+ return s2
+ }
+
+ r := s[:tot]
+
+ if i+len(v) <= j {
+ // Easy, as v fits in the deleted portion.
+ copy(r[i:], v)
+ if i+len(v) != j {
+ copy(r[i+len(v):], s[j:])
+ }
+ clearSlice(s[tot:]) // zero/nil out the obsolete elements, for GC
+ return r
+ }
+
+ // We are expanding (v is bigger than j-i).
+ // The situation is something like this:
+ // (example has i=4,j=8,len(s)=16,len(v)=6)
+ // s: aaaaxxxxbbbbbbbbyy
+ // ^ ^ ^ ^
+ // i j len(s) tot
+ // a: prefix of s
+ // x: deleted range
+ // b: more of s
+ // y: area to expand into
+
+ if !overlaps(r[i+len(v):], v) {
+ // Easy, as v is not clobbered by the first copy.
+ copy(r[i+len(v):], s[j:])
+ copy(r[i:], v)
+ return r
+ }
+
+ // This is a situation where we don't have a single place to which
+ // we can copy v. Parts of it need to go to two different places.
+ // We want to copy the prefix of v into y and the suffix into x, then
+ // rotate |y| spots to the right.
+ //
+ // v[2:] v[:2]
+ // | |
+ // s: aaaavvvvbbbbbbbbvv
+ // ^ ^ ^ ^
+ // i j len(s) tot
+ //
+ // If either of those two destinations don't alias v, then we're good.
+ y := len(v) - (j - i) // length of y portion
+
+ if !overlaps(r[i:j], v) {
+ copy(r[i:j], v[y:])
+ copy(r[len(s):], v[:y])
+ rotateRight(r[i:], y)
+ return r
+ }
+ if !overlaps(r[len(s):], v) {
+ copy(r[len(s):], v[:y])
+ copy(r[i:j], v[y:])
+ rotateRight(r[i:], y)
+ return r
+ }
+
+ // Now we know that v overlaps both x and y.
+ // That means that the entirety of b is *inside* v.
+ // So we don't need to preserve b at all; instead we
+ // can copy v first, then copy the b part of v out of
+ // v to the right destination.
+ k := startIdx(v, s[j:])
+ copy(r[i:], v)
+ copy(r[i+len(v):], r[i+k:])
+ return r
+}
+
+// Clone returns a copy of the slice.
+// The elements are copied using assignment, so this is a shallow clone.
+func Clone[S ~[]E, E any](s S) S {
+ // Preserve nil in case it matters.
+ if s == nil {
+ return nil
+ }
+ return append(S([]E{}), s...)
+}
+
+// Compact replaces consecutive runs of equal elements with a single copy.
+// This is like the uniq command found on Unix.
+// Compact modifies the contents of the slice s and returns the modified slice,
+// which may have a smaller length.
+// Compact zeroes the elements between the new length and the original length.
+func Compact[S ~[]E, E comparable](s S) S {
+ if len(s) < 2 {
+ return s
+ }
+ i := 1
+ for k := 1; k < len(s); k++ {
+ if s[k] != s[k-1] {
+ if i != k {
+ s[i] = s[k]
+ }
+ i++
+ }
+ }
+ clearSlice(s[i:]) // zero/nil out the obsolete elements, for GC
+ return s[:i]
+}
+
+// CompactFunc is like [Compact] but uses an equality function to compare elements.
+// For runs of elements that compare equal, CompactFunc keeps the first one.
+// CompactFunc zeroes the elements between the new length and the original length.
+func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S {
+ if len(s) < 2 {
+ return s
+ }
+ i := 1
+ for k := 1; k < len(s); k++ {
+ if !eq(s[k], s[k-1]) {
+ if i != k {
+ s[i] = s[k]
+ }
+ i++
+ }
+ }
+ clearSlice(s[i:]) // zero/nil out the obsolete elements, for GC
+ return s[:i]
+}
+
+// Grow increases the slice's capacity, if necessary, to guarantee space for
+// another n elements. After Grow(n), at least n elements can be appended
+// to the slice without another allocation. If n is negative or too large to
+// allocate the memory, Grow panics.
+func Grow[S ~[]E, E any](s S, n int) S {
+ if n < 0 {
+ panic("cannot be negative")
+ }
+ if n -= cap(s) - len(s); n > 0 {
+ // TODO(https://go.dev/issue/53888): Make using []E instead of S
+ // to workaround a compiler bug where the runtime.growslice optimization
+ // does not take effect. Revert when the compiler is fixed.
+ s = append([]E(s)[:cap(s)], make([]E, n)...)[:len(s)]
+ }
+ return s
+}
+
+// Clip removes unused capacity from the slice, returning s[:len(s):len(s)].
+func Clip[S ~[]E, E any](s S) S {
+ return s[:len(s):len(s)]
+}
+
+// Rotation algorithm explanation:
+//
+// rotate left by 2
+// start with
+// 0123456789
+// split up like this
+// 01 234567 89
+// swap first 2 and last 2
+// 89 234567 01
+// join first parts
+// 89234567 01
+// recursively rotate first left part by 2
+// 23456789 01
+// join at the end
+// 2345678901
+//
+// rotate left by 8
+// start with
+// 0123456789
+// split up like this
+// 01 234567 89
+// swap first 2 and last 2
+// 89 234567 01
+// join last parts
+// 89 23456701
+// recursively rotate second part left by 6
+// 89 01234567
+// join at the end
+// 8901234567
+
+// TODO: There are other rotate algorithms.
+// This algorithm has the desirable property that it moves each element exactly twice.
+// The triple-reverse algorithm is simpler and more cache friendly, but takes more writes.
+// The follow-cycles algorithm can be 1-write but it is not very cache friendly.
+
+// rotateLeft rotates b left by n spaces.
+// s_final[i] = s_orig[i+r], wrapping around.
+func rotateLeft[E any](s []E, r int) {
+ for r != 0 && r != len(s) {
+ if r*2 <= len(s) {
+ swap(s[:r], s[len(s)-r:])
+ s = s[:len(s)-r]
+ } else {
+ swap(s[:len(s)-r], s[r:])
+ s, r = s[len(s)-r:], r*2-len(s)
+ }
+ }
+}
+func rotateRight[E any](s []E, r int) {
+ rotateLeft(s, len(s)-r)
+}
+
+// swap swaps the contents of x and y. x and y must be equal length and disjoint.
+func swap[E any](x, y []E) {
+ for i := 0; i < len(x); i++ {
+ x[i], y[i] = y[i], x[i]
+ }
+}
+
+// overlaps reports whether the memory ranges a[0:len(a)] and b[0:len(b)] overlap.
+func overlaps[E any](a, b []E) bool {
+ if len(a) == 0 || len(b) == 0 {
+ return false
+ }
+ elemSize := unsafe.Sizeof(a[0])
+ if elemSize == 0 {
+ return false
+ }
+ // TODO: use a runtime/unsafe facility once one becomes available. See issue 12445.
+ // Also see crypto/internal/alias/alias.go:AnyOverlap
+ return uintptr(unsafe.Pointer(&a[0])) <= uintptr(unsafe.Pointer(&b[len(b)-1]))+(elemSize-1) &&
+ uintptr(unsafe.Pointer(&b[0])) <= uintptr(unsafe.Pointer(&a[len(a)-1]))+(elemSize-1)
+}
+
+// startIdx returns the index in haystack where the needle starts.
+// prerequisite: the needle must be aliased entirely inside the haystack.
+func startIdx[E any](haystack, needle []E) int {
+ p := &needle[0]
+ for i := range haystack {
+ if p == &haystack[i] {
+ return i
+ }
+ }
+ // TODO: what if the overlap is by a non-integral number of Es?
+ panic("needle not found")
+}
+
+// Reverse reverses the elements of the slice in place.
+func Reverse[S ~[]E, E any](s S) {
+ for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
+ s[i], s[j] = s[j], s[i]
+ }
+}
diff --git a/vendor/golang.org/x/exp/slices/sort.go b/vendor/golang.org/x/exp/slices/sort.go
new file mode 100644
index 00000000..b67897f7
--- /dev/null
+++ b/vendor/golang.org/x/exp/slices/sort.go
@@ -0,0 +1,195 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:generate go run $GOROOT/src/sort/gen_sort_variants.go -exp
+
+package slices
+
+import (
+ "math/bits"
+
+ "golang.org/x/exp/constraints"
+)
+
+// Sort sorts a slice of any ordered type in ascending order.
+// When sorting floating-point numbers, NaNs are ordered before other values.
+func Sort[S ~[]E, E constraints.Ordered](x S) {
+ n := len(x)
+ pdqsortOrdered(x, 0, n, bits.Len(uint(n)))
+}
+
+// SortFunc sorts the slice x in ascending order as determined by the cmp
+// function. This sort is not guaranteed to be stable.
+// cmp(a, b) should return a negative number when a < b, a positive number when
+// a > b and zero when a == b.
+//
+// SortFunc requires that cmp is a strict weak ordering.
+// See https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings.
+func SortFunc[S ~[]E, E any](x S, cmp func(a, b E) int) {
+ n := len(x)
+ pdqsortCmpFunc(x, 0, n, bits.Len(uint(n)), cmp)
+}
+
+// SortStableFunc sorts the slice x while keeping the original order of equal
+// elements, using cmp to compare elements in the same way as [SortFunc].
+func SortStableFunc[S ~[]E, E any](x S, cmp func(a, b E) int) {
+ stableCmpFunc(x, len(x), cmp)
+}
+
+// IsSorted reports whether x is sorted in ascending order.
+func IsSorted[S ~[]E, E constraints.Ordered](x S) bool {
+ for i := len(x) - 1; i > 0; i-- {
+ if cmpLess(x[i], x[i-1]) {
+ return false
+ }
+ }
+ return true
+}
+
+// IsSortedFunc reports whether x is sorted in ascending order, with cmp as the
+// comparison function as defined by [SortFunc].
+func IsSortedFunc[S ~[]E, E any](x S, cmp func(a, b E) int) bool {
+ for i := len(x) - 1; i > 0; i-- {
+ if cmp(x[i], x[i-1]) < 0 {
+ return false
+ }
+ }
+ return true
+}
+
+// Min returns the minimal value in x. It panics if x is empty.
+// For floating-point numbers, Min propagates NaNs (any NaN value in x
+// forces the output to be NaN).
+func Min[S ~[]E, E constraints.Ordered](x S) E {
+ if len(x) < 1 {
+ panic("slices.Min: empty list")
+ }
+ m := x[0]
+ for i := 1; i < len(x); i++ {
+ m = min(m, x[i])
+ }
+ return m
+}
+
+// MinFunc returns the minimal value in x, using cmp to compare elements.
+// It panics if x is empty. If there is more than one minimal element
+// according to the cmp function, MinFunc returns the first one.
+func MinFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E {
+ if len(x) < 1 {
+ panic("slices.MinFunc: empty list")
+ }
+ m := x[0]
+ for i := 1; i < len(x); i++ {
+ if cmp(x[i], m) < 0 {
+ m = x[i]
+ }
+ }
+ return m
+}
+
+// Max returns the maximal value in x. It panics if x is empty.
+// For floating-point E, Max propagates NaNs (any NaN value in x
+// forces the output to be NaN).
+func Max[S ~[]E, E constraints.Ordered](x S) E {
+ if len(x) < 1 {
+ panic("slices.Max: empty list")
+ }
+ m := x[0]
+ for i := 1; i < len(x); i++ {
+ m = max(m, x[i])
+ }
+ return m
+}
+
+// MaxFunc returns the maximal value in x, using cmp to compare elements.
+// It panics if x is empty. If there is more than one maximal element
+// according to the cmp function, MaxFunc returns the first one.
+func MaxFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E {
+ if len(x) < 1 {
+ panic("slices.MaxFunc: empty list")
+ }
+ m := x[0]
+ for i := 1; i < len(x); i++ {
+ if cmp(x[i], m) > 0 {
+ m = x[i]
+ }
+ }
+ return m
+}
+
+// BinarySearch searches for target in a sorted slice and returns the position
+// where target is found, or the position where target would appear in the
+// sort order; it also returns a bool saying whether the target is really found
+// in the slice. The slice must be sorted in increasing order.
+func BinarySearch[S ~[]E, E constraints.Ordered](x S, target E) (int, bool) {
+ // Inlining is faster than calling BinarySearchFunc with a lambda.
+ n := len(x)
+ // Define x[-1] < target and x[n] >= target.
+ // Invariant: x[i-1] < target, x[j] >= target.
+ i, j := 0, n
+ for i < j {
+ h := int(uint(i+j) >> 1) // avoid overflow when computing h
+ // i ≤ h < j
+ if cmpLess(x[h], target) {
+ i = h + 1 // preserves x[i-1] < target
+ } else {
+ j = h // preserves x[j] >= target
+ }
+ }
+ // i == j, x[i-1] < target, and x[j] (= x[i]) >= target => answer is i.
+ return i, i < n && (x[i] == target || (isNaN(x[i]) && isNaN(target)))
+}
+
+// BinarySearchFunc works like [BinarySearch], but uses a custom comparison
+// function. The slice must be sorted in increasing order, where "increasing"
+// is defined by cmp. cmp should return 0 if the slice element matches
+// the target, a negative number if the slice element precedes the target,
+// or a positive number if the slice element follows the target.
+// cmp must implement the same ordering as the slice, such that if
+// cmp(a, t) < 0 and cmp(b, t) >= 0, then a must precede b in the slice.
+func BinarySearchFunc[S ~[]E, E, T any](x S, target T, cmp func(E, T) int) (int, bool) {
+ n := len(x)
+ // Define cmp(x[-1], target) < 0 and cmp(x[n], target) >= 0 .
+ // Invariant: cmp(x[i - 1], target) < 0, cmp(x[j], target) >= 0.
+ i, j := 0, n
+ for i < j {
+ h := int(uint(i+j) >> 1) // avoid overflow when computing h
+ // i ≤ h < j
+ if cmp(x[h], target) < 0 {
+ i = h + 1 // preserves cmp(x[i - 1], target) < 0
+ } else {
+ j = h // preserves cmp(x[j], target) >= 0
+ }
+ }
+ // i == j, cmp(x[i-1], target) < 0, and cmp(x[j], target) (= cmp(x[i], target)) >= 0 => answer is i.
+ return i, i < n && cmp(x[i], target) == 0
+}
+
+type sortedHint int // hint for pdqsort when choosing the pivot
+
+const (
+ unknownHint sortedHint = iota
+ increasingHint
+ decreasingHint
+)
+
+// xorshift paper: https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf
+type xorshift uint64
+
+func (r *xorshift) Next() uint64 {
+ *r ^= *r << 13
+ *r ^= *r >> 17
+ *r ^= *r << 5
+ return uint64(*r)
+}
+
+func nextPowerOfTwo(length int) uint {
+ return 1 << bits.Len(uint(length))
+}
+
+// isNaN reports whether x is a NaN without requiring the math package.
+// This will always return false if T is not floating-point.
+func isNaN[T constraints.Ordered](x T) bool {
+ return x != x
+}
diff --git a/vendor/golang.org/x/exp/slices/zsortanyfunc.go b/vendor/golang.org/x/exp/slices/zsortanyfunc.go
new file mode 100644
index 00000000..06f2c7a2
--- /dev/null
+++ b/vendor/golang.org/x/exp/slices/zsortanyfunc.go
@@ -0,0 +1,479 @@
+// Code generated by gen_sort_variants.go; DO NOT EDIT.
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package slices
+
+// insertionSortCmpFunc sorts data[a:b] using insertion sort.
+func insertionSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
+ for i := a + 1; i < b; i++ {
+ for j := i; j > a && (cmp(data[j], data[j-1]) < 0); j-- {
+ data[j], data[j-1] = data[j-1], data[j]
+ }
+ }
+}
+
+// siftDownCmpFunc implements the heap property on data[lo:hi].
+// first is an offset into the array where the root of the heap lies.
+func siftDownCmpFunc[E any](data []E, lo, hi, first int, cmp func(a, b E) int) {
+ root := lo
+ for {
+ child := 2*root + 1
+ if child >= hi {
+ break
+ }
+ if child+1 < hi && (cmp(data[first+child], data[first+child+1]) < 0) {
+ child++
+ }
+ if !(cmp(data[first+root], data[first+child]) < 0) {
+ return
+ }
+ data[first+root], data[first+child] = data[first+child], data[first+root]
+ root = child
+ }
+}
+
+func heapSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
+ first := a
+ lo := 0
+ hi := b - a
+
+ // Build heap with greatest element at top.
+ for i := (hi - 1) / 2; i >= 0; i-- {
+ siftDownCmpFunc(data, i, hi, first, cmp)
+ }
+
+ // Pop elements, largest first, into end of data.
+ for i := hi - 1; i >= 0; i-- {
+ data[first], data[first+i] = data[first+i], data[first]
+ siftDownCmpFunc(data, lo, i, first, cmp)
+ }
+}
+
+// pdqsortCmpFunc sorts data[a:b].
+// The algorithm based on pattern-defeating quicksort(pdqsort), but without the optimizations from BlockQuicksort.
+// pdqsort paper: https://arxiv.org/pdf/2106.05123.pdf
+// C++ implementation: https://github.com/orlp/pdqsort
+// Rust implementation: https://docs.rs/pdqsort/latest/pdqsort/
+// limit is the number of allowed bad (very unbalanced) pivots before falling back to heapsort.
+func pdqsortCmpFunc[E any](data []E, a, b, limit int, cmp func(a, b E) int) {
+ const maxInsertion = 12
+
+ var (
+ wasBalanced = true // whether the last partitioning was reasonably balanced
+ wasPartitioned = true // whether the slice was already partitioned
+ )
+
+ for {
+ length := b - a
+
+ if length <= maxInsertion {
+ insertionSortCmpFunc(data, a, b, cmp)
+ return
+ }
+
+ // Fall back to heapsort if too many bad choices were made.
+ if limit == 0 {
+ heapSortCmpFunc(data, a, b, cmp)
+ return
+ }
+
+ // If the last partitioning was imbalanced, we need to breaking patterns.
+ if !wasBalanced {
+ breakPatternsCmpFunc(data, a, b, cmp)
+ limit--
+ }
+
+ pivot, hint := choosePivotCmpFunc(data, a, b, cmp)
+ if hint == decreasingHint {
+ reverseRangeCmpFunc(data, a, b, cmp)
+ // The chosen pivot was pivot-a elements after the start of the array.
+ // After reversing it is pivot-a elements before the end of the array.
+ // The idea came from Rust's implementation.
+ pivot = (b - 1) - (pivot - a)
+ hint = increasingHint
+ }
+
+ // The slice is likely already sorted.
+ if wasBalanced && wasPartitioned && hint == increasingHint {
+ if partialInsertionSortCmpFunc(data, a, b, cmp) {
+ return
+ }
+ }
+
+ // Probably the slice contains many duplicate elements, partition the slice into
+ // elements equal to and elements greater than the pivot.
+ if a > 0 && !(cmp(data[a-1], data[pivot]) < 0) {
+ mid := partitionEqualCmpFunc(data, a, b, pivot, cmp)
+ a = mid
+ continue
+ }
+
+ mid, alreadyPartitioned := partitionCmpFunc(data, a, b, pivot, cmp)
+ wasPartitioned = alreadyPartitioned
+
+ leftLen, rightLen := mid-a, b-mid
+ balanceThreshold := length / 8
+ if leftLen < rightLen {
+ wasBalanced = leftLen >= balanceThreshold
+ pdqsortCmpFunc(data, a, mid, limit, cmp)
+ a = mid + 1
+ } else {
+ wasBalanced = rightLen >= balanceThreshold
+ pdqsortCmpFunc(data, mid+1, b, limit, cmp)
+ b = mid
+ }
+ }
+}
+
+// partitionCmpFunc does one quicksort partition.
+// Let p = data[pivot]
+// Moves elements in data[a:b] around, so that data[i]
=p for inewpivot.
+// On return, data[newpivot] = p
+func partitionCmpFunc[E any](data []E, a, b, pivot int, cmp func(a, b E) int) (newpivot int, alreadyPartitioned bool) {
+ data[a], data[pivot] = data[pivot], data[a]
+ i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
+
+ for i <= j && (cmp(data[i], data[a]) < 0) {
+ i++
+ }
+ for i <= j && !(cmp(data[j], data[a]) < 0) {
+ j--
+ }
+ if i > j {
+ data[j], data[a] = data[a], data[j]
+ return j, true
+ }
+ data[i], data[j] = data[j], data[i]
+ i++
+ j--
+
+ for {
+ for i <= j && (cmp(data[i], data[a]) < 0) {
+ i++
+ }
+ for i <= j && !(cmp(data[j], data[a]) < 0) {
+ j--
+ }
+ if i > j {
+ break
+ }
+ data[i], data[j] = data[j], data[i]
+ i++
+ j--
+ }
+ data[j], data[a] = data[a], data[j]
+ return j, false
+}
+
+// partitionEqualCmpFunc partitions data[a:b] into elements equal to data[pivot] followed by elements greater than data[pivot].
+// It assumed that data[a:b] does not contain elements smaller than the data[pivot].
+func partitionEqualCmpFunc[E any](data []E, a, b, pivot int, cmp func(a, b E) int) (newpivot int) {
+ data[a], data[pivot] = data[pivot], data[a]
+ i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
+
+ for {
+ for i <= j && !(cmp(data[a], data[i]) < 0) {
+ i++
+ }
+ for i <= j && (cmp(data[a], data[j]) < 0) {
+ j--
+ }
+ if i > j {
+ break
+ }
+ data[i], data[j] = data[j], data[i]
+ i++
+ j--
+ }
+ return i
+}
+
+// partialInsertionSortCmpFunc partially sorts a slice, returns true if the slice is sorted at the end.
+func partialInsertionSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) bool {
+ const (
+ maxSteps = 5 // maximum number of adjacent out-of-order pairs that will get shifted
+ shortestShifting = 50 // don't shift any elements on short arrays
+ )
+ i := a + 1
+ for j := 0; j < maxSteps; j++ {
+ for i < b && !(cmp(data[i], data[i-1]) < 0) {
+ i++
+ }
+
+ if i == b {
+ return true
+ }
+
+ if b-a < shortestShifting {
+ return false
+ }
+
+ data[i], data[i-1] = data[i-1], data[i]
+
+ // Shift the smaller one to the left.
+ if i-a >= 2 {
+ for j := i - 1; j >= 1; j-- {
+ if !(cmp(data[j], data[j-1]) < 0) {
+ break
+ }
+ data[j], data[j-1] = data[j-1], data[j]
+ }
+ }
+ // Shift the greater one to the right.
+ if b-i >= 2 {
+ for j := i + 1; j < b; j++ {
+ if !(cmp(data[j], data[j-1]) < 0) {
+ break
+ }
+ data[j], data[j-1] = data[j-1], data[j]
+ }
+ }
+ }
+ return false
+}
+
+// breakPatternsCmpFunc scatters some elements around in an attempt to break some patterns
+// that might cause imbalanced partitions in quicksort.
+func breakPatternsCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
+ length := b - a
+ if length >= 8 {
+ random := xorshift(length)
+ modulus := nextPowerOfTwo(length)
+
+ for idx := a + (length/4)*2 - 1; idx <= a+(length/4)*2+1; idx++ {
+ other := int(uint(random.Next()) & (modulus - 1))
+ if other >= length {
+ other -= length
+ }
+ data[idx], data[a+other] = data[a+other], data[idx]
+ }
+ }
+}
+
+// choosePivotCmpFunc chooses a pivot in data[a:b].
+//
+// [0,8): chooses a static pivot.
+// [8,shortestNinther): uses the simple median-of-three method.
+// [shortestNinther,∞): uses the Tukey ninther method.
+func choosePivotCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) (pivot int, hint sortedHint) {
+ const (
+ shortestNinther = 50
+ maxSwaps = 4 * 3
+ )
+
+ l := b - a
+
+ var (
+ swaps int
+ i = a + l/4*1
+ j = a + l/4*2
+ k = a + l/4*3
+ )
+
+ if l >= 8 {
+ if l >= shortestNinther {
+ // Tukey ninther method, the idea came from Rust's implementation.
+ i = medianAdjacentCmpFunc(data, i, &swaps, cmp)
+ j = medianAdjacentCmpFunc(data, j, &swaps, cmp)
+ k = medianAdjacentCmpFunc(data, k, &swaps, cmp)
+ }
+ // Find the median among i, j, k and stores it into j.
+ j = medianCmpFunc(data, i, j, k, &swaps, cmp)
+ }
+
+ switch swaps {
+ case 0:
+ return j, increasingHint
+ case maxSwaps:
+ return j, decreasingHint
+ default:
+ return j, unknownHint
+ }
+}
+
+// order2CmpFunc returns x,y where data[x] <= data[y], where x,y=a,b or x,y=b,a.
+func order2CmpFunc[E any](data []E, a, b int, swaps *int, cmp func(a, b E) int) (int, int) {
+ if cmp(data[b], data[a]) < 0 {
+ *swaps++
+ return b, a
+ }
+ return a, b
+}
+
+// medianCmpFunc returns x where data[x] is the median of data[a],data[b],data[c], where x is a, b, or c.
+func medianCmpFunc[E any](data []E, a, b, c int, swaps *int, cmp func(a, b E) int) int {
+ a, b = order2CmpFunc(data, a, b, swaps, cmp)
+ b, c = order2CmpFunc(data, b, c, swaps, cmp)
+ a, b = order2CmpFunc(data, a, b, swaps, cmp)
+ return b
+}
+
+// medianAdjacentCmpFunc finds the median of data[a - 1], data[a], data[a + 1] and stores the index into a.
+func medianAdjacentCmpFunc[E any](data []E, a int, swaps *int, cmp func(a, b E) int) int {
+ return medianCmpFunc(data, a-1, a, a+1, swaps, cmp)
+}
+
+func reverseRangeCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
+ i := a
+ j := b - 1
+ for i < j {
+ data[i], data[j] = data[j], data[i]
+ i++
+ j--
+ }
+}
+
+func swapRangeCmpFunc[E any](data []E, a, b, n int, cmp func(a, b E) int) {
+ for i := 0; i < n; i++ {
+ data[a+i], data[b+i] = data[b+i], data[a+i]
+ }
+}
+
+func stableCmpFunc[E any](data []E, n int, cmp func(a, b E) int) {
+ blockSize := 20 // must be > 0
+ a, b := 0, blockSize
+ for b <= n {
+ insertionSortCmpFunc(data, a, b, cmp)
+ a = b
+ b += blockSize
+ }
+ insertionSortCmpFunc(data, a, n, cmp)
+
+ for blockSize < n {
+ a, b = 0, 2*blockSize
+ for b <= n {
+ symMergeCmpFunc(data, a, a+blockSize, b, cmp)
+ a = b
+ b += 2 * blockSize
+ }
+ if m := a + blockSize; m < n {
+ symMergeCmpFunc(data, a, m, n, cmp)
+ }
+ blockSize *= 2
+ }
+}
+
+// symMergeCmpFunc merges the two sorted subsequences data[a:m] and data[m:b] using
+// the SymMerge algorithm from Pok-Son Kim and Arne Kutzner, "Stable Minimum
+// Storage Merging by Symmetric Comparisons", in Susanne Albers and Tomasz
+// Radzik, editors, Algorithms - ESA 2004, volume 3221 of Lecture Notes in
+// Computer Science, pages 714-723. Springer, 2004.
+//
+// Let M = m-a and N = b-n. Wolog M < N.
+// The recursion depth is bound by ceil(log(N+M)).
+// The algorithm needs O(M*log(N/M + 1)) calls to data.Less.
+// The algorithm needs O((M+N)*log(M)) calls to data.Swap.
+//
+// The paper gives O((M+N)*log(M)) as the number of assignments assuming a
+// rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation
+// in the paper carries through for Swap operations, especially as the block
+// swapping rotate uses only O(M+N) Swaps.
+//
+// symMerge assumes non-degenerate arguments: a < m && m < b.
+// Having the caller check this condition eliminates many leaf recursion calls,
+// which improves performance.
+func symMergeCmpFunc[E any](data []E, a, m, b int, cmp func(a, b E) int) {
+ // Avoid unnecessary recursions of symMerge
+ // by direct insertion of data[a] into data[m:b]
+ // if data[a:m] only contains one element.
+ if m-a == 1 {
+ // Use binary search to find the lowest index i
+ // such that data[i] >= data[a] for m <= i < b.
+ // Exit the search loop with i == b in case no such index exists.
+ i := m
+ j := b
+ for i < j {
+ h := int(uint(i+j) >> 1)
+ if cmp(data[h], data[a]) < 0 {
+ i = h + 1
+ } else {
+ j = h
+ }
+ }
+ // Swap values until data[a] reaches the position before i.
+ for k := a; k < i-1; k++ {
+ data[k], data[k+1] = data[k+1], data[k]
+ }
+ return
+ }
+
+ // Avoid unnecessary recursions of symMerge
+ // by direct insertion of data[m] into data[a:m]
+ // if data[m:b] only contains one element.
+ if b-m == 1 {
+ // Use binary search to find the lowest index i
+ // such that data[i] > data[m] for a <= i < m.
+ // Exit the search loop with i == m in case no such index exists.
+ i := a
+ j := m
+ for i < j {
+ h := int(uint(i+j) >> 1)
+ if !(cmp(data[m], data[h]) < 0) {
+ i = h + 1
+ } else {
+ j = h
+ }
+ }
+ // Swap values until data[m] reaches the position i.
+ for k := m; k > i; k-- {
+ data[k], data[k-1] = data[k-1], data[k]
+ }
+ return
+ }
+
+ mid := int(uint(a+b) >> 1)
+ n := mid + m
+ var start, r int
+ if m > mid {
+ start = n - b
+ r = mid
+ } else {
+ start = a
+ r = m
+ }
+ p := n - 1
+
+ for start < r {
+ c := int(uint(start+r) >> 1)
+ if !(cmp(data[p-c], data[c]) < 0) {
+ start = c + 1
+ } else {
+ r = c
+ }
+ }
+
+ end := n - start
+ if start < m && m < end {
+ rotateCmpFunc(data, start, m, end, cmp)
+ }
+ if a < start && start < mid {
+ symMergeCmpFunc(data, a, start, mid, cmp)
+ }
+ if mid < end && end < b {
+ symMergeCmpFunc(data, mid, end, b, cmp)
+ }
+}
+
+// rotateCmpFunc rotates two consecutive blocks u = data[a:m] and v = data[m:b] in data:
+// Data of the form 'x u v y' is changed to 'x v u y'.
+// rotate performs at most b-a many calls to data.Swap,
+// and it assumes non-degenerate arguments: a < m && m < b.
+func rotateCmpFunc[E any](data []E, a, m, b int, cmp func(a, b E) int) {
+ i := m - a
+ j := b - m
+
+ for i != j {
+ if i > j {
+ swapRangeCmpFunc(data, m-i, m, j, cmp)
+ i -= j
+ } else {
+ swapRangeCmpFunc(data, m-i, m+j-i, i, cmp)
+ j -= i
+ }
+ }
+ // i == j
+ swapRangeCmpFunc(data, m-i, m, i, cmp)
+}
diff --git a/vendor/golang.org/x/exp/slices/zsortordered.go b/vendor/golang.org/x/exp/slices/zsortordered.go
new file mode 100644
index 00000000..99b47c39
--- /dev/null
+++ b/vendor/golang.org/x/exp/slices/zsortordered.go
@@ -0,0 +1,481 @@
+// Code generated by gen_sort_variants.go; DO NOT EDIT.
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package slices
+
+import "golang.org/x/exp/constraints"
+
+// insertionSortOrdered sorts data[a:b] using insertion sort.
+func insertionSortOrdered[E constraints.Ordered](data []E, a, b int) {
+ for i := a + 1; i < b; i++ {
+ for j := i; j > a && cmpLess(data[j], data[j-1]); j-- {
+ data[j], data[j-1] = data[j-1], data[j]
+ }
+ }
+}
+
+// siftDownOrdered implements the heap property on data[lo:hi].
+// first is an offset into the array where the root of the heap lies.
+func siftDownOrdered[E constraints.Ordered](data []E, lo, hi, first int) {
+ root := lo
+ for {
+ child := 2*root + 1
+ if child >= hi {
+ break
+ }
+ if child+1 < hi && cmpLess(data[first+child], data[first+child+1]) {
+ child++
+ }
+ if !cmpLess(data[first+root], data[first+child]) {
+ return
+ }
+ data[first+root], data[first+child] = data[first+child], data[first+root]
+ root = child
+ }
+}
+
+func heapSortOrdered[E constraints.Ordered](data []E, a, b int) {
+ first := a
+ lo := 0
+ hi := b - a
+
+ // Build heap with greatest element at top.
+ for i := (hi - 1) / 2; i >= 0; i-- {
+ siftDownOrdered(data, i, hi, first)
+ }
+
+ // Pop elements, largest first, into end of data.
+ for i := hi - 1; i >= 0; i-- {
+ data[first], data[first+i] = data[first+i], data[first]
+ siftDownOrdered(data, lo, i, first)
+ }
+}
+
+// pdqsortOrdered sorts data[a:b].
+// The algorithm based on pattern-defeating quicksort(pdqsort), but without the optimizations from BlockQuicksort.
+// pdqsort paper: https://arxiv.org/pdf/2106.05123.pdf
+// C++ implementation: https://github.com/orlp/pdqsort
+// Rust implementation: https://docs.rs/pdqsort/latest/pdqsort/
+// limit is the number of allowed bad (very unbalanced) pivots before falling back to heapsort.
+func pdqsortOrdered[E constraints.Ordered](data []E, a, b, limit int) {
+ const maxInsertion = 12
+
+ var (
+ wasBalanced = true // whether the last partitioning was reasonably balanced
+ wasPartitioned = true // whether the slice was already partitioned
+ )
+
+ for {
+ length := b - a
+
+ if length <= maxInsertion {
+ insertionSortOrdered(data, a, b)
+ return
+ }
+
+ // Fall back to heapsort if too many bad choices were made.
+ if limit == 0 {
+ heapSortOrdered(data, a, b)
+ return
+ }
+
+ // If the last partitioning was imbalanced, we need to breaking patterns.
+ if !wasBalanced {
+ breakPatternsOrdered(data, a, b)
+ limit--
+ }
+
+ pivot, hint := choosePivotOrdered(data, a, b)
+ if hint == decreasingHint {
+ reverseRangeOrdered(data, a, b)
+ // The chosen pivot was pivot-a elements after the start of the array.
+ // After reversing it is pivot-a elements before the end of the array.
+ // The idea came from Rust's implementation.
+ pivot = (b - 1) - (pivot - a)
+ hint = increasingHint
+ }
+
+ // The slice is likely already sorted.
+ if wasBalanced && wasPartitioned && hint == increasingHint {
+ if partialInsertionSortOrdered(data, a, b) {
+ return
+ }
+ }
+
+ // Probably the slice contains many duplicate elements, partition the slice into
+ // elements equal to and elements greater than the pivot.
+ if a > 0 && !cmpLess(data[a-1], data[pivot]) {
+ mid := partitionEqualOrdered(data, a, b, pivot)
+ a = mid
+ continue
+ }
+
+ mid, alreadyPartitioned := partitionOrdered(data, a, b, pivot)
+ wasPartitioned = alreadyPartitioned
+
+ leftLen, rightLen := mid-a, b-mid
+ balanceThreshold := length / 8
+ if leftLen < rightLen {
+ wasBalanced = leftLen >= balanceThreshold
+ pdqsortOrdered(data, a, mid, limit)
+ a = mid + 1
+ } else {
+ wasBalanced = rightLen >= balanceThreshold
+ pdqsortOrdered(data, mid+1, b, limit)
+ b = mid
+ }
+ }
+}
+
+// partitionOrdered does one quicksort partition.
+// Let p = data[pivot]
+// Moves elements in data[a:b] around, so that data[i]=p for inewpivot.
+// On return, data[newpivot] = p
+func partitionOrdered[E constraints.Ordered](data []E, a, b, pivot int) (newpivot int, alreadyPartitioned bool) {
+ data[a], data[pivot] = data[pivot], data[a]
+ i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
+
+ for i <= j && cmpLess(data[i], data[a]) {
+ i++
+ }
+ for i <= j && !cmpLess(data[j], data[a]) {
+ j--
+ }
+ if i > j {
+ data[j], data[a] = data[a], data[j]
+ return j, true
+ }
+ data[i], data[j] = data[j], data[i]
+ i++
+ j--
+
+ for {
+ for i <= j && cmpLess(data[i], data[a]) {
+ i++
+ }
+ for i <= j && !cmpLess(data[j], data[a]) {
+ j--
+ }
+ if i > j {
+ break
+ }
+ data[i], data[j] = data[j], data[i]
+ i++
+ j--
+ }
+ data[j], data[a] = data[a], data[j]
+ return j, false
+}
+
+// partitionEqualOrdered partitions data[a:b] into elements equal to data[pivot] followed by elements greater than data[pivot].
+// It assumed that data[a:b] does not contain elements smaller than the data[pivot].
+func partitionEqualOrdered[E constraints.Ordered](data []E, a, b, pivot int) (newpivot int) {
+ data[a], data[pivot] = data[pivot], data[a]
+ i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
+
+ for {
+ for i <= j && !cmpLess(data[a], data[i]) {
+ i++
+ }
+ for i <= j && cmpLess(data[a], data[j]) {
+ j--
+ }
+ if i > j {
+ break
+ }
+ data[i], data[j] = data[j], data[i]
+ i++
+ j--
+ }
+ return i
+}
+
+// partialInsertionSortOrdered partially sorts a slice, returns true if the slice is sorted at the end.
+func partialInsertionSortOrdered[E constraints.Ordered](data []E, a, b int) bool {
+ const (
+ maxSteps = 5 // maximum number of adjacent out-of-order pairs that will get shifted
+ shortestShifting = 50 // don't shift any elements on short arrays
+ )
+ i := a + 1
+ for j := 0; j < maxSteps; j++ {
+ for i < b && !cmpLess(data[i], data[i-1]) {
+ i++
+ }
+
+ if i == b {
+ return true
+ }
+
+ if b-a < shortestShifting {
+ return false
+ }
+
+ data[i], data[i-1] = data[i-1], data[i]
+
+ // Shift the smaller one to the left.
+ if i-a >= 2 {
+ for j := i - 1; j >= 1; j-- {
+ if !cmpLess(data[j], data[j-1]) {
+ break
+ }
+ data[j], data[j-1] = data[j-1], data[j]
+ }
+ }
+ // Shift the greater one to the right.
+ if b-i >= 2 {
+ for j := i + 1; j < b; j++ {
+ if !cmpLess(data[j], data[j-1]) {
+ break
+ }
+ data[j], data[j-1] = data[j-1], data[j]
+ }
+ }
+ }
+ return false
+}
+
+// breakPatternsOrdered scatters some elements around in an attempt to break some patterns
+// that might cause imbalanced partitions in quicksort.
+func breakPatternsOrdered[E constraints.Ordered](data []E, a, b int) {
+ length := b - a
+ if length >= 8 {
+ random := xorshift(length)
+ modulus := nextPowerOfTwo(length)
+
+ for idx := a + (length/4)*2 - 1; idx <= a+(length/4)*2+1; idx++ {
+ other := int(uint(random.Next()) & (modulus - 1))
+ if other >= length {
+ other -= length
+ }
+ data[idx], data[a+other] = data[a+other], data[idx]
+ }
+ }
+}
+
+// choosePivotOrdered chooses a pivot in data[a:b].
+//
+// [0,8): chooses a static pivot.
+// [8,shortestNinther): uses the simple median-of-three method.
+// [shortestNinther,∞): uses the Tukey ninther method.
+func choosePivotOrdered[E constraints.Ordered](data []E, a, b int) (pivot int, hint sortedHint) {
+ const (
+ shortestNinther = 50
+ maxSwaps = 4 * 3
+ )
+
+ l := b - a
+
+ var (
+ swaps int
+ i = a + l/4*1
+ j = a + l/4*2
+ k = a + l/4*3
+ )
+
+ if l >= 8 {
+ if l >= shortestNinther {
+ // Tukey ninther method, the idea came from Rust's implementation.
+ i = medianAdjacentOrdered(data, i, &swaps)
+ j = medianAdjacentOrdered(data, j, &swaps)
+ k = medianAdjacentOrdered(data, k, &swaps)
+ }
+ // Find the median among i, j, k and stores it into j.
+ j = medianOrdered(data, i, j, k, &swaps)
+ }
+
+ switch swaps {
+ case 0:
+ return j, increasingHint
+ case maxSwaps:
+ return j, decreasingHint
+ default:
+ return j, unknownHint
+ }
+}
+
+// order2Ordered returns x,y where data[x] <= data[y], where x,y=a,b or x,y=b,a.
+func order2Ordered[E constraints.Ordered](data []E, a, b int, swaps *int) (int, int) {
+ if cmpLess(data[b], data[a]) {
+ *swaps++
+ return b, a
+ }
+ return a, b
+}
+
+// medianOrdered returns x where data[x] is the median of data[a],data[b],data[c], where x is a, b, or c.
+func medianOrdered[E constraints.Ordered](data []E, a, b, c int, swaps *int) int {
+ a, b = order2Ordered(data, a, b, swaps)
+ b, c = order2Ordered(data, b, c, swaps)
+ a, b = order2Ordered(data, a, b, swaps)
+ return b
+}
+
+// medianAdjacentOrdered finds the median of data[a - 1], data[a], data[a + 1] and stores the index into a.
+func medianAdjacentOrdered[E constraints.Ordered](data []E, a int, swaps *int) int {
+ return medianOrdered(data, a-1, a, a+1, swaps)
+}
+
+func reverseRangeOrdered[E constraints.Ordered](data []E, a, b int) {
+ i := a
+ j := b - 1
+ for i < j {
+ data[i], data[j] = data[j], data[i]
+ i++
+ j--
+ }
+}
+
+func swapRangeOrdered[E constraints.Ordered](data []E, a, b, n int) {
+ for i := 0; i < n; i++ {
+ data[a+i], data[b+i] = data[b+i], data[a+i]
+ }
+}
+
+func stableOrdered[E constraints.Ordered](data []E, n int) {
+ blockSize := 20 // must be > 0
+ a, b := 0, blockSize
+ for b <= n {
+ insertionSortOrdered(data, a, b)
+ a = b
+ b += blockSize
+ }
+ insertionSortOrdered(data, a, n)
+
+ for blockSize < n {
+ a, b = 0, 2*blockSize
+ for b <= n {
+ symMergeOrdered(data, a, a+blockSize, b)
+ a = b
+ b += 2 * blockSize
+ }
+ if m := a + blockSize; m < n {
+ symMergeOrdered(data, a, m, n)
+ }
+ blockSize *= 2
+ }
+}
+
+// symMergeOrdered merges the two sorted subsequences data[a:m] and data[m:b] using
+// the SymMerge algorithm from Pok-Son Kim and Arne Kutzner, "Stable Minimum
+// Storage Merging by Symmetric Comparisons", in Susanne Albers and Tomasz
+// Radzik, editors, Algorithms - ESA 2004, volume 3221 of Lecture Notes in
+// Computer Science, pages 714-723. Springer, 2004.
+//
+// Let M = m-a and N = b-n. Wolog M < N.
+// The recursion depth is bound by ceil(log(N+M)).
+// The algorithm needs O(M*log(N/M + 1)) calls to data.Less.
+// The algorithm needs O((M+N)*log(M)) calls to data.Swap.
+//
+// The paper gives O((M+N)*log(M)) as the number of assignments assuming a
+// rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation
+// in the paper carries through for Swap operations, especially as the block
+// swapping rotate uses only O(M+N) Swaps.
+//
+// symMerge assumes non-degenerate arguments: a < m && m < b.
+// Having the caller check this condition eliminates many leaf recursion calls,
+// which improves performance.
+func symMergeOrdered[E constraints.Ordered](data []E, a, m, b int) {
+ // Avoid unnecessary recursions of symMerge
+ // by direct insertion of data[a] into data[m:b]
+ // if data[a:m] only contains one element.
+ if m-a == 1 {
+ // Use binary search to find the lowest index i
+ // such that data[i] >= data[a] for m <= i < b.
+ // Exit the search loop with i == b in case no such index exists.
+ i := m
+ j := b
+ for i < j {
+ h := int(uint(i+j) >> 1)
+ if cmpLess(data[h], data[a]) {
+ i = h + 1
+ } else {
+ j = h
+ }
+ }
+ // Swap values until data[a] reaches the position before i.
+ for k := a; k < i-1; k++ {
+ data[k], data[k+1] = data[k+1], data[k]
+ }
+ return
+ }
+
+ // Avoid unnecessary recursions of symMerge
+ // by direct insertion of data[m] into data[a:m]
+ // if data[m:b] only contains one element.
+ if b-m == 1 {
+ // Use binary search to find the lowest index i
+ // such that data[i] > data[m] for a <= i < m.
+ // Exit the search loop with i == m in case no such index exists.
+ i := a
+ j := m
+ for i < j {
+ h := int(uint(i+j) >> 1)
+ if !cmpLess(data[m], data[h]) {
+ i = h + 1
+ } else {
+ j = h
+ }
+ }
+ // Swap values until data[m] reaches the position i.
+ for k := m; k > i; k-- {
+ data[k], data[k-1] = data[k-1], data[k]
+ }
+ return
+ }
+
+ mid := int(uint(a+b) >> 1)
+ n := mid + m
+ var start, r int
+ if m > mid {
+ start = n - b
+ r = mid
+ } else {
+ start = a
+ r = m
+ }
+ p := n - 1
+
+ for start < r {
+ c := int(uint(start+r) >> 1)
+ if !cmpLess(data[p-c], data[c]) {
+ start = c + 1
+ } else {
+ r = c
+ }
+ }
+
+ end := n - start
+ if start < m && m < end {
+ rotateOrdered(data, start, m, end)
+ }
+ if a < start && start < mid {
+ symMergeOrdered(data, a, start, mid)
+ }
+ if mid < end && end < b {
+ symMergeOrdered(data, mid, end, b)
+ }
+}
+
+// rotateOrdered rotates two consecutive blocks u = data[a:m] and v = data[m:b] in data:
+// Data of the form 'x u v y' is changed to 'x v u y'.
+// rotate performs at most b-a many calls to data.Swap,
+// and it assumes non-degenerate arguments: a < m && m < b.
+func rotateOrdered[E constraints.Ordered](data []E, a, m, b int) {
+ i := m - a
+ j := b - m
+
+ for i != j {
+ if i > j {
+ swapRangeOrdered(data, m-i, m, j)
+ i -= j
+ } else {
+ swapRangeOrdered(data, m-i, m+j-i, i)
+ j -= i
+ }
+ }
+ // i == j
+ swapRangeOrdered(data, m-i, m, i)
+}
diff --git a/vendor/golang.org/x/net/http2/frame.go b/vendor/golang.org/x/net/http2/frame.go
index c1f6b90d..e2b298d8 100644
--- a/vendor/golang.org/x/net/http2/frame.go
+++ b/vendor/golang.org/x/net/http2/frame.go
@@ -1510,13 +1510,12 @@ func (mh *MetaHeadersFrame) checkPseudos() error {
}
func (fr *Framer) maxHeaderStringLen() int {
- v := fr.maxHeaderListSize()
- if uint32(int(v)) == v {
- return int(v)
+ v := int(fr.maxHeaderListSize())
+ if v < 0 {
+ // If maxHeaderListSize overflows an int, use no limit (0).
+ return 0
}
- // They had a crazy big number for MaxHeaderBytes anyway,
- // so give them unlimited header lengths:
- return 0
+ return v
}
// readMetaFrame returns 0 or more CONTINUATION frames from fr and
diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh
index 6202638b..fdcaa974 100644
--- a/vendor/golang.org/x/sys/unix/mkerrors.sh
+++ b/vendor/golang.org/x/sys/unix/mkerrors.sh
@@ -248,6 +248,7 @@ struct ltchars {
#include
#include
#include
+#include
#include
#include
#include
@@ -283,10 +284,6 @@ struct ltchars {
#include
#endif
-#ifndef MSG_FASTOPEN
-#define MSG_FASTOPEN 0x20000000
-#endif
-
#ifndef PTRACE_GETREGS
#define PTRACE_GETREGS 0xc
#endif
@@ -295,14 +292,6 @@ struct ltchars {
#define PTRACE_SETREGS 0xd
#endif
-#ifndef SOL_NETLINK
-#define SOL_NETLINK 270
-#endif
-
-#ifndef SOL_SMC
-#define SOL_SMC 286
-#endif
-
#ifdef SOL_BLUETOOTH
// SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h
// but it is already in bluetooth_linux.go
@@ -319,10 +308,23 @@ struct ltchars {
#undef TIPC_WAIT_FOREVER
#define TIPC_WAIT_FOREVER 0xffffffff
-// Copied from linux/l2tp.h
-// Including linux/l2tp.h here causes conflicts between linux/in.h
-// and netinet/in.h included via net/route.h above.
-#define IPPROTO_L2TP 115
+// Copied from linux/netfilter/nf_nat.h
+// Including linux/netfilter/nf_nat.h here causes conflicts between linux/in.h
+// and netinet/in.h.
+#define NF_NAT_RANGE_MAP_IPS (1 << 0)
+#define NF_NAT_RANGE_PROTO_SPECIFIED (1 << 1)
+#define NF_NAT_RANGE_PROTO_RANDOM (1 << 2)
+#define NF_NAT_RANGE_PERSISTENT (1 << 3)
+#define NF_NAT_RANGE_PROTO_RANDOM_FULLY (1 << 4)
+#define NF_NAT_RANGE_PROTO_OFFSET (1 << 5)
+#define NF_NAT_RANGE_NETMAP (1 << 6)
+#define NF_NAT_RANGE_PROTO_RANDOM_ALL \
+ (NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PROTO_RANDOM_FULLY)
+#define NF_NAT_RANGE_MASK \
+ (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED | \
+ NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PERSISTENT | \
+ NF_NAT_RANGE_PROTO_RANDOM_FULLY | NF_NAT_RANGE_PROTO_OFFSET | \
+ NF_NAT_RANGE_NETMAP)
// Copied from linux/hid.h.
// Keep in sync with the size of the referenced fields.
@@ -582,7 +584,7 @@ ccflags="$@"
$2 ~ /^KEY_(SPEC|REQKEY_DEFL)_/ ||
$2 ~ /^KEYCTL_/ ||
$2 ~ /^PERF_/ ||
- $2 ~ /^SECCOMP_MODE_/ ||
+ $2 ~ /^SECCOMP_/ ||
$2 ~ /^SEEK_/ ||
$2 ~ /^SCHED_/ ||
$2 ~ /^SPLICE_/ ||
@@ -603,6 +605,9 @@ ccflags="$@"
$2 ~ /^FSOPT_/ ||
$2 ~ /^WDIO[CFS]_/ ||
$2 ~ /^NFN/ ||
+ $2 !~ /^NFT_META_IIFTYPE/ &&
+ $2 ~ /^NFT_/ ||
+ $2 ~ /^NF_NAT_/ ||
$2 ~ /^XDP_/ ||
$2 ~ /^RWF_/ ||
$2 ~ /^(HDIO|WIN|SMART)_/ ||
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux.go b/vendor/golang.org/x/sys/unix/zerrors_linux.go
index c73cfe2f..36bf8399 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux.go
@@ -1785,6 +1785,8 @@ const (
LANDLOCK_ACCESS_FS_REMOVE_FILE = 0x20
LANDLOCK_ACCESS_FS_TRUNCATE = 0x4000
LANDLOCK_ACCESS_FS_WRITE_FILE = 0x2
+ LANDLOCK_ACCESS_NET_BIND_TCP = 0x1
+ LANDLOCK_ACCESS_NET_CONNECT_TCP = 0x2
LANDLOCK_CREATE_RULESET_VERSION = 0x1
LINUX_REBOOT_CMD_CAD_OFF = 0x0
LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef
@@ -2127,6 +2129,60 @@ const (
NFNL_SUBSYS_QUEUE = 0x3
NFNL_SUBSYS_ULOG = 0x4
NFS_SUPER_MAGIC = 0x6969
+ NFT_CHAIN_FLAGS = 0x7
+ NFT_CHAIN_MAXNAMELEN = 0x100
+ NFT_CT_MAX = 0x17
+ NFT_DATA_RESERVED_MASK = 0xffffff00
+ NFT_DATA_VALUE_MAXLEN = 0x40
+ NFT_EXTHDR_OP_MAX = 0x4
+ NFT_FIB_RESULT_MAX = 0x3
+ NFT_INNER_MASK = 0xf
+ NFT_LOGLEVEL_MAX = 0x8
+ NFT_NAME_MAXLEN = 0x100
+ NFT_NG_MAX = 0x1
+ NFT_OBJECT_CONNLIMIT = 0x5
+ NFT_OBJECT_COUNTER = 0x1
+ NFT_OBJECT_CT_EXPECT = 0x9
+ NFT_OBJECT_CT_HELPER = 0x3
+ NFT_OBJECT_CT_TIMEOUT = 0x7
+ NFT_OBJECT_LIMIT = 0x4
+ NFT_OBJECT_MAX = 0xa
+ NFT_OBJECT_QUOTA = 0x2
+ NFT_OBJECT_SECMARK = 0x8
+ NFT_OBJECT_SYNPROXY = 0xa
+ NFT_OBJECT_TUNNEL = 0x6
+ NFT_OBJECT_UNSPEC = 0x0
+ NFT_OBJ_MAXNAMELEN = 0x100
+ NFT_OSF_MAXGENRELEN = 0x10
+ NFT_QUEUE_FLAG_BYPASS = 0x1
+ NFT_QUEUE_FLAG_CPU_FANOUT = 0x2
+ NFT_QUEUE_FLAG_MASK = 0x3
+ NFT_REG32_COUNT = 0x10
+ NFT_REG32_SIZE = 0x4
+ NFT_REG_MAX = 0x4
+ NFT_REG_SIZE = 0x10
+ NFT_REJECT_ICMPX_MAX = 0x3
+ NFT_RT_MAX = 0x4
+ NFT_SECMARK_CTX_MAXLEN = 0x100
+ NFT_SET_MAXNAMELEN = 0x100
+ NFT_SOCKET_MAX = 0x3
+ NFT_TABLE_F_MASK = 0x3
+ NFT_TABLE_MAXNAMELEN = 0x100
+ NFT_TRACETYPE_MAX = 0x3
+ NFT_TUNNEL_F_MASK = 0x7
+ NFT_TUNNEL_MAX = 0x1
+ NFT_TUNNEL_MODE_MAX = 0x2
+ NFT_USERDATA_MAXLEN = 0x100
+ NFT_XFRM_KEY_MAX = 0x6
+ NF_NAT_RANGE_MAP_IPS = 0x1
+ NF_NAT_RANGE_MASK = 0x7f
+ NF_NAT_RANGE_NETMAP = 0x40
+ NF_NAT_RANGE_PERSISTENT = 0x8
+ NF_NAT_RANGE_PROTO_OFFSET = 0x20
+ NF_NAT_RANGE_PROTO_RANDOM = 0x4
+ NF_NAT_RANGE_PROTO_RANDOM_ALL = 0x14
+ NF_NAT_RANGE_PROTO_RANDOM_FULLY = 0x10
+ NF_NAT_RANGE_PROTO_SPECIFIED = 0x2
NILFS_SUPER_MAGIC = 0x3434
NL0 = 0x0
NL1 = 0x100
@@ -2411,6 +2467,7 @@ const (
PR_MCE_KILL_GET = 0x22
PR_MCE_KILL_LATE = 0x0
PR_MCE_KILL_SET = 0x1
+ PR_MDWE_NO_INHERIT = 0x2
PR_MDWE_REFUSE_EXEC_GAIN = 0x1
PR_MPX_DISABLE_MANAGEMENT = 0x2c
PR_MPX_ENABLE_MANAGEMENT = 0x2b
@@ -2615,8 +2672,9 @@ const (
RTAX_FEATURES = 0xc
RTAX_FEATURE_ALLFRAG = 0x8
RTAX_FEATURE_ECN = 0x1
- RTAX_FEATURE_MASK = 0xf
+ RTAX_FEATURE_MASK = 0x1f
RTAX_FEATURE_SACK = 0x2
+ RTAX_FEATURE_TCP_USEC_TS = 0x10
RTAX_FEATURE_TIMESTAMP = 0x4
RTAX_HOPLIMIT = 0xa
RTAX_INITCWND = 0xb
@@ -2859,9 +2917,38 @@ const (
SCM_RIGHTS = 0x1
SCM_TIMESTAMP = 0x1d
SC_LOG_FLUSH = 0x100000
+ SECCOMP_ADDFD_FLAG_SEND = 0x2
+ SECCOMP_ADDFD_FLAG_SETFD = 0x1
+ SECCOMP_FILTER_FLAG_LOG = 0x2
+ SECCOMP_FILTER_FLAG_NEW_LISTENER = 0x8
+ SECCOMP_FILTER_FLAG_SPEC_ALLOW = 0x4
+ SECCOMP_FILTER_FLAG_TSYNC = 0x1
+ SECCOMP_FILTER_FLAG_TSYNC_ESRCH = 0x10
+ SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV = 0x20
+ SECCOMP_GET_ACTION_AVAIL = 0x2
+ SECCOMP_GET_NOTIF_SIZES = 0x3
+ SECCOMP_IOCTL_NOTIF_RECV = 0xc0502100
+ SECCOMP_IOCTL_NOTIF_SEND = 0xc0182101
+ SECCOMP_IOC_MAGIC = '!'
SECCOMP_MODE_DISABLED = 0x0
SECCOMP_MODE_FILTER = 0x2
SECCOMP_MODE_STRICT = 0x1
+ SECCOMP_RET_ACTION = 0x7fff0000
+ SECCOMP_RET_ACTION_FULL = 0xffff0000
+ SECCOMP_RET_ALLOW = 0x7fff0000
+ SECCOMP_RET_DATA = 0xffff
+ SECCOMP_RET_ERRNO = 0x50000
+ SECCOMP_RET_KILL = 0x0
+ SECCOMP_RET_KILL_PROCESS = 0x80000000
+ SECCOMP_RET_KILL_THREAD = 0x0
+ SECCOMP_RET_LOG = 0x7ffc0000
+ SECCOMP_RET_TRACE = 0x7ff00000
+ SECCOMP_RET_TRAP = 0x30000
+ SECCOMP_RET_USER_NOTIF = 0x7fc00000
+ SECCOMP_SET_MODE_FILTER = 0x1
+ SECCOMP_SET_MODE_STRICT = 0x0
+ SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP = 0x1
+ SECCOMP_USER_NOTIF_FLAG_CONTINUE = 0x1
SECRETMEM_MAGIC = 0x5345434d
SECURITYFS_MAGIC = 0x73636673
SEEK_CUR = 0x1
@@ -3021,6 +3108,7 @@ const (
SOL_TIPC = 0x10f
SOL_TLS = 0x11a
SOL_UDP = 0x11
+ SOL_VSOCK = 0x11f
SOL_X25 = 0x106
SOL_XDP = 0x11b
SOMAXCONN = 0x1000
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go
index 4920821c..42ff8c3c 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go
@@ -281,6 +281,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
index a0c1e411..dca43600 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
@@ -282,6 +282,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
index c6398556..5cca668a 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
@@ -288,6 +288,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
index 47cc62e2..d8cae6d1 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
@@ -278,6 +278,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go
index 27ac4a09..28e39afd 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go
@@ -275,6 +275,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
index 54694642..cd66e92c 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
@@ -281,6 +281,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x80
SIOCATMARK = 0x40047307
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
index 3adb81d7..c1595eba 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
@@ -281,6 +281,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x80
SIOCATMARK = 0x40047307
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
index 2dfe98f0..ee9456b0 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
@@ -281,6 +281,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x80
SIOCATMARK = 0x40047307
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
index f5398f84..8cfca81e 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
@@ -281,6 +281,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x80
SIOCATMARK = 0x40047307
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go
index c54f152d..60b0deb3 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go
@@ -336,6 +336,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
index 76057dc7..f90aa728 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
@@ -340,6 +340,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
index e0c3725e..ba9e0150 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
@@ -340,6 +340,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
index 18f2813e..07cdfd6e 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
@@ -272,6 +272,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go
index 11619d4e..2f1dd214 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go
@@ -344,6 +344,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go
index 396d994d..f40519d9 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go
@@ -335,6 +335,9 @@ const (
SCM_TIMESTAMPNS = 0x21
SCM_TXTIME = 0x3f
SCM_WIFI_STATUS = 0x25
+ SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
+ SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
+ SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x400000
SFD_NONBLOCK = 0x4000
SF_FP = 0x38
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go
index a1d06159..9dc42410 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go
@@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so"
-
-
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go
index 5b2a7409..0d3a0751 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go
@@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so"
-
-
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go
index f6eda134..c39f7776 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go
@@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so"
-
-
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go
index 55df20ae..57571d07 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go
@@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so"
-
-
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go
index 8c1155cb..e62963e6 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go
@@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so"
-
-
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go
index 7cc80c58..00831354 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go
@@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so"
-
-
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go
index 0688737f..79029ed5 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go
@@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so"
-
-
diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go
index fcf3ecbd..0cc3ce49 100644
--- a/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go
+++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go
@@ -448,4 +448,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452
+ SYS_MAP_SHADOW_STACK = 453
+ SYS_FUTEX_WAKE = 454
+ SYS_FUTEX_WAIT = 455
+ SYS_FUTEX_REQUEUE = 456
)
diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go
index f56dc250..856d92d6 100644
--- a/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go
+++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go
@@ -371,4 +371,7 @@ const (
SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452
SYS_MAP_SHADOW_STACK = 453
+ SYS_FUTEX_WAKE = 454
+ SYS_FUTEX_WAIT = 455
+ SYS_FUTEX_REQUEUE = 456
)
diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go
index 974bf246..8d467094 100644
--- a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go
+++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go
@@ -412,4 +412,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452
+ SYS_MAP_SHADOW_STACK = 453
+ SYS_FUTEX_WAKE = 454
+ SYS_FUTEX_WAIT = 455
+ SYS_FUTEX_REQUEUE = 456
)
diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go
index 39a2739e..edc17324 100644
--- a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go
+++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go
@@ -315,4 +315,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452
+ SYS_MAP_SHADOW_STACK = 453
+ SYS_FUTEX_WAKE = 454
+ SYS_FUTEX_WAIT = 455
+ SYS_FUTEX_REQUEUE = 456
)
diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go
index cf9c9d77..445eba20 100644
--- a/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go
+++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go
@@ -309,4 +309,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452
+ SYS_MAP_SHADOW_STACK = 453
+ SYS_FUTEX_WAKE = 454
+ SYS_FUTEX_WAIT = 455
+ SYS_FUTEX_REQUEUE = 456
)
diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go
index 10b7362e..adba01bc 100644
--- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go
+++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go
@@ -432,4 +432,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 4450
SYS_CACHESTAT = 4451
SYS_FCHMODAT2 = 4452
+ SYS_MAP_SHADOW_STACK = 4453
+ SYS_FUTEX_WAKE = 4454
+ SYS_FUTEX_WAIT = 4455
+ SYS_FUTEX_REQUEUE = 4456
)
diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go
index cd4d8b4f..014c4e9c 100644
--- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go
+++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go
@@ -362,4 +362,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 5450
SYS_CACHESTAT = 5451
SYS_FCHMODAT2 = 5452
+ SYS_MAP_SHADOW_STACK = 5453
+ SYS_FUTEX_WAKE = 5454
+ SYS_FUTEX_WAIT = 5455
+ SYS_FUTEX_REQUEUE = 5456
)
diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go
index 2c0efca8..ccc97d74 100644
--- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go
+++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go
@@ -362,4 +362,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 5450
SYS_CACHESTAT = 5451
SYS_FCHMODAT2 = 5452
+ SYS_MAP_SHADOW_STACK = 5453
+ SYS_FUTEX_WAKE = 5454
+ SYS_FUTEX_WAIT = 5455
+ SYS_FUTEX_REQUEUE = 5456
)
diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go
index a72e31d3..ec2b64a9 100644
--- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go
+++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go
@@ -432,4 +432,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 4450
SYS_CACHESTAT = 4451
SYS_FCHMODAT2 = 4452
+ SYS_MAP_SHADOW_STACK = 4453
+ SYS_FUTEX_WAKE = 4454
+ SYS_FUTEX_WAIT = 4455
+ SYS_FUTEX_REQUEUE = 4456
)
diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go
index c7d1e374..21a839e3 100644
--- a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go
+++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go
@@ -439,4 +439,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452
+ SYS_MAP_SHADOW_STACK = 453
+ SYS_FUTEX_WAKE = 454
+ SYS_FUTEX_WAIT = 455
+ SYS_FUTEX_REQUEUE = 456
)
diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go
index f4d4838c..c11121ec 100644
--- a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go
+++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go
@@ -411,4 +411,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452
+ SYS_MAP_SHADOW_STACK = 453
+ SYS_FUTEX_WAKE = 454
+ SYS_FUTEX_WAIT = 455
+ SYS_FUTEX_REQUEUE = 456
)
diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go
index b64f0e59..909b631f 100644
--- a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go
+++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go
@@ -411,4 +411,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452
+ SYS_MAP_SHADOW_STACK = 453
+ SYS_FUTEX_WAKE = 454
+ SYS_FUTEX_WAIT = 455
+ SYS_FUTEX_REQUEUE = 456
)
diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go
index 95711195..e49bed16 100644
--- a/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go
+++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go
@@ -316,4 +316,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452
+ SYS_MAP_SHADOW_STACK = 453
+ SYS_FUTEX_WAKE = 454
+ SYS_FUTEX_WAIT = 455
+ SYS_FUTEX_REQUEUE = 456
)
diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go
index f94e943b..66017d2d 100644
--- a/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go
+++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go
@@ -377,4 +377,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452
+ SYS_MAP_SHADOW_STACK = 453
+ SYS_FUTEX_WAKE = 454
+ SYS_FUTEX_WAIT = 455
+ SYS_FUTEX_REQUEUE = 456
)
diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go
index ba0c2bc5..47bab18d 100644
--- a/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go
+++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go
@@ -390,4 +390,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452
+ SYS_MAP_SHADOW_STACK = 453
+ SYS_FUTEX_WAKE = 454
+ SYS_FUTEX_WAIT = 455
+ SYS_FUTEX_REQUEUE = 456
)
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux.go b/vendor/golang.org/x/sys/unix/ztypes_linux.go
index bbf8399f..dc0c955e 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux.go
@@ -174,7 +174,8 @@ type FscryptPolicyV2 struct {
Contents_encryption_mode uint8
Filenames_encryption_mode uint8
Flags uint8
- _ [4]uint8
+ Log2_data_unit_size uint8
+ _ [3]uint8
Master_key_identifier [16]uint8
}
@@ -455,60 +456,63 @@ type Ucred struct {
}
type TCPInfo struct {
- State uint8
- Ca_state uint8
- Retransmits uint8
- Probes uint8
- Backoff uint8
- Options uint8
- Rto uint32
- Ato uint32
- Snd_mss uint32
- Rcv_mss uint32
- Unacked uint32
- Sacked uint32
- Lost uint32
- Retrans uint32
- Fackets uint32
- Last_data_sent uint32
- Last_ack_sent uint32
- Last_data_recv uint32
- Last_ack_recv uint32
- Pmtu uint32
- Rcv_ssthresh uint32
- Rtt uint32
- Rttvar uint32
- Snd_ssthresh uint32
- Snd_cwnd uint32
- Advmss uint32
- Reordering uint32
- Rcv_rtt uint32
- Rcv_space uint32
- Total_retrans uint32
- Pacing_rate uint64
- Max_pacing_rate uint64
- Bytes_acked uint64
- Bytes_received uint64
- Segs_out uint32
- Segs_in uint32
- Notsent_bytes uint32
- Min_rtt uint32
- Data_segs_in uint32
- Data_segs_out uint32
- Delivery_rate uint64
- Busy_time uint64
- Rwnd_limited uint64
- Sndbuf_limited uint64
- Delivered uint32
- Delivered_ce uint32
- Bytes_sent uint64
- Bytes_retrans uint64
- Dsack_dups uint32
- Reord_seen uint32
- Rcv_ooopack uint32
- Snd_wnd uint32
- Rcv_wnd uint32
- Rehash uint32
+ State uint8
+ Ca_state uint8
+ Retransmits uint8
+ Probes uint8
+ Backoff uint8
+ Options uint8
+ Rto uint32
+ Ato uint32
+ Snd_mss uint32
+ Rcv_mss uint32
+ Unacked uint32
+ Sacked uint32
+ Lost uint32
+ Retrans uint32
+ Fackets uint32
+ Last_data_sent uint32
+ Last_ack_sent uint32
+ Last_data_recv uint32
+ Last_ack_recv uint32
+ Pmtu uint32
+ Rcv_ssthresh uint32
+ Rtt uint32
+ Rttvar uint32
+ Snd_ssthresh uint32
+ Snd_cwnd uint32
+ Advmss uint32
+ Reordering uint32
+ Rcv_rtt uint32
+ Rcv_space uint32
+ Total_retrans uint32
+ Pacing_rate uint64
+ Max_pacing_rate uint64
+ Bytes_acked uint64
+ Bytes_received uint64
+ Segs_out uint32
+ Segs_in uint32
+ Notsent_bytes uint32
+ Min_rtt uint32
+ Data_segs_in uint32
+ Data_segs_out uint32
+ Delivery_rate uint64
+ Busy_time uint64
+ Rwnd_limited uint64
+ Sndbuf_limited uint64
+ Delivered uint32
+ Delivered_ce uint32
+ Bytes_sent uint64
+ Bytes_retrans uint64
+ Dsack_dups uint32
+ Reord_seen uint32
+ Rcv_ooopack uint32
+ Snd_wnd uint32
+ Rcv_wnd uint32
+ Rehash uint32
+ Total_rto uint16
+ Total_rto_recoveries uint16
+ Total_rto_time uint32
}
type CanFilter struct {
@@ -551,7 +555,7 @@ const (
SizeofIPv6MTUInfo = 0x20
SizeofICMPv6Filter = 0x20
SizeofUcred = 0xc
- SizeofTCPInfo = 0xf0
+ SizeofTCPInfo = 0xf8
SizeofCanFilter = 0x8
SizeofTCPRepairOpt = 0x8
)
@@ -3399,7 +3403,7 @@ const (
DEVLINK_PORT_FN_ATTR_STATE = 0x2
DEVLINK_PORT_FN_ATTR_OPSTATE = 0x3
DEVLINK_PORT_FN_ATTR_CAPS = 0x4
- DEVLINK_PORT_FUNCTION_ATTR_MAX = 0x4
+ DEVLINK_PORT_FUNCTION_ATTR_MAX = 0x5
)
type FsverityDigest struct {
@@ -4183,7 +4187,8 @@ const (
)
type LandlockRulesetAttr struct {
- Access_fs uint64
+ Access_fs uint64
+ Access_net uint64
}
type LandlockPathBeneathAttr struct {
@@ -5134,7 +5139,7 @@ const (
NL80211_FREQUENCY_ATTR_GO_CONCURRENT = 0xf
NL80211_FREQUENCY_ATTR_INDOOR_ONLY = 0xe
NL80211_FREQUENCY_ATTR_IR_CONCURRENT = 0xf
- NL80211_FREQUENCY_ATTR_MAX = 0x1b
+ NL80211_FREQUENCY_ATTR_MAX = 0x1c
NL80211_FREQUENCY_ATTR_MAX_TX_POWER = 0x6
NL80211_FREQUENCY_ATTR_NO_10MHZ = 0x11
NL80211_FREQUENCY_ATTR_NO_160MHZ = 0xc
@@ -5547,7 +5552,7 @@ const (
NL80211_REGDOM_TYPE_CUSTOM_WORLD = 0x2
NL80211_REGDOM_TYPE_INTERSECTION = 0x3
NL80211_REGDOM_TYPE_WORLD = 0x1
- NL80211_REG_RULE_ATTR_MAX = 0x7
+ NL80211_REG_RULE_ATTR_MAX = 0x8
NL80211_REKEY_DATA_AKM = 0x4
NL80211_REKEY_DATA_KCK = 0x2
NL80211_REKEY_DATA_KEK = 0x1
diff --git a/vendor/golang.org/x/sys/windows/env_windows.go b/vendor/golang.org/x/sys/windows/env_windows.go
index b8ad1925..d4577a42 100644
--- a/vendor/golang.org/x/sys/windows/env_windows.go
+++ b/vendor/golang.org/x/sys/windows/env_windows.go
@@ -37,14 +37,17 @@ func (token Token) Environ(inheritExisting bool) (env []string, err error) {
return nil, err
}
defer DestroyEnvironmentBlock(block)
- blockp := unsafe.Pointer(block)
- for {
- entry := UTF16PtrToString((*uint16)(blockp))
- if len(entry) == 0 {
- break
+ size := unsafe.Sizeof(*block)
+ for *block != 0 {
+ // find NUL terminator
+ end := unsafe.Pointer(block)
+ for *(*uint16)(end) != 0 {
+ end = unsafe.Add(end, size)
}
- env = append(env, entry)
- blockp = unsafe.Add(blockp, 2*(len(entry)+1))
+
+ entry := unsafe.Slice(block, (uintptr(end)-uintptr(unsafe.Pointer(block)))/size)
+ env = append(env, UTF16ToString(entry))
+ block = (*uint16)(unsafe.Add(end, size))
}
return env, nil
}
diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go
index 47dc5796..6395a031 100644
--- a/vendor/golang.org/x/sys/windows/syscall_windows.go
+++ b/vendor/golang.org/x/sys/windows/syscall_windows.go
@@ -125,8 +125,7 @@ func UTF16PtrToString(p *uint16) string {
for ptr := unsafe.Pointer(p); *(*uint16)(ptr) != 0; n++ {
ptr = unsafe.Pointer(uintptr(ptr) + unsafe.Sizeof(*p))
}
-
- return string(utf16.Decode(unsafe.Slice(p, n)))
+ return UTF16ToString(unsafe.Slice(p, n))
}
func Getpagesize() int { return 4096 }
@@ -194,6 +193,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW
//sys GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW
//sys SetEndOfFile(handle Handle) (err error)
+//sys SetFileValidData(handle Handle, validDataLength int64) (err error)
//sys GetSystemTimeAsFileTime(time *Filetime)
//sys GetSystemTimePreciseAsFileTime(time *Filetime)
//sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff]
diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go
index 146a1f01..e8791c82 100644
--- a/vendor/golang.org/x/sys/windows/zsyscall_windows.go
+++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go
@@ -342,6 +342,7 @@ var (
procSetDefaultDllDirectories = modkernel32.NewProc("SetDefaultDllDirectories")
procSetDllDirectoryW = modkernel32.NewProc("SetDllDirectoryW")
procSetEndOfFile = modkernel32.NewProc("SetEndOfFile")
+ procSetFileValidData = modkernel32.NewProc("SetFileValidData")
procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW")
procSetErrorMode = modkernel32.NewProc("SetErrorMode")
procSetEvent = modkernel32.NewProc("SetEvent")
@@ -2988,6 +2989,14 @@ func SetEndOfFile(handle Handle) (err error) {
return
}
+func SetFileValidData(handle Handle, validDataLength int64) (err error) {
+ r1, _, e1 := syscall.Syscall(procSetFileValidData.Addr(), 2, uintptr(handle), uintptr(validDataLength), 0)
+ if r1 == 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
func SetEnvironmentVariable(name *uint16, value *uint16) (err error) {
r1, _, e1 := syscall.Syscall(procSetEnvironmentVariableW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0)
if r1 == 0 {
diff --git a/vendor/golang.org/x/tools/cmd/stringer/stringer.go b/vendor/golang.org/x/tools/cmd/stringer/stringer.go
index 998d1a51..2b19c93e 100644
--- a/vendor/golang.org/x/tools/cmd/stringer/stringer.go
+++ b/vendor/golang.org/x/tools/cmd/stringer/stringer.go
@@ -188,6 +188,8 @@ type Generator struct {
trimPrefix string
lineComment bool
+
+ logf func(format string, args ...interface{}) // test logging hook; nil when not testing
}
func (g *Generator) Printf(format string, args ...interface{}) {
@@ -221,13 +223,14 @@ func (g *Generator) parsePackage(patterns []string, tags []string) {
// in a separate pass? For later.
Tests: false,
BuildFlags: []string{fmt.Sprintf("-tags=%s", strings.Join(tags, " "))},
+ Logf: g.logf,
}
pkgs, err := packages.Load(cfg, patterns...)
if err != nil {
log.Fatal(err)
}
if len(pkgs) != 1 {
- log.Fatalf("error: %d packages found", len(pkgs))
+ log.Fatalf("error: %d packages matching %v", len(pkgs), strings.Join(patterns, " "))
}
g.addPackage(pkgs[0])
}
diff --git a/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go b/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go
index 0454cdd7..333676b7 100644
--- a/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go
+++ b/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go
@@ -13,16 +13,17 @@ import (
"golang.org/x/tools/internal/gocommand"
)
-var debug = false
-
func GetSizesForArgsGolist(ctx context.Context, inv gocommand.Invocation, gocmdRunner *gocommand.Runner) (string, string, error) {
inv.Verb = "list"
inv.Args = []string{"-f", "{{context.GOARCH}} {{context.Compiler}}", "--", "unsafe"}
stdout, stderr, friendlyErr, rawErr := gocmdRunner.RunRaw(ctx, inv)
var goarch, compiler string
if rawErr != nil {
- if rawErrMsg := rawErr.Error(); strings.Contains(rawErrMsg, "cannot find main module") || strings.Contains(rawErrMsg, "go.mod file not found") {
- // User's running outside of a module. All bets are off. Get GOARCH and guess compiler is gc.
+ rawErrMsg := rawErr.Error()
+ if strings.Contains(rawErrMsg, "cannot find main module") ||
+ strings.Contains(rawErrMsg, "go.mod file not found") {
+ // User's running outside of a module.
+ // All bets are off. Get GOARCH and guess compiler is gc.
// TODO(matloob): Is this a problem in practice?
inv.Verb = "env"
inv.Args = []string{"GOARCH"}
@@ -32,8 +33,12 @@ func GetSizesForArgsGolist(ctx context.Context, inv gocommand.Invocation, gocmdR
}
goarch = strings.TrimSpace(envout.String())
compiler = "gc"
- } else {
+ } else if friendlyErr != nil {
return "", "", friendlyErr
+ } else {
+ // This should be unreachable, but be defensive
+ // in case RunRaw's error results are inconsistent.
+ return "", "", rawErr
}
} else {
fields := strings.Fields(stdout.String())
diff --git a/vendor/golang.org/x/tools/go/packages/doc.go b/vendor/golang.org/x/tools/go/packages/doc.go
index da4ab89f..a8d7b06a 100644
--- a/vendor/golang.org/x/tools/go/packages/doc.go
+++ b/vendor/golang.org/x/tools/go/packages/doc.go
@@ -5,12 +5,20 @@
/*
Package packages loads Go packages for inspection and analysis.
-The Load function takes as input a list of patterns and return a list of Package
-structs describing individual packages matched by those patterns.
-The LoadMode controls the amount of detail in the loaded packages.
-
-Load passes most patterns directly to the underlying build tool,
-but all patterns with the prefix "query=", where query is a
+The [Load] function takes as input a list of patterns and returns a
+list of [Package] values describing individual packages matched by those
+patterns.
+A [Config] specifies configuration options, the most important of which is
+the [LoadMode], which controls the amount of detail in the loaded packages.
+
+Load passes most patterns directly to the underlying build tool.
+The default build tool is the go command.
+Its supported patterns are described at
+https://pkg.go.dev/cmd/go#hdr-Package_lists_and_patterns.
+Other build systems may be supported by providing a "driver";
+see [The driver protocol].
+
+All patterns with the prefix "query=", where query is a
non-empty string of letters from [a-z], are reserved and may be
interpreted as query operators.
@@ -35,7 +43,7 @@ The Package struct provides basic information about the package, including
- Imports, a map from source import strings to the Packages they name;
- Types, the type information for the package's exported symbols;
- Syntax, the parsed syntax trees for the package's source code; and
- - TypeInfo, the result of a complete type-check of the package syntax trees.
+ - TypesInfo, the result of a complete type-check of the package syntax trees.
(See the documentation for type Package for the complete list of fields
and more detailed descriptions.)
@@ -64,9 +72,31 @@ reported about the loaded packages. See the documentation for type LoadMode
for details.
Most tools should pass their command-line arguments (after any flags)
-uninterpreted to the loader, so that the loader can interpret them
+uninterpreted to [Load], so that it can interpret them
according to the conventions of the underlying build system.
+
See the Example function for typical usage.
+
+# The driver protocol
+
+[Load] may be used to load Go packages even in Go projects that use
+alternative build systems, by installing an appropriate "driver"
+program for the build system and specifying its location in the
+GOPACKAGESDRIVER environment variable.
+For example,
+https://github.com/bazelbuild/rules_go/wiki/Editor-and-tool-integration
+explains how to use the driver for Bazel.
+
+The driver program is responsible for interpreting patterns in its
+preferred notation and reporting information about the packages that
+those patterns identify. Drivers must also support the special "file="
+and "pattern=" patterns described above.
+
+The patterns are provided as positional command-line arguments. A
+JSON-encoded [DriverRequest] message providing additional information
+is written to the driver's standard input. The driver must write a
+JSON-encoded [DriverResponse] message to its standard output. (This
+message differs from the JSON schema produced by 'go list'.)
*/
package packages // import "golang.org/x/tools/go/packages"
diff --git a/vendor/golang.org/x/tools/go/packages/external.go b/vendor/golang.org/x/tools/go/packages/external.go
index 7242a0a7..4335c1eb 100644
--- a/vendor/golang.org/x/tools/go/packages/external.go
+++ b/vendor/golang.org/x/tools/go/packages/external.go
@@ -2,46 +2,85 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// This file enables an external tool to intercept package requests.
-// If the tool is present then its results are used in preference to
-// the go list command.
-
package packages
+// This file defines the protocol that enables an external "driver"
+// tool to supply package metadata in place of 'go list'.
+
import (
"bytes"
"encoding/json"
"fmt"
- exec "golang.org/x/sys/execabs"
"os"
+ "os/exec"
"strings"
)
-// The Driver Protocol
+// DriverRequest defines the schema of a request for package metadata
+// from an external driver program. The JSON-encoded DriverRequest
+// message is provided to the driver program's standard input. The
+// query patterns are provided as command-line arguments.
//
-// The driver, given the inputs to a call to Load, returns metadata about the packages specified.
-// This allows for different build systems to support go/packages by telling go/packages how the
-// packages' source is organized.
-// The driver is a binary, either specified by the GOPACKAGESDRIVER environment variable or in
-// the path as gopackagesdriver. It's given the inputs to load in its argv. See the package
-// documentation in doc.go for the full description of the patterns that need to be supported.
-// A driver receives as a JSON-serialized driverRequest struct in standard input and will
-// produce a JSON-serialized driverResponse (see definition in packages.go) in its standard output.
-
-// driverRequest is used to provide the portion of Load's Config that is needed by a driver.
-type driverRequest struct {
+// See the package documentation for an overview.
+type DriverRequest struct {
Mode LoadMode `json:"mode"`
+
// Env specifies the environment the underlying build system should be run in.
Env []string `json:"env"`
+
// BuildFlags are flags that should be passed to the underlying build system.
BuildFlags []string `json:"build_flags"`
+
// Tests specifies whether the patterns should also return test packages.
Tests bool `json:"tests"`
+
// Overlay maps file paths (relative to the driver's working directory) to the byte contents
// of overlay files.
Overlay map[string][]byte `json:"overlay"`
}
+// DriverResponse defines the schema of a response from an external
+// driver program, providing the results of a query for package
+// metadata. The driver program must write a JSON-encoded
+// DriverResponse message to its standard output.
+//
+// See the package documentation for an overview.
+type DriverResponse struct {
+ // NotHandled is returned if the request can't be handled by the current
+ // driver. If an external driver returns a response with NotHandled, the
+ // rest of the DriverResponse is ignored, and go/packages will fallback
+ // to the next driver. If go/packages is extended in the future to support
+ // lists of multiple drivers, go/packages will fall back to the next driver.
+ NotHandled bool
+
+ // Compiler and Arch are the arguments pass of types.SizesFor
+ // to get a types.Sizes to use when type checking.
+ Compiler string
+ Arch string
+
+ // Roots is the set of package IDs that make up the root packages.
+ // We have to encode this separately because when we encode a single package
+ // we cannot know if it is one of the roots as that requires knowledge of the
+ // graph it is part of.
+ Roots []string `json:",omitempty"`
+
+ // Packages is the full set of packages in the graph.
+ // The packages are not connected into a graph.
+ // The Imports if populated will be stubs that only have their ID set.
+ // Imports will be connected and then type and syntax information added in a
+ // later pass (see refine).
+ Packages []*Package
+
+ // GoVersion is the minor version number used by the driver
+ // (e.g. the go command on the PATH) when selecting .go files.
+ // Zero means unknown.
+ GoVersion int
+}
+
+// driver is the type for functions that query the build system for the
+// packages named by the patterns.
+type driver func(cfg *Config, patterns ...string) (*DriverResponse, error)
+
// findExternalDriver returns the file path of a tool that supplies
// the build system package structure, or "" if not found."
// If GOPACKAGESDRIVER is set in the environment findExternalTool returns its
@@ -64,8 +103,8 @@ func findExternalDriver(cfg *Config) driver {
return nil
}
}
- return func(cfg *Config, words ...string) (*driverResponse, error) {
- req, err := json.Marshal(driverRequest{
+ return func(cfg *Config, words ...string) (*DriverResponse, error) {
+ req, err := json.Marshal(DriverRequest{
Mode: cfg.Mode,
Env: cfg.Env,
BuildFlags: cfg.BuildFlags,
@@ -92,7 +131,7 @@ func findExternalDriver(cfg *Config) driver {
fmt.Fprintf(os.Stderr, "%s stderr: <<%s>>\n", cmdDebugStr(cmd), stderr)
}
- var response driverResponse
+ var response DriverResponse
if err := json.Unmarshal(buf.Bytes(), &response); err != nil {
return nil, err
}
diff --git a/vendor/golang.org/x/tools/go/packages/golist.go b/vendor/golang.org/x/tools/go/packages/golist.go
index b5de9cf9..22305d9c 100644
--- a/vendor/golang.org/x/tools/go/packages/golist.go
+++ b/vendor/golang.org/x/tools/go/packages/golist.go
@@ -9,9 +9,9 @@ import (
"context"
"encoding/json"
"fmt"
- "io/ioutil"
"log"
"os"
+ "os/exec"
"path"
"path/filepath"
"reflect"
@@ -21,7 +21,6 @@ import (
"sync"
"unicode"
- exec "golang.org/x/sys/execabs"
"golang.org/x/tools/go/internal/packagesdriver"
"golang.org/x/tools/internal/gocommand"
"golang.org/x/tools/internal/packagesinternal"
@@ -36,23 +35,23 @@ type goTooOldError struct {
error
}
-// responseDeduper wraps a driverResponse, deduplicating its contents.
+// responseDeduper wraps a DriverResponse, deduplicating its contents.
type responseDeduper struct {
seenRoots map[string]bool
seenPackages map[string]*Package
- dr *driverResponse
+ dr *DriverResponse
}
func newDeduper() *responseDeduper {
return &responseDeduper{
- dr: &driverResponse{},
+ dr: &DriverResponse{},
seenRoots: map[string]bool{},
seenPackages: map[string]*Package{},
}
}
-// addAll fills in r with a driverResponse.
-func (r *responseDeduper) addAll(dr *driverResponse) {
+// addAll fills in r with a DriverResponse.
+func (r *responseDeduper) addAll(dr *DriverResponse) {
for _, pkg := range dr.Packages {
r.addPackage(pkg)
}
@@ -129,7 +128,7 @@ func (state *golistState) mustGetEnv() map[string]string {
// goListDriver uses the go list command to interpret the patterns and produce
// the build system package structure.
// See driver for more details.
-func goListDriver(cfg *Config, patterns ...string) (*driverResponse, error) {
+func goListDriver(cfg *Config, patterns ...string) (_ *DriverResponse, err error) {
// Make sure that any asynchronous go commands are killed when we return.
parentCtx := cfg.Context
if parentCtx == nil {
@@ -147,16 +146,18 @@ func goListDriver(cfg *Config, patterns ...string) (*driverResponse, error) {
}
// Fill in response.Sizes asynchronously if necessary.
- var sizeserr error
- var sizeswg sync.WaitGroup
if cfg.Mode&NeedTypesSizes != 0 || cfg.Mode&NeedTypes != 0 {
- sizeswg.Add(1)
+ errCh := make(chan error)
go func() {
compiler, arch, err := packagesdriver.GetSizesForArgsGolist(ctx, state.cfgInvocation(), cfg.gocmdRunner)
- sizeserr = err
response.dr.Compiler = compiler
response.dr.Arch = arch
- sizeswg.Done()
+ errCh <- err
+ }()
+ defer func() {
+ if sizesErr := <-errCh; sizesErr != nil {
+ err = sizesErr
+ }
}()
}
@@ -209,87 +210,10 @@ extractQueries:
}
}
- // Only use go/packages' overlay processing if we're using a Go version
- // below 1.16. Otherwise, go list handles it.
- if goVersion, err := state.getGoVersion(); err == nil && goVersion < 16 {
- modifiedPkgs, needPkgs, err := state.processGolistOverlay(response)
- if err != nil {
- return nil, err
- }
-
- var containsCandidates []string
- if len(containFiles) > 0 {
- containsCandidates = append(containsCandidates, modifiedPkgs...)
- containsCandidates = append(containsCandidates, needPkgs...)
- }
- if err := state.addNeededOverlayPackages(response, needPkgs); err != nil {
- return nil, err
- }
- // Check candidate packages for containFiles.
- if len(containFiles) > 0 {
- for _, id := range containsCandidates {
- pkg, ok := response.seenPackages[id]
- if !ok {
- response.addPackage(&Package{
- ID: id,
- Errors: []Error{{
- Kind: ListError,
- Msg: fmt.Sprintf("package %s expected but not seen", id),
- }},
- })
- continue
- }
- for _, f := range containFiles {
- for _, g := range pkg.GoFiles {
- if sameFile(f, g) {
- response.addRoot(id)
- }
- }
- }
- }
- }
- // Add root for any package that matches a pattern. This applies only to
- // packages that are modified by overlays, since they are not added as
- // roots automatically.
- for _, pattern := range restPatterns {
- match := matchPattern(pattern)
- for _, pkgID := range modifiedPkgs {
- pkg, ok := response.seenPackages[pkgID]
- if !ok {
- continue
- }
- if match(pkg.PkgPath) {
- response.addRoot(pkg.ID)
- }
- }
- }
- }
-
- sizeswg.Wait()
- if sizeserr != nil {
- return nil, sizeserr
- }
+ // (We may yet return an error due to defer.)
return response.dr, nil
}
-func (state *golistState) addNeededOverlayPackages(response *responseDeduper, pkgs []string) error {
- if len(pkgs) == 0 {
- return nil
- }
- dr, err := state.createDriverResponse(pkgs...)
- if err != nil {
- return err
- }
- for _, pkg := range dr.Packages {
- response.addPackage(pkg)
- }
- _, needPkgs, err := state.processGolistOverlay(response)
- if err != nil {
- return err
- }
- return state.addNeededOverlayPackages(response, needPkgs)
-}
-
func (state *golistState) runContainsQueries(response *responseDeduper, queries []string) error {
for _, query := range queries {
// TODO(matloob): Do only one query per directory.
@@ -341,7 +265,7 @@ func (state *golistState) runContainsQueries(response *responseDeduper, queries
// adhocPackage attempts to load or construct an ad-hoc package for a given
// query, if the original call to the driver produced inadequate results.
-func (state *golistState) adhocPackage(pattern, query string) (*driverResponse, error) {
+func (state *golistState) adhocPackage(pattern, query string) (*DriverResponse, error) {
response, err := state.createDriverResponse(query)
if err != nil {
return nil, err
@@ -432,7 +356,7 @@ func otherFiles(p *jsonPackage) [][]string {
// createDriverResponse uses the "go list" command to expand the pattern
// words and return a response for the specified packages.
-func (state *golistState) createDriverResponse(words ...string) (*driverResponse, error) {
+func (state *golistState) createDriverResponse(words ...string) (*DriverResponse, error) {
// go list uses the following identifiers in ImportPath and Imports:
//
// "p" -- importable package or main (command)
@@ -459,7 +383,7 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse
pkgs := make(map[string]*Package)
additionalErrors := make(map[string][]Error)
// Decode the JSON and convert it to Package form.
- response := &driverResponse{
+ response := &DriverResponse{
GoVersion: goVersion,
}
for dec := json.NewDecoder(buf); dec.More(); {
@@ -1109,7 +1033,7 @@ func (state *golistState) writeOverlays() (filename string, cleanup func(), err
if len(state.cfg.Overlay) == 0 {
return "", func() {}, nil
}
- dir, err := ioutil.TempDir("", "gopackages-*")
+ dir, err := os.MkdirTemp("", "gopackages-*")
if err != nil {
return "", nil, err
}
@@ -1128,7 +1052,7 @@ func (state *golistState) writeOverlays() (filename string, cleanup func(), err
// Create a unique filename for the overlaid files, to avoid
// creating nested directories.
noSeparator := strings.Join(strings.Split(filepath.ToSlash(k), "/"), "")
- f, err := ioutil.TempFile(dir, fmt.Sprintf("*-%s", noSeparator))
+ f, err := os.CreateTemp(dir, fmt.Sprintf("*-%s", noSeparator))
if err != nil {
return "", func() {}, err
}
@@ -1146,7 +1070,7 @@ func (state *golistState) writeOverlays() (filename string, cleanup func(), err
}
// Write out the overlay file that contains the filepath mappings.
filename = filepath.Join(dir, "overlay.json")
- if err := ioutil.WriteFile(filename, b, 0665); err != nil {
+ if err := os.WriteFile(filename, b, 0665); err != nil {
return "", func() {}, err
}
return filename, cleanup, nil
diff --git a/vendor/golang.org/x/tools/go/packages/golist_overlay.go b/vendor/golang.org/x/tools/go/packages/golist_overlay.go
index 9576b472..d823c474 100644
--- a/vendor/golang.org/x/tools/go/packages/golist_overlay.go
+++ b/vendor/golang.org/x/tools/go/packages/golist_overlay.go
@@ -6,314 +6,11 @@ package packages
import (
"encoding/json"
- "fmt"
- "go/parser"
- "go/token"
- "os"
"path/filepath"
- "regexp"
- "sort"
- "strconv"
- "strings"
"golang.org/x/tools/internal/gocommand"
)
-// processGolistOverlay provides rudimentary support for adding
-// files that don't exist on disk to an overlay. The results can be
-// sometimes incorrect.
-// TODO(matloob): Handle unsupported cases, including the following:
-// - determining the correct package to add given a new import path
-func (state *golistState) processGolistOverlay(response *responseDeduper) (modifiedPkgs, needPkgs []string, err error) {
- havePkgs := make(map[string]string) // importPath -> non-test package ID
- needPkgsSet := make(map[string]bool)
- modifiedPkgsSet := make(map[string]bool)
-
- pkgOfDir := make(map[string][]*Package)
- for _, pkg := range response.dr.Packages {
- // This is an approximation of import path to id. This can be
- // wrong for tests, vendored packages, and a number of other cases.
- havePkgs[pkg.PkgPath] = pkg.ID
- dir, err := commonDir(pkg.GoFiles)
- if err != nil {
- return nil, nil, err
- }
- if dir != "" {
- pkgOfDir[dir] = append(pkgOfDir[dir], pkg)
- }
- }
-
- // If no new imports are added, it is safe to avoid loading any needPkgs.
- // Otherwise, it's hard to tell which package is actually being loaded
- // (due to vendoring) and whether any modified package will show up
- // in the transitive set of dependencies (because new imports are added,
- // potentially modifying the transitive set of dependencies).
- var overlayAddsImports bool
-
- // If both a package and its test package are created by the overlay, we
- // need the real package first. Process all non-test files before test
- // files, and make the whole process deterministic while we're at it.
- var overlayFiles []string
- for opath := range state.cfg.Overlay {
- overlayFiles = append(overlayFiles, opath)
- }
- sort.Slice(overlayFiles, func(i, j int) bool {
- iTest := strings.HasSuffix(overlayFiles[i], "_test.go")
- jTest := strings.HasSuffix(overlayFiles[j], "_test.go")
- if iTest != jTest {
- return !iTest // non-tests are before tests.
- }
- return overlayFiles[i] < overlayFiles[j]
- })
- for _, opath := range overlayFiles {
- contents := state.cfg.Overlay[opath]
- base := filepath.Base(opath)
- dir := filepath.Dir(opath)
- var pkg *Package // if opath belongs to both a package and its test variant, this will be the test variant
- var testVariantOf *Package // if opath is a test file, this is the package it is testing
- var fileExists bool
- isTestFile := strings.HasSuffix(opath, "_test.go")
- pkgName, ok := extractPackageName(opath, contents)
- if !ok {
- // Don't bother adding a file that doesn't even have a parsable package statement
- // to the overlay.
- continue
- }
- // If all the overlay files belong to a different package, change the
- // package name to that package.
- maybeFixPackageName(pkgName, isTestFile, pkgOfDir[dir])
- nextPackage:
- for _, p := range response.dr.Packages {
- if pkgName != p.Name && p.ID != "command-line-arguments" {
- continue
- }
- for _, f := range p.GoFiles {
- if !sameFile(filepath.Dir(f), dir) {
- continue
- }
- // Make sure to capture information on the package's test variant, if needed.
- if isTestFile && !hasTestFiles(p) {
- // TODO(matloob): Are there packages other than the 'production' variant
- // of a package that this can match? This shouldn't match the test main package
- // because the file is generated in another directory.
- testVariantOf = p
- continue nextPackage
- } else if !isTestFile && hasTestFiles(p) {
- // We're examining a test variant, but the overlaid file is
- // a non-test file. Because the overlay implementation
- // (currently) only adds a file to one package, skip this
- // package, so that we can add the file to the production
- // variant of the package. (https://golang.org/issue/36857
- // tracks handling overlays on both the production and test
- // variant of a package).
- continue nextPackage
- }
- if pkg != nil && p != pkg && pkg.PkgPath == p.PkgPath {
- // We have already seen the production version of the
- // for which p is a test variant.
- if hasTestFiles(p) {
- testVariantOf = pkg
- }
- }
- pkg = p
- if filepath.Base(f) == base {
- fileExists = true
- }
- }
- }
- // The overlay could have included an entirely new package or an
- // ad-hoc package. An ad-hoc package is one that we have manually
- // constructed from inadequate `go list` results for a file= query.
- // It will have the ID command-line-arguments.
- if pkg == nil || pkg.ID == "command-line-arguments" {
- // Try to find the module or gopath dir the file is contained in.
- // Then for modules, add the module opath to the beginning.
- pkgPath, ok, err := state.getPkgPath(dir)
- if err != nil {
- return nil, nil, err
- }
- if !ok {
- break
- }
- var forTest string // only set for x tests
- isXTest := strings.HasSuffix(pkgName, "_test")
- if isXTest {
- forTest = pkgPath
- pkgPath += "_test"
- }
- id := pkgPath
- if isTestFile {
- if isXTest {
- id = fmt.Sprintf("%s [%s.test]", pkgPath, forTest)
- } else {
- id = fmt.Sprintf("%s [%s.test]", pkgPath, pkgPath)
- }
- }
- if pkg != nil {
- // TODO(rstambler): We should change the package's path and ID
- // here. The only issue is that this messes with the roots.
- } else {
- // Try to reclaim a package with the same ID, if it exists in the response.
- for _, p := range response.dr.Packages {
- if reclaimPackage(p, id, opath, contents) {
- pkg = p
- break
- }
- }
- // Otherwise, create a new package.
- if pkg == nil {
- pkg = &Package{
- PkgPath: pkgPath,
- ID: id,
- Name: pkgName,
- Imports: make(map[string]*Package),
- }
- response.addPackage(pkg)
- havePkgs[pkg.PkgPath] = id
- // Add the production package's sources for a test variant.
- if isTestFile && !isXTest && testVariantOf != nil {
- pkg.GoFiles = append(pkg.GoFiles, testVariantOf.GoFiles...)
- pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, testVariantOf.CompiledGoFiles...)
- // Add the package under test and its imports to the test variant.
- pkg.forTest = testVariantOf.PkgPath
- for k, v := range testVariantOf.Imports {
- pkg.Imports[k] = &Package{ID: v.ID}
- }
- }
- if isXTest {
- pkg.forTest = forTest
- }
- }
- }
- }
- if !fileExists {
- pkg.GoFiles = append(pkg.GoFiles, opath)
- // TODO(matloob): Adding the file to CompiledGoFiles can exhibit the wrong behavior
- // if the file will be ignored due to its build tags.
- pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, opath)
- modifiedPkgsSet[pkg.ID] = true
- }
- imports, err := extractImports(opath, contents)
- if err != nil {
- // Let the parser or type checker report errors later.
- continue
- }
- for _, imp := range imports {
- // TODO(rstambler): If the package is an x test and the import has
- // a test variant, make sure to replace it.
- if _, found := pkg.Imports[imp]; found {
- continue
- }
- overlayAddsImports = true
- id, ok := havePkgs[imp]
- if !ok {
- var err error
- id, err = state.resolveImport(dir, imp)
- if err != nil {
- return nil, nil, err
- }
- }
- pkg.Imports[imp] = &Package{ID: id}
- // Add dependencies to the non-test variant version of this package as well.
- if testVariantOf != nil {
- testVariantOf.Imports[imp] = &Package{ID: id}
- }
- }
- }
-
- // toPkgPath guesses the package path given the id.
- toPkgPath := func(sourceDir, id string) (string, error) {
- if i := strings.IndexByte(id, ' '); i >= 0 {
- return state.resolveImport(sourceDir, id[:i])
- }
- return state.resolveImport(sourceDir, id)
- }
-
- // Now that new packages have been created, do another pass to determine
- // the new set of missing packages.
- for _, pkg := range response.dr.Packages {
- for _, imp := range pkg.Imports {
- if len(pkg.GoFiles) == 0 {
- return nil, nil, fmt.Errorf("cannot resolve imports for package %q with no Go files", pkg.PkgPath)
- }
- pkgPath, err := toPkgPath(filepath.Dir(pkg.GoFiles[0]), imp.ID)
- if err != nil {
- return nil, nil, err
- }
- if _, ok := havePkgs[pkgPath]; !ok {
- needPkgsSet[pkgPath] = true
- }
- }
- }
-
- if overlayAddsImports {
- needPkgs = make([]string, 0, len(needPkgsSet))
- for pkg := range needPkgsSet {
- needPkgs = append(needPkgs, pkg)
- }
- }
- modifiedPkgs = make([]string, 0, len(modifiedPkgsSet))
- for pkg := range modifiedPkgsSet {
- modifiedPkgs = append(modifiedPkgs, pkg)
- }
- return modifiedPkgs, needPkgs, err
-}
-
-// resolveImport finds the ID of a package given its import path.
-// In particular, it will find the right vendored copy when in GOPATH mode.
-func (state *golistState) resolveImport(sourceDir, importPath string) (string, error) {
- env, err := state.getEnv()
- if err != nil {
- return "", err
- }
- if env["GOMOD"] != "" {
- return importPath, nil
- }
-
- searchDir := sourceDir
- for {
- vendorDir := filepath.Join(searchDir, "vendor")
- exists, ok := state.vendorDirs[vendorDir]
- if !ok {
- info, err := os.Stat(vendorDir)
- exists = err == nil && info.IsDir()
- state.vendorDirs[vendorDir] = exists
- }
-
- if exists {
- vendoredPath := filepath.Join(vendorDir, importPath)
- if info, err := os.Stat(vendoredPath); err == nil && info.IsDir() {
- // We should probably check for .go files here, but shame on anyone who fools us.
- path, ok, err := state.getPkgPath(vendoredPath)
- if err != nil {
- return "", err
- }
- if ok {
- return path, nil
- }
- }
- }
-
- // We know we've hit the top of the filesystem when we Dir / and get /,
- // or C:\ and get C:\, etc.
- next := filepath.Dir(searchDir)
- if next == searchDir {
- break
- }
- searchDir = next
- }
- return importPath, nil
-}
-
-func hasTestFiles(p *Package) bool {
- for _, f := range p.GoFiles {
- if strings.HasSuffix(f, "_test.go") {
- return true
- }
- }
- return false
-}
-
// determineRootDirs returns a mapping from absolute directories that could
// contain code to their corresponding import path prefixes.
func (state *golistState) determineRootDirs() (map[string]string, error) {
@@ -384,192 +81,3 @@ func (state *golistState) determineRootDirsGOPATH() (map[string]string, error) {
}
return m, nil
}
-
-func extractImports(filename string, contents []byte) ([]string, error) {
- f, err := parser.ParseFile(token.NewFileSet(), filename, contents, parser.ImportsOnly) // TODO(matloob): reuse fileset?
- if err != nil {
- return nil, err
- }
- var res []string
- for _, imp := range f.Imports {
- quotedPath := imp.Path.Value
- path, err := strconv.Unquote(quotedPath)
- if err != nil {
- return nil, err
- }
- res = append(res, path)
- }
- return res, nil
-}
-
-// reclaimPackage attempts to reuse a package that failed to load in an overlay.
-//
-// If the package has errors and has no Name, GoFiles, or Imports,
-// then it's possible that it doesn't yet exist on disk.
-func reclaimPackage(pkg *Package, id string, filename string, contents []byte) bool {
- // TODO(rstambler): Check the message of the actual error?
- // It differs between $GOPATH and module mode.
- if pkg.ID != id {
- return false
- }
- if len(pkg.Errors) != 1 {
- return false
- }
- if pkg.Name != "" || pkg.ExportFile != "" {
- return false
- }
- if len(pkg.GoFiles) > 0 || len(pkg.CompiledGoFiles) > 0 || len(pkg.OtherFiles) > 0 {
- return false
- }
- if len(pkg.Imports) > 0 {
- return false
- }
- pkgName, ok := extractPackageName(filename, contents)
- if !ok {
- return false
- }
- pkg.Name = pkgName
- pkg.Errors = nil
- return true
-}
-
-func extractPackageName(filename string, contents []byte) (string, bool) {
- // TODO(rstambler): Check the message of the actual error?
- // It differs between $GOPATH and module mode.
- f, err := parser.ParseFile(token.NewFileSet(), filename, contents, parser.PackageClauseOnly) // TODO(matloob): reuse fileset?
- if err != nil {
- return "", false
- }
- return f.Name.Name, true
-}
-
-// commonDir returns the directory that all files are in, "" if files is empty,
-// or an error if they aren't in the same directory.
-func commonDir(files []string) (string, error) {
- seen := make(map[string]bool)
- for _, f := range files {
- seen[filepath.Dir(f)] = true
- }
- if len(seen) > 1 {
- return "", fmt.Errorf("files (%v) are in more than one directory: %v", files, seen)
- }
- for k := range seen {
- // seen has only one element; return it.
- return k, nil
- }
- return "", nil // no files
-}
-
-// It is possible that the files in the disk directory dir have a different package
-// name from newName, which is deduced from the overlays. If they all have a different
-// package name, and they all have the same package name, then that name becomes
-// the package name.
-// It returns true if it changes the package name, false otherwise.
-func maybeFixPackageName(newName string, isTestFile bool, pkgsOfDir []*Package) {
- names := make(map[string]int)
- for _, p := range pkgsOfDir {
- names[p.Name]++
- }
- if len(names) != 1 {
- // some files are in different packages
- return
- }
- var oldName string
- for k := range names {
- oldName = k
- }
- if newName == oldName {
- return
- }
- // We might have a case where all of the package names in the directory are
- // the same, but the overlay file is for an x test, which belongs to its
- // own package. If the x test does not yet exist on disk, we may not yet
- // have its package name on disk, but we should not rename the packages.
- //
- // We use a heuristic to determine if this file belongs to an x test:
- // The test file should have a package name whose package name has a _test
- // suffix or looks like "newName_test".
- maybeXTest := strings.HasPrefix(oldName+"_test", newName) || strings.HasSuffix(newName, "_test")
- if isTestFile && maybeXTest {
- return
- }
- for _, p := range pkgsOfDir {
- p.Name = newName
- }
-}
-
-// This function is copy-pasted from
-// https://github.com/golang/go/blob/9706f510a5e2754595d716bd64be8375997311fb/src/cmd/go/internal/search/search.go#L360.
-// It should be deleted when we remove support for overlays from go/packages.
-//
-// NOTE: This does not handle any ./... or ./ style queries, as this function
-// doesn't know the working directory.
-//
-// matchPattern(pattern)(name) reports whether
-// name matches pattern. Pattern is a limited glob
-// pattern in which '...' means 'any string' and there
-// is no other special syntax.
-// Unfortunately, there are two special cases. Quoting "go help packages":
-//
-// First, /... at the end of the pattern can match an empty string,
-// so that net/... matches both net and packages in its subdirectories, like net/http.
-// Second, any slash-separated pattern element containing a wildcard never
-// participates in a match of the "vendor" element in the path of a vendored
-// package, so that ./... does not match packages in subdirectories of
-// ./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do.
-// Note, however, that a directory named vendor that itself contains code
-// is not a vendored package: cmd/vendor would be a command named vendor,
-// and the pattern cmd/... matches it.
-func matchPattern(pattern string) func(name string) bool {
- // Convert pattern to regular expression.
- // The strategy for the trailing /... is to nest it in an explicit ? expression.
- // The strategy for the vendor exclusion is to change the unmatchable
- // vendor strings to a disallowed code point (vendorChar) and to use
- // "(anything but that codepoint)*" as the implementation of the ... wildcard.
- // This is a bit complicated but the obvious alternative,
- // namely a hand-written search like in most shell glob matchers,
- // is too easy to make accidentally exponential.
- // Using package regexp guarantees linear-time matching.
-
- const vendorChar = "\x00"
-
- if strings.Contains(pattern, vendorChar) {
- return func(name string) bool { return false }
- }
-
- re := regexp.QuoteMeta(pattern)
- re = replaceVendor(re, vendorChar)
- switch {
- case strings.HasSuffix(re, `/`+vendorChar+`/\.\.\.`):
- re = strings.TrimSuffix(re, `/`+vendorChar+`/\.\.\.`) + `(/vendor|/` + vendorChar + `/\.\.\.)`
- case re == vendorChar+`/\.\.\.`:
- re = `(/vendor|/` + vendorChar + `/\.\.\.)`
- case strings.HasSuffix(re, `/\.\.\.`):
- re = strings.TrimSuffix(re, `/\.\.\.`) + `(/\.\.\.)?`
- }
- re = strings.ReplaceAll(re, `\.\.\.`, `[^`+vendorChar+`]*`)
-
- reg := regexp.MustCompile(`^` + re + `$`)
-
- return func(name string) bool {
- if strings.Contains(name, vendorChar) {
- return false
- }
- return reg.MatchString(replaceVendor(name, vendorChar))
- }
-}
-
-// replaceVendor returns the result of replacing
-// non-trailing vendor path elements in x with repl.
-func replaceVendor(x, repl string) string {
- if !strings.Contains(x, "vendor") {
- return x
- }
- elem := strings.Split(x, "/")
- for i := 0; i < len(elem)-1; i++ {
- if elem[i] == "vendor" {
- elem[i] = repl
- }
- }
- return strings.Join(elem, "/")
-}
diff --git a/vendor/golang.org/x/tools/go/packages/packages.go b/vendor/golang.org/x/tools/go/packages/packages.go
index 124a6fe1..f33b0afc 100644
--- a/vendor/golang.org/x/tools/go/packages/packages.go
+++ b/vendor/golang.org/x/tools/go/packages/packages.go
@@ -16,7 +16,6 @@ import (
"go/token"
"go/types"
"io"
- "io/ioutil"
"log"
"os"
"path/filepath"
@@ -28,8 +27,8 @@ import (
"golang.org/x/tools/go/gcexportdata"
"golang.org/x/tools/internal/gocommand"
"golang.org/x/tools/internal/packagesinternal"
- "golang.org/x/tools/internal/typeparams"
"golang.org/x/tools/internal/typesinternal"
+ "golang.org/x/tools/internal/versions"
)
// A LoadMode controls the amount of detail to return when loading.
@@ -207,43 +206,6 @@ type Config struct {
Overlay map[string][]byte
}
-// driver is the type for functions that query the build system for the
-// packages named by the patterns.
-type driver func(cfg *Config, patterns ...string) (*driverResponse, error)
-
-// driverResponse contains the results for a driver query.
-type driverResponse struct {
- // NotHandled is returned if the request can't be handled by the current
- // driver. If an external driver returns a response with NotHandled, the
- // rest of the driverResponse is ignored, and go/packages will fallback
- // to the next driver. If go/packages is extended in the future to support
- // lists of multiple drivers, go/packages will fall back to the next driver.
- NotHandled bool
-
- // Compiler and Arch are the arguments pass of types.SizesFor
- // to get a types.Sizes to use when type checking.
- Compiler string
- Arch string
-
- // Roots is the set of package IDs that make up the root packages.
- // We have to encode this separately because when we encode a single package
- // we cannot know if it is one of the roots as that requires knowledge of the
- // graph it is part of.
- Roots []string `json:",omitempty"`
-
- // Packages is the full set of packages in the graph.
- // The packages are not connected into a graph.
- // The Imports if populated will be stubs that only have their ID set.
- // Imports will be connected and then type and syntax information added in a
- // later pass (see refine).
- Packages []*Package
-
- // GoVersion is the minor version number used by the driver
- // (e.g. the go command on the PATH) when selecting .go files.
- // Zero means unknown.
- GoVersion int
-}
-
// Load loads and returns the Go packages named by the given patterns.
//
// Config specifies loading options;
@@ -259,31 +221,55 @@ type driverResponse struct {
// proceeding with further analysis. The PrintErrors function is
// provided for convenient display of all errors.
func Load(cfg *Config, patterns ...string) ([]*Package, error) {
- l := newLoader(cfg)
- response, err := defaultDriver(&l.Config, patterns...)
+ ld := newLoader(cfg)
+ response, external, err := defaultDriver(&ld.Config, patterns...)
if err != nil {
return nil, err
}
- l.sizes = types.SizesFor(response.Compiler, response.Arch)
- return l.refine(response)
+
+ ld.sizes = types.SizesFor(response.Compiler, response.Arch)
+ if ld.sizes == nil && ld.Config.Mode&(NeedTypes|NeedTypesSizes|NeedTypesInfo) != 0 {
+ // Type size information is needed but unavailable.
+ if external {
+ // An external driver may fail to populate the Compiler/GOARCH fields,
+ // especially since they are relatively new (see #63700).
+ // Provide a sensible fallback in this case.
+ ld.sizes = types.SizesFor("gc", runtime.GOARCH)
+ if ld.sizes == nil { // gccgo-only arch
+ ld.sizes = types.SizesFor("gc", "amd64")
+ }
+ } else {
+ // Go list should never fail to deliver accurate size information.
+ // Reject the whole Load since the error is the same for every package.
+ return nil, fmt.Errorf("can't determine type sizes for compiler %q on GOARCH %q",
+ response.Compiler, response.Arch)
+ }
+ }
+
+ return ld.refine(response)
}
// defaultDriver is a driver that implements go/packages' fallback behavior.
// It will try to request to an external driver, if one exists. If there's
// no external driver, or the driver returns a response with NotHandled set,
// defaultDriver will fall back to the go list driver.
-func defaultDriver(cfg *Config, patterns ...string) (*driverResponse, error) {
- driver := findExternalDriver(cfg)
- if driver == nil {
- driver = goListDriver
+// The boolean result indicates that an external driver handled the request.
+func defaultDriver(cfg *Config, patterns ...string) (*DriverResponse, bool, error) {
+ if driver := findExternalDriver(cfg); driver != nil {
+ response, err := driver(cfg, patterns...)
+ if err != nil {
+ return nil, false, err
+ } else if !response.NotHandled {
+ return response, true, nil
+ }
+ // (fall through)
}
- response, err := driver(cfg, patterns...)
+
+ response, err := goListDriver(cfg, patterns...)
if err != nil {
- return response, err
- } else if response.NotHandled {
- return goListDriver(cfg, patterns...)
+ return nil, false, err
}
- return response, nil
+ return response, false, nil
}
// A Package describes a loaded Go package.
@@ -412,12 +398,6 @@ func init() {
packagesinternal.GetDepsErrors = func(p interface{}) []*packagesinternal.PackageError {
return p.(*Package).depsErrors
}
- packagesinternal.GetGoCmdRunner = func(config interface{}) *gocommand.Runner {
- return config.(*Config).gocmdRunner
- }
- packagesinternal.SetGoCmdRunner = func(config interface{}, runner *gocommand.Runner) {
- config.(*Config).gocmdRunner = runner
- }
packagesinternal.SetModFile = func(config interface{}, value string) {
config.(*Config).modFile = value
}
@@ -554,7 +534,7 @@ type loaderPackage struct {
type loader struct {
pkgs map[string]*loaderPackage
Config
- sizes types.Sizes
+ sizes types.Sizes // non-nil if needed by mode
parseCache map[string]*parseValue
parseCacheMu sync.Mutex
exportMu sync.Mutex // enforces mutual exclusion of exportdata operations
@@ -634,7 +614,7 @@ func newLoader(cfg *Config) *loader {
// refine connects the supplied packages into a graph and then adds type
// and syntax information as requested by the LoadMode.
-func (ld *loader) refine(response *driverResponse) ([]*Package, error) {
+func (ld *loader) refine(response *DriverResponse) ([]*Package, error) {
roots := response.Roots
rootMap := make(map[string]int, len(roots))
for i, root := range roots {
@@ -679,39 +659,38 @@ func (ld *loader) refine(response *driverResponse) ([]*Package, error) {
}
}
- // Materialize the import graph.
-
- const (
- white = 0 // new
- grey = 1 // in progress
- black = 2 // complete
- )
-
- // visit traverses the import graph, depth-first,
- // and materializes the graph as Packages.Imports.
- //
- // Valid imports are saved in the Packages.Import map.
- // Invalid imports (cycles and missing nodes) are saved in the importErrors map.
- // Thus, even in the presence of both kinds of errors, the Import graph remains a DAG.
- //
- // visit returns whether the package needs src or has a transitive
- // dependency on a package that does. These are the only packages
- // for which we load source code.
- var stack []*loaderPackage
- var visit func(lpkg *loaderPackage) bool
- var srcPkgs []*loaderPackage
- visit = func(lpkg *loaderPackage) bool {
- switch lpkg.color {
- case black:
- return lpkg.needsrc
- case grey:
- panic("internal error: grey node")
- }
- lpkg.color = grey
- stack = append(stack, lpkg) // push
- stubs := lpkg.Imports // the structure form has only stubs with the ID in the Imports
- // If NeedImports isn't set, the imports fields will all be zeroed out.
- if ld.Mode&NeedImports != 0 {
+ if ld.Mode&NeedImports != 0 {
+ // Materialize the import graph.
+
+ const (
+ white = 0 // new
+ grey = 1 // in progress
+ black = 2 // complete
+ )
+
+ // visit traverses the import graph, depth-first,
+ // and materializes the graph as Packages.Imports.
+ //
+ // Valid imports are saved in the Packages.Import map.
+ // Invalid imports (cycles and missing nodes) are saved in the importErrors map.
+ // Thus, even in the presence of both kinds of errors,
+ // the Import graph remains a DAG.
+ //
+ // visit returns whether the package needs src or has a transitive
+ // dependency on a package that does. These are the only packages
+ // for which we load source code.
+ var stack []*loaderPackage
+ var visit func(lpkg *loaderPackage) bool
+ visit = func(lpkg *loaderPackage) bool {
+ switch lpkg.color {
+ case black:
+ return lpkg.needsrc
+ case grey:
+ panic("internal error: grey node")
+ }
+ lpkg.color = grey
+ stack = append(stack, lpkg) // push
+ stubs := lpkg.Imports // the structure form has only stubs with the ID in the Imports
lpkg.Imports = make(map[string]*Package, len(stubs))
for importPath, ipkg := range stubs {
var importErr error
@@ -735,40 +714,39 @@ func (ld *loader) refine(response *driverResponse) ([]*Package, error) {
}
lpkg.Imports[importPath] = imp.Package
}
- }
- if lpkg.needsrc {
- srcPkgs = append(srcPkgs, lpkg)
- }
- if ld.Mode&NeedTypesSizes != 0 {
- lpkg.TypesSizes = ld.sizes
- }
- stack = stack[:len(stack)-1] // pop
- lpkg.color = black
- return lpkg.needsrc
- }
+ // Complete type information is required for the
+ // immediate dependencies of each source package.
+ if lpkg.needsrc && ld.Mode&NeedTypes != 0 {
+ for _, ipkg := range lpkg.Imports {
+ ld.pkgs[ipkg.ID].needtypes = true
+ }
+ }
- if ld.Mode&NeedImports == 0 {
- // We do this to drop the stub import packages that we are not even going to try to resolve.
- for _, lpkg := range initial {
- lpkg.Imports = nil
+ // NeedTypeSizes causes TypeSizes to be set even
+ // on packages for which types aren't needed.
+ if ld.Mode&NeedTypesSizes != 0 {
+ lpkg.TypesSizes = ld.sizes
+ }
+ stack = stack[:len(stack)-1] // pop
+ lpkg.color = black
+
+ return lpkg.needsrc
}
- } else {
+
// For each initial package, create its import DAG.
for _, lpkg := range initial {
visit(lpkg)
}
- }
- if ld.Mode&NeedImports != 0 && ld.Mode&NeedTypes != 0 {
- for _, lpkg := range srcPkgs {
- // Complete type information is required for the
- // immediate dependencies of each source package.
- for _, ipkg := range lpkg.Imports {
- imp := ld.pkgs[ipkg.ID]
- imp.needtypes = true
- }
+
+ } else {
+ // !NeedImports: drop the stub (ID-only) import packages
+ // that we are not even going to try to resolve.
+ for _, lpkg := range initial {
+ lpkg.Imports = nil
}
}
+
// Load type data and syntax if needed, starting at
// the initial packages (roots of the import DAG).
if ld.Mode&NeedTypes != 0 || ld.Mode&NeedSyntax != 0 {
@@ -1002,10 +980,11 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
Defs: make(map[*ast.Ident]types.Object),
Uses: make(map[*ast.Ident]types.Object),
Implicits: make(map[ast.Node]types.Object),
+ Instances: make(map[*ast.Ident]types.Instance),
Scopes: make(map[ast.Node]*types.Scope),
Selections: make(map[*ast.SelectorExpr]*types.Selection),
}
- typeparams.InitInstanceInfo(lpkg.TypesInfo)
+ versions.InitFileVersions(lpkg.TypesInfo)
lpkg.TypesSizes = ld.sizes
importer := importerFunc(func(path string) (*types.Package, error) {
@@ -1043,7 +1022,7 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
IgnoreFuncBodies: ld.Mode&NeedDeps == 0 && !lpkg.initial,
Error: appendError,
- Sizes: ld.sizes,
+ Sizes: ld.sizes, // may be nil
}
if lpkg.Module != nil && lpkg.Module.GoVersion != "" {
typesinternal.SetGoVersion(tc, "go"+lpkg.Module.GoVersion)
@@ -1127,7 +1106,7 @@ func (ld *loader) parseFile(filename string) (*ast.File, error) {
var err error
if src == nil {
ioLimit <- true // wait
- src, err = ioutil.ReadFile(filename)
+ src, err = os.ReadFile(filename)
<-ioLimit // signal
}
if err != nil {
diff --git a/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go b/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go
index fa5834ba..11d5c8c3 100644
--- a/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go
+++ b/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go
@@ -26,13 +26,10 @@ package objectpath
import (
"fmt"
"go/types"
- "sort"
"strconv"
"strings"
- _ "unsafe"
"golang.org/x/tools/internal/typeparams"
- "golang.org/x/tools/internal/typesinternal"
)
// A Path is an opaque name that identifies a types.Object
@@ -123,20 +120,7 @@ func For(obj types.Object) (Path, error) {
// An Encoder amortizes the cost of encoding the paths of multiple objects.
// The zero value of an Encoder is ready to use.
type Encoder struct {
- scopeMemo map[*types.Scope][]types.Object // memoization of scopeObjects
- namedMethodsMemo map[*types.Named][]*types.Func // memoization of namedMethods()
- skipMethodSorting bool
-}
-
-// Expose back doors so that gopls can avoid method sorting, which can dominate
-// analysis on certain repositories.
-//
-// TODO(golang/go#61443): remove this.
-func init() {
- typesinternal.SkipEncoderMethodSorting = func(enc interface{}) {
- enc.(*Encoder).skipMethodSorting = true
- }
- typesinternal.ObjectpathObject = object
+ scopeMemo map[*types.Scope][]types.Object // memoization of scopeObjects
}
// For returns the path to an object relative to its package,
@@ -239,7 +223,7 @@ func (enc *Encoder) For(obj types.Object) (Path, error) {
// Reject obviously non-viable cases.
switch obj := obj.(type) {
case *types.TypeName:
- if _, ok := obj.Type().(*typeparams.TypeParam); !ok {
+ if _, ok := obj.Type().(*types.TypeParam); !ok {
// With the exception of type parameters, only package-level type names
// have a path.
return "", fmt.Errorf("no path for %v", obj)
@@ -299,7 +283,7 @@ func (enc *Encoder) For(obj types.Object) (Path, error) {
}
} else {
if named, _ := T.(*types.Named); named != nil {
- if r := findTypeParam(obj, typeparams.ForNamed(named), path, nil); r != nil {
+ if r := findTypeParam(obj, named.TypeParams(), path, nil); r != nil {
// generic named type
return Path(r), nil
}
@@ -328,31 +312,18 @@ func (enc *Encoder) For(obj types.Object) (Path, error) {
// Inspect declared methods of defined types.
if T, ok := o.Type().(*types.Named); ok {
path = append(path, opType)
- if !enc.skipMethodSorting {
- // Note that method index here is always with respect
- // to canonical ordering of methods, regardless of how
- // they appear in the underlying type.
- for i, m := range enc.namedMethods(T) {
- path2 := appendOpArg(path, opMethod, i)
- if m == obj {
- return Path(path2), nil // found declared method
- }
- if r := find(obj, m.Type(), append(path2, opType), nil); r != nil {
- return Path(r), nil
- }
+ // The method index here is always with respect
+ // to the underlying go/types data structures,
+ // which ultimately derives from source order
+ // and must be preserved by export data.
+ for i := 0; i < T.NumMethods(); i++ {
+ m := T.Method(i)
+ path2 := appendOpArg(path, opMethod, i)
+ if m == obj {
+ return Path(path2), nil // found declared method
}
- } else {
- // This branch must match the logic in the branch above, using go/types
- // APIs without sorting.
- for i := 0; i < T.NumMethods(); i++ {
- m := T.Method(i)
- path2 := appendOpArg(path, opMethod, i)
- if m == obj {
- return Path(path2), nil // found declared method
- }
- if r := find(obj, m.Type(), append(path2, opType), nil); r != nil {
- return Path(r), nil
- }
+ if r := find(obj, m.Type(), append(path2, opType), nil); r != nil {
+ return Path(r), nil
}
}
}
@@ -448,22 +419,13 @@ func (enc *Encoder) concreteMethod(meth *types.Func) (Path, bool) {
path = append(path, name...)
path = append(path, opType)
- if !enc.skipMethodSorting {
- for i, m := range enc.namedMethods(named) {
- if m == meth {
- path = appendOpArg(path, opMethod, i)
- return Path(path), true
- }
- }
- } else {
- // This branch must match the logic of the branch above, using go/types
- // APIs without sorting.
- for i := 0; i < named.NumMethods(); i++ {
- m := named.Method(i)
- if m == meth {
- path = appendOpArg(path, opMethod, i)
- return Path(path), true
- }
+ // Method indices are w.r.t. the go/types data structures,
+ // ultimately deriving from source order,
+ // which is preserved by export data.
+ for i := 0; i < named.NumMethods(); i++ {
+ if named.Method(i) == meth {
+ path = appendOpArg(path, opMethod, i)
+ return Path(path), true
}
}
@@ -500,7 +462,7 @@ func find(obj types.Object, T types.Type, path []byte, seen map[*types.TypeName]
}
return find(obj, T.Elem(), append(path, opElem), seen)
case *types.Signature:
- if r := findTypeParam(obj, typeparams.ForSignature(T), path, seen); r != nil {
+ if r := findTypeParam(obj, T.TypeParams(), path, seen); r != nil {
return r
}
if r := find(obj, T.Params(), append(path, opParams), seen); r != nil {
@@ -543,7 +505,7 @@ func find(obj types.Object, T types.Type, path []byte, seen map[*types.TypeName]
}
}
return nil
- case *typeparams.TypeParam:
+ case *types.TypeParam:
name := T.Obj()
if name == obj {
return append(path, opObj)
@@ -563,7 +525,7 @@ func find(obj types.Object, T types.Type, path []byte, seen map[*types.TypeName]
panic(T)
}
-func findTypeParam(obj types.Object, list *typeparams.TypeParamList, path []byte, seen map[*types.TypeName]bool) []byte {
+func findTypeParam(obj types.Object, list *types.TypeParamList, path []byte, seen map[*types.TypeName]bool) []byte {
for i := 0; i < list.Len(); i++ {
tparam := list.At(i)
path2 := appendOpArg(path, opTypeParam, i)
@@ -576,12 +538,7 @@ func findTypeParam(obj types.Object, list *typeparams.TypeParamList, path []byte
// Object returns the object denoted by path p within the package pkg.
func Object(pkg *types.Package, p Path) (types.Object, error) {
- return object(pkg, string(p), false)
-}
-
-// Note: the skipMethodSorting parameter must match the value of
-// Encoder.skipMethodSorting used during encoding.
-func object(pkg *types.Package, pathstr string, skipMethodSorting bool) (types.Object, error) {
+ pathstr := string(p)
if pathstr == "" {
return nil, fmt.Errorf("empty path")
}
@@ -605,7 +562,7 @@ func object(pkg *types.Package, pathstr string, skipMethodSorting bool) (types.O
}
// abstraction of *types.{Named,Signature}
type hasTypeParams interface {
- TypeParams() *typeparams.TypeParamList
+ TypeParams() *types.TypeParamList
}
// abstraction of *types.{Named,TypeParam}
type hasObj interface {
@@ -707,7 +664,7 @@ func object(pkg *types.Package, pathstr string, skipMethodSorting bool) (types.O
t = tparams.At(index)
case opConstraint:
- tparam, ok := t.(*typeparams.TypeParam)
+ tparam, ok := t.(*types.TypeParam)
if !ok {
return nil, fmt.Errorf("cannot apply %q to %s (got %T, want type parameter)", code, t, t)
}
@@ -747,12 +704,7 @@ func object(pkg *types.Package, pathstr string, skipMethodSorting bool) (types.O
if index >= t.NumMethods() {
return nil, fmt.Errorf("method index %d out of range [0-%d)", index, t.NumMethods())
}
- if skipMethodSorting {
- obj = t.Method(index)
- } else {
- methods := namedMethods(t) // (unmemoized)
- obj = methods[index] // Id-ordered
- }
+ obj = t.Method(index)
default:
return nil, fmt.Errorf("cannot apply %q to %s (got %T, want interface or named)", code, t, t)
@@ -779,33 +731,6 @@ func object(pkg *types.Package, pathstr string, skipMethodSorting bool) (types.O
return obj, nil // success
}
-// namedMethods returns the methods of a Named type in ascending Id order.
-func namedMethods(named *types.Named) []*types.Func {
- methods := make([]*types.Func, named.NumMethods())
- for i := range methods {
- methods[i] = named.Method(i)
- }
- sort.Slice(methods, func(i, j int) bool {
- return methods[i].Id() < methods[j].Id()
- })
- return methods
-}
-
-// namedMethods is a memoization of the namedMethods function. Callers must not modify the result.
-func (enc *Encoder) namedMethods(named *types.Named) []*types.Func {
- m := enc.namedMethodsMemo
- if m == nil {
- m = make(map[*types.Named][]*types.Func)
- enc.namedMethodsMemo = m
- }
- methods, ok := m[named]
- if !ok {
- methods = namedMethods(named) // allocates and sorts
- m[named] = methods
- }
- return methods
-}
-
// scopeObjects is a memoization of scope objects.
// Callers must not modify the result.
func (enc *Encoder) scopeObjects(scope *types.Scope) []types.Object {
diff --git a/vendor/golang.org/x/tools/internal/event/keys/util.go b/vendor/golang.org/x/tools/internal/event/keys/util.go
new file mode 100644
index 00000000..c0e8e731
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/event/keys/util.go
@@ -0,0 +1,21 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package keys
+
+import (
+ "sort"
+ "strings"
+)
+
+// Join returns a canonical join of the keys in S:
+// a sorted comma-separated string list.
+func Join[S ~[]T, T ~string](s S) string {
+ strs := make([]string, 0, len(s))
+ for _, v := range s {
+ strs = append(strs, string(v))
+ }
+ sort.Strings(strs)
+ return strings.Join(strs, ",")
+}
diff --git a/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go b/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go
index b1223713..2d078ccb 100644
--- a/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go
+++ b/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go
@@ -29,7 +29,6 @@ import (
"go/token"
"go/types"
"io"
- "io/ioutil"
"os"
"os/exec"
"path/filepath"
@@ -221,7 +220,7 @@ func Import(packages map[string]*types.Package, path, srcDir string, lookup func
switch hdr {
case "$$B\n":
var data []byte
- data, err = ioutil.ReadAll(buf)
+ data, err = io.ReadAll(buf)
if err != nil {
break
}
diff --git a/vendor/golang.org/x/tools/internal/gcimporter/iexport.go b/vendor/golang.org/x/tools/internal/gcimporter/iexport.go
index 6103dd71..2ee8c701 100644
--- a/vendor/golang.org/x/tools/internal/gcimporter/iexport.go
+++ b/vendor/golang.org/x/tools/internal/gcimporter/iexport.go
@@ -24,7 +24,6 @@ import (
"golang.org/x/tools/go/types/objectpath"
"golang.org/x/tools/internal/tokeninternal"
- "golang.org/x/tools/internal/typeparams"
)
// IExportShallow encodes "shallow" export data for the specified package.
@@ -481,7 +480,7 @@ func (p *iexporter) doDecl(obj types.Object) {
}
// Function.
- if typeparams.ForSignature(sig).Len() == 0 {
+ if sig.TypeParams().Len() == 0 {
w.tag('F')
} else {
w.tag('G')
@@ -494,7 +493,7 @@ func (p *iexporter) doDecl(obj types.Object) {
//
// While importing the type parameters, tparamList computes and records
// their export name, so that it can be later used when writing the index.
- if tparams := typeparams.ForSignature(sig); tparams.Len() > 0 {
+ if tparams := sig.TypeParams(); tparams.Len() > 0 {
w.tparamList(obj.Name(), tparams, obj.Pkg())
}
w.signature(sig)
@@ -507,14 +506,14 @@ func (p *iexporter) doDecl(obj types.Object) {
case *types.TypeName:
t := obj.Type()
- if tparam, ok := t.(*typeparams.TypeParam); ok {
+ if tparam, ok := t.(*types.TypeParam); ok {
w.tag('P')
w.pos(obj.Pos())
constraint := tparam.Constraint()
if p.version >= iexportVersionGo1_18 {
implicit := false
if iface, _ := constraint.(*types.Interface); iface != nil {
- implicit = typeparams.IsImplicit(iface)
+ implicit = iface.IsImplicit()
}
w.bool(implicit)
}
@@ -535,17 +534,17 @@ func (p *iexporter) doDecl(obj types.Object) {
panic(internalErrorf("%s is not a defined type", t))
}
- if typeparams.ForNamed(named).Len() == 0 {
+ if named.TypeParams().Len() == 0 {
w.tag('T')
} else {
w.tag('U')
}
w.pos(obj.Pos())
- if typeparams.ForNamed(named).Len() > 0 {
+ if named.TypeParams().Len() > 0 {
// While importing the type parameters, tparamList computes and records
// their export name, so that it can be later used when writing the index.
- w.tparamList(obj.Name(), typeparams.ForNamed(named), obj.Pkg())
+ w.tparamList(obj.Name(), named.TypeParams(), obj.Pkg())
}
underlying := obj.Type().Underlying()
@@ -565,7 +564,7 @@ func (p *iexporter) doDecl(obj types.Object) {
// Receiver type parameters are type arguments of the receiver type, so
// their name must be qualified before exporting recv.
- if rparams := typeparams.RecvTypeParams(sig); rparams.Len() > 0 {
+ if rparams := sig.RecvTypeParams(); rparams.Len() > 0 {
prefix := obj.Name() + "." + m.Name()
for i := 0; i < rparams.Len(); i++ {
rparam := rparams.At(i)
@@ -740,19 +739,19 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) {
}
switch t := t.(type) {
case *types.Named:
- if targs := typeparams.NamedTypeArgs(t); targs.Len() > 0 {
+ if targs := t.TypeArgs(); targs.Len() > 0 {
w.startType(instanceType)
// TODO(rfindley): investigate if this position is correct, and if it
// matters.
w.pos(t.Obj().Pos())
w.typeList(targs, pkg)
- w.typ(typeparams.NamedTypeOrigin(t), pkg)
+ w.typ(t.Origin(), pkg)
return
}
w.startType(definedType)
w.qualifiedType(t.Obj())
- case *typeparams.TypeParam:
+ case *types.TypeParam:
w.startType(typeParamType)
w.qualifiedType(t.Obj())
@@ -868,7 +867,7 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) {
w.signature(sig)
}
- case *typeparams.Union:
+ case *types.Union:
w.startType(unionType)
nt := t.Len()
w.uint64(uint64(nt))
@@ -948,14 +947,14 @@ func (w *exportWriter) signature(sig *types.Signature) {
}
}
-func (w *exportWriter) typeList(ts *typeparams.TypeList, pkg *types.Package) {
+func (w *exportWriter) typeList(ts *types.TypeList, pkg *types.Package) {
w.uint64(uint64(ts.Len()))
for i := 0; i < ts.Len(); i++ {
w.typ(ts.At(i), pkg)
}
}
-func (w *exportWriter) tparamList(prefix string, list *typeparams.TypeParamList, pkg *types.Package) {
+func (w *exportWriter) tparamList(prefix string, list *types.TypeParamList, pkg *types.Package) {
ll := uint64(list.Len())
w.uint64(ll)
for i := 0; i < list.Len(); i++ {
@@ -973,7 +972,7 @@ const blankMarker = "$"
// differs from its actual object name: it is prefixed with a qualifier, and
// blank type parameter names are disambiguated by their index in the type
// parameter list.
-func tparamExportName(prefix string, tparam *typeparams.TypeParam) string {
+func tparamExportName(prefix string, tparam *types.TypeParam) string {
assert(prefix != "")
name := tparam.Obj().Name()
if name == "_" {
diff --git a/vendor/golang.org/x/tools/internal/gcimporter/iimport.go b/vendor/golang.org/x/tools/internal/gcimporter/iimport.go
index 8e64cf64..9fffa9ad 100644
--- a/vendor/golang.org/x/tools/internal/gcimporter/iimport.go
+++ b/vendor/golang.org/x/tools/internal/gcimporter/iimport.go
@@ -22,7 +22,6 @@ import (
"strings"
"golang.org/x/tools/go/types/objectpath"
- "golang.org/x/tools/internal/typeparams"
)
type intReader struct {
@@ -225,6 +224,7 @@ func iimportCommon(fset *token.FileSet, getPackages GetPackagesFunc, data []byte
// Gather the relevant packages from the manifest.
items := make([]GetPackagesItem, r.uint64())
+ uniquePkgPaths := make(map[string]bool)
for i := range items {
pkgPathOff := r.uint64()
pkgPath := p.stringAt(pkgPathOff)
@@ -249,6 +249,12 @@ func iimportCommon(fset *token.FileSet, getPackages GetPackagesFunc, data []byte
}
items[i].nameIndex = nameIndex
+
+ uniquePkgPaths[pkgPath] = true
+ }
+ // Debugging #63822; hypothesis: there are duplicate PkgPaths.
+ if len(uniquePkgPaths) != len(items) {
+ reportf("found duplicate PkgPaths while reading export data manifest: %v", items)
}
// Request packages all at once from the client,
@@ -321,7 +327,7 @@ func iimportCommon(fset *token.FileSet, getPackages GetPackagesFunc, data []byte
// Therefore, we defer calling SetConstraint there, and call it here instead
// after all types are complete.
for _, d := range p.later {
- typeparams.SetTypeParamConstraint(d.t, d.constraint)
+ d.t.SetConstraint(d.constraint)
}
for _, typ := range p.interfaceList {
@@ -339,7 +345,7 @@ func iimportCommon(fset *token.FileSet, getPackages GetPackagesFunc, data []byte
}
type setConstraintArgs struct {
- t *typeparams.TypeParam
+ t *types.TypeParam
constraint types.Type
}
@@ -549,7 +555,7 @@ func (r *importReader) obj(name string) {
r.declare(types.NewConst(pos, r.currPkg, name, typ, val))
case 'F', 'G':
- var tparams []*typeparams.TypeParam
+ var tparams []*types.TypeParam
if tag == 'G' {
tparams = r.tparamList()
}
@@ -566,7 +572,7 @@ func (r *importReader) obj(name string) {
r.declare(obj)
if tag == 'U' {
tparams := r.tparamList()
- typeparams.SetForNamed(named, tparams)
+ named.SetTypeParams(tparams)
}
underlying := r.p.typAt(r.uint64(), named).Underlying()
@@ -583,12 +589,12 @@ func (r *importReader) obj(name string) {
// typeparams being used in the method sig/body).
base := baseType(recv.Type())
assert(base != nil)
- targs := typeparams.NamedTypeArgs(base)
- var rparams []*typeparams.TypeParam
+ targs := base.TypeArgs()
+ var rparams []*types.TypeParam
if targs.Len() > 0 {
- rparams = make([]*typeparams.TypeParam, targs.Len())
+ rparams = make([]*types.TypeParam, targs.Len())
for i := range rparams {
- rparams[i] = targs.At(i).(*typeparams.TypeParam)
+ rparams[i] = targs.At(i).(*types.TypeParam)
}
}
msig := r.signature(recv, rparams, nil)
@@ -606,7 +612,7 @@ func (r *importReader) obj(name string) {
}
name0 := tparamName(name)
tn := types.NewTypeName(pos, r.currPkg, name0, nil)
- t := typeparams.NewTypeParam(tn, nil)
+ t := types.NewTypeParam(tn, nil)
// To handle recursive references to the typeparam within its
// bound, save the partial type in tparamIndex before reading the bounds.
@@ -622,7 +628,7 @@ func (r *importReader) obj(name string) {
if iface == nil {
errorf("non-interface constraint marked implicit")
}
- typeparams.MarkImplicit(iface)
+ iface.MarkImplicit()
}
// The constraint type may not be complete, if we
// are in the middle of a type recursion involving type
@@ -966,7 +972,7 @@ func (r *importReader) doType(base *types.Named) (res types.Type) {
// The imported instantiated type doesn't include any methods, so
// we must always use the methods of the base (orig) type.
// TODO provide a non-nil *Environment
- t, _ := typeparams.Instantiate(nil, baseType, targs, false)
+ t, _ := types.Instantiate(nil, baseType, targs, false)
// Workaround for golang/go#61561. See the doc for instanceList for details.
r.p.instanceList = append(r.p.instanceList, t)
@@ -976,11 +982,11 @@ func (r *importReader) doType(base *types.Named) (res types.Type) {
if r.p.version < iexportVersionGenerics {
errorf("unexpected instantiation type")
}
- terms := make([]*typeparams.Term, r.uint64())
+ terms := make([]*types.Term, r.uint64())
for i := range terms {
- terms[i] = typeparams.NewTerm(r.bool(), r.typ())
+ terms[i] = types.NewTerm(r.bool(), r.typ())
}
- return typeparams.NewUnion(terms)
+ return types.NewUnion(terms)
}
}
@@ -1008,23 +1014,23 @@ func (r *importReader) objectPathObject() types.Object {
return obj
}
-func (r *importReader) signature(recv *types.Var, rparams []*typeparams.TypeParam, tparams []*typeparams.TypeParam) *types.Signature {
+func (r *importReader) signature(recv *types.Var, rparams []*types.TypeParam, tparams []*types.TypeParam) *types.Signature {
params := r.paramList()
results := r.paramList()
variadic := params.Len() > 0 && r.bool()
- return typeparams.NewSignatureType(recv, rparams, tparams, params, results, variadic)
+ return types.NewSignatureType(recv, rparams, tparams, params, results, variadic)
}
-func (r *importReader) tparamList() []*typeparams.TypeParam {
+func (r *importReader) tparamList() []*types.TypeParam {
n := r.uint64()
if n == 0 {
return nil
}
- xs := make([]*typeparams.TypeParam, n)
+ xs := make([]*types.TypeParam, n)
for i := range xs {
// Note: the standard library importer is tolerant of nil types here,
// though would panic in SetTypeParams.
- xs[i] = r.typ().(*typeparams.TypeParam)
+ xs[i] = r.typ().(*types.TypeParam)
}
return xs
}
diff --git a/vendor/golang.org/x/tools/internal/gocommand/invoke.go b/vendor/golang.org/x/tools/internal/gocommand/invoke.go
index 53cf66da..55312522 100644
--- a/vendor/golang.org/x/tools/internal/gocommand/invoke.go
+++ b/vendor/golang.org/x/tools/internal/gocommand/invoke.go
@@ -13,6 +13,7 @@ import (
"io"
"log"
"os"
+ "os/exec"
"reflect"
"regexp"
"runtime"
@@ -21,8 +22,6 @@ import (
"sync"
"time"
- exec "golang.org/x/sys/execabs"
-
"golang.org/x/tools/internal/event"
"golang.org/x/tools/internal/event/keys"
"golang.org/x/tools/internal/event/label"
@@ -85,6 +84,7 @@ func (runner *Runner) RunPiped(ctx context.Context, inv Invocation, stdout, stde
// RunRaw runs the invocation, serializing requests only if they fight over
// go.mod changes.
+// Postcondition: both error results have same nilness.
func (runner *Runner) RunRaw(ctx context.Context, inv Invocation) (*bytes.Buffer, *bytes.Buffer, error, error) {
ctx, done := event.Start(ctx, "gocommand.Runner.RunRaw", invLabels(inv)...)
defer done()
@@ -95,23 +95,24 @@ func (runner *Runner) RunRaw(ctx context.Context, inv Invocation) (*bytes.Buffer
stdout, stderr, friendlyErr, err := runner.runConcurrent(ctx, inv)
// If we encounter a load concurrency error, we need to retry serially.
- if friendlyErr == nil || !modConcurrencyError.MatchString(friendlyErr.Error()) {
- return stdout, stderr, friendlyErr, err
+ if friendlyErr != nil && modConcurrencyError.MatchString(friendlyErr.Error()) {
+ event.Error(ctx, "Load concurrency error, will retry serially", err)
+
+ // Run serially by calling runPiped.
+ stdout.Reset()
+ stderr.Reset()
+ friendlyErr, err = runner.runPiped(ctx, inv, stdout, stderr)
}
- event.Error(ctx, "Load concurrency error, will retry serially", err)
- // Run serially by calling runPiped.
- stdout.Reset()
- stderr.Reset()
- friendlyErr, err = runner.runPiped(ctx, inv, stdout, stderr)
return stdout, stderr, friendlyErr, err
}
+// Postcondition: both error results have same nilness.
func (runner *Runner) runConcurrent(ctx context.Context, inv Invocation) (*bytes.Buffer, *bytes.Buffer, error, error) {
// Wait for 1 worker to become available.
select {
case <-ctx.Done():
- return nil, nil, nil, ctx.Err()
+ return nil, nil, ctx.Err(), ctx.Err()
case runner.inFlight <- struct{}{}:
defer func() { <-runner.inFlight }()
}
@@ -121,6 +122,7 @@ func (runner *Runner) runConcurrent(ctx context.Context, inv Invocation) (*bytes
return stdout, stderr, friendlyErr, err
}
+// Postcondition: both error results have same nilness.
func (runner *Runner) runPiped(ctx context.Context, inv Invocation, stdout, stderr io.Writer) (error, error) {
// Make sure the runner is always initialized.
runner.initialize()
@@ -129,7 +131,7 @@ func (runner *Runner) runPiped(ctx context.Context, inv Invocation, stdout, stde
// runPiped commands.
select {
case <-ctx.Done():
- return nil, ctx.Err()
+ return ctx.Err(), ctx.Err()
case runner.serialized <- struct{}{}:
defer func() { <-runner.serialized }()
}
@@ -139,7 +141,7 @@ func (runner *Runner) runPiped(ctx context.Context, inv Invocation, stdout, stde
for i := 0; i < maxInFlight; i++ {
select {
case <-ctx.Done():
- return nil, ctx.Err()
+ return ctx.Err(), ctx.Err()
case runner.inFlight <- struct{}{}:
// Make sure we always "return" any workers we took.
defer func() { <-runner.inFlight }()
@@ -172,6 +174,7 @@ type Invocation struct {
Logf func(format string, args ...interface{})
}
+// Postcondition: both error results have same nilness.
func (i *Invocation) runWithFriendlyError(ctx context.Context, stdout, stderr io.Writer) (friendlyError error, rawError error) {
rawError = i.run(ctx, stdout, stderr)
if rawError != nil {
diff --git a/vendor/golang.org/x/tools/internal/packagesinternal/packages.go b/vendor/golang.org/x/tools/internal/packagesinternal/packages.go
index d9950b1f..44719de1 100644
--- a/vendor/golang.org/x/tools/internal/packagesinternal/packages.go
+++ b/vendor/golang.org/x/tools/internal/packagesinternal/packages.go
@@ -5,10 +5,6 @@
// Package packagesinternal exposes internal-only fields from go/packages.
package packagesinternal
-import (
- "golang.org/x/tools/internal/gocommand"
-)
-
var GetForTest = func(p interface{}) string { return "" }
var GetDepsErrors = func(p interface{}) []*PackageError { return nil }
@@ -18,10 +14,6 @@ type PackageError struct {
Err string // the error itself
}
-var GetGoCmdRunner = func(config interface{}) *gocommand.Runner { return nil }
-
-var SetGoCmdRunner = func(config interface{}, runner *gocommand.Runner) {}
-
var TypecheckCgo int
var DepsErrors int // must be set as a LoadMode to call GetDepsErrors
var ForTest int // must be set as a LoadMode to call GetForTest
diff --git a/vendor/golang.org/x/tools/internal/typeparams/common.go b/vendor/golang.org/x/tools/internal/typeparams/common.go
index d0d0649f..cdab9885 100644
--- a/vendor/golang.org/x/tools/internal/typeparams/common.go
+++ b/vendor/golang.org/x/tools/internal/typeparams/common.go
@@ -42,7 +42,7 @@ func UnpackIndexExpr(n ast.Node) (x ast.Expr, lbrack token.Pos, indices []ast.Ex
switch e := n.(type) {
case *ast.IndexExpr:
return e.X, e.Lbrack, []ast.Expr{e.Index}, e.Rbrack
- case *IndexListExpr:
+ case *ast.IndexListExpr:
return e.X, e.Lbrack, e.Indices, e.Rbrack
}
return nil, token.NoPos, nil, token.NoPos
@@ -63,7 +63,7 @@ func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack toke
Rbrack: rbrack,
}
default:
- return &IndexListExpr{
+ return &ast.IndexListExpr{
X: x,
Lbrack: lbrack,
Indices: indices,
@@ -74,7 +74,7 @@ func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack toke
// IsTypeParam reports whether t is a type parameter.
func IsTypeParam(t types.Type) bool {
- _, ok := t.(*TypeParam)
+ _, ok := t.(*types.TypeParam)
return ok
}
@@ -100,11 +100,11 @@ func OriginMethod(fn *types.Func) *types.Func {
// Receiver is a *types.Interface.
return fn
}
- if ForNamed(named).Len() == 0 {
+ if named.TypeParams().Len() == 0 {
// Receiver base has no type parameters, so we can avoid the lookup below.
return fn
}
- orig := NamedTypeOrigin(named)
+ orig := named.Origin()
gfn, _, _ := types.LookupFieldOrMethod(orig, true, fn.Pkg(), fn.Name())
// This is a fix for a gopls crash (#60628) due to a go/types bug (#60634). In:
@@ -157,7 +157,7 @@ func OriginMethod(fn *types.Func) *types.Func {
//
// In this case, GenericAssignableTo reports that instantiations of Container
// are assignable to the corresponding instantiation of Interface.
-func GenericAssignableTo(ctxt *Context, V, T types.Type) bool {
+func GenericAssignableTo(ctxt *types.Context, V, T types.Type) bool {
// If V and T are not both named, or do not have matching non-empty type
// parameter lists, fall back on types.AssignableTo.
@@ -167,9 +167,9 @@ func GenericAssignableTo(ctxt *Context, V, T types.Type) bool {
return types.AssignableTo(V, T)
}
- vtparams := ForNamed(VN)
- ttparams := ForNamed(TN)
- if vtparams.Len() == 0 || vtparams.Len() != ttparams.Len() || NamedTypeArgs(VN).Len() != 0 || NamedTypeArgs(TN).Len() != 0 {
+ vtparams := VN.TypeParams()
+ ttparams := TN.TypeParams()
+ if vtparams.Len() == 0 || vtparams.Len() != ttparams.Len() || VN.TypeArgs().Len() != 0 || TN.TypeArgs().Len() != 0 {
return types.AssignableTo(V, T)
}
@@ -182,7 +182,7 @@ func GenericAssignableTo(ctxt *Context, V, T types.Type) bool {
// Minor optimization: ensure we share a context across the two
// instantiations below.
if ctxt == nil {
- ctxt = NewContext()
+ ctxt = types.NewContext()
}
var targs []types.Type
@@ -190,12 +190,12 @@ func GenericAssignableTo(ctxt *Context, V, T types.Type) bool {
targs = append(targs, vtparams.At(i))
}
- vinst, err := Instantiate(ctxt, V, targs, true)
+ vinst, err := types.Instantiate(ctxt, V, targs, true)
if err != nil {
panic("type parameters should satisfy their own constraints")
}
- tinst, err := Instantiate(ctxt, T, targs, true)
+ tinst, err := types.Instantiate(ctxt, T, targs, true)
if err != nil {
return false
}
diff --git a/vendor/golang.org/x/tools/internal/typeparams/coretype.go b/vendor/golang.org/x/tools/internal/typeparams/coretype.go
index 71248209..7ea8840e 100644
--- a/vendor/golang.org/x/tools/internal/typeparams/coretype.go
+++ b/vendor/golang.org/x/tools/internal/typeparams/coretype.go
@@ -108,15 +108,15 @@ func CoreType(T types.Type) types.Type {
//
// _NormalTerms makes no guarantees about the order of terms, except that it
// is deterministic.
-func _NormalTerms(typ types.Type) ([]*Term, error) {
+func _NormalTerms(typ types.Type) ([]*types.Term, error) {
switch typ := typ.(type) {
- case *TypeParam:
+ case *types.TypeParam:
return StructuralTerms(typ)
- case *Union:
+ case *types.Union:
return UnionTermSet(typ)
case *types.Interface:
return InterfaceTermSet(typ)
default:
- return []*Term{NewTerm(false, typ)}, nil
+ return []*types.Term{types.NewTerm(false, typ)}, nil
}
}
diff --git a/vendor/golang.org/x/tools/internal/typeparams/enabled_go117.go b/vendor/golang.org/x/tools/internal/typeparams/enabled_go117.go
deleted file mode 100644
index 18212390..00000000
--- a/vendor/golang.org/x/tools/internal/typeparams/enabled_go117.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2021 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build !go1.18
-// +build !go1.18
-
-package typeparams
-
-// Enabled reports whether type parameters are enabled in the current build
-// environment.
-const Enabled = false
diff --git a/vendor/golang.org/x/tools/internal/typeparams/enabled_go118.go b/vendor/golang.org/x/tools/internal/typeparams/enabled_go118.go
deleted file mode 100644
index d6714882..00000000
--- a/vendor/golang.org/x/tools/internal/typeparams/enabled_go118.go
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2021 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build go1.18
-// +build go1.18
-
-package typeparams
-
-// Note: this constant is in a separate file as this is the only acceptable
-// diff between the <1.18 API of this package and the 1.18 API.
-
-// Enabled reports whether type parameters are enabled in the current build
-// environment.
-const Enabled = true
diff --git a/vendor/golang.org/x/tools/internal/typeparams/normalize.go b/vendor/golang.org/x/tools/internal/typeparams/normalize.go
index 9c631b65..93c80fdc 100644
--- a/vendor/golang.org/x/tools/internal/typeparams/normalize.go
+++ b/vendor/golang.org/x/tools/internal/typeparams/normalize.go
@@ -60,7 +60,7 @@ var ErrEmptyTypeSet = errors.New("empty type set")
//
// StructuralTerms makes no guarantees about the order of terms, except that it
// is deterministic.
-func StructuralTerms(tparam *TypeParam) ([]*Term, error) {
+func StructuralTerms(tparam *types.TypeParam) ([]*types.Term, error) {
constraint := tparam.Constraint()
if constraint == nil {
return nil, fmt.Errorf("%s has nil constraint", tparam)
@@ -78,7 +78,7 @@ func StructuralTerms(tparam *TypeParam) ([]*Term, error) {
//
// See the documentation of StructuralTerms for more information on
// normalization.
-func InterfaceTermSet(iface *types.Interface) ([]*Term, error) {
+func InterfaceTermSet(iface *types.Interface) ([]*types.Term, error) {
return computeTermSet(iface)
}
@@ -88,11 +88,11 @@ func InterfaceTermSet(iface *types.Interface) ([]*Term, error) {
//
// See the documentation of StructuralTerms for more information on
// normalization.
-func UnionTermSet(union *Union) ([]*Term, error) {
+func UnionTermSet(union *types.Union) ([]*types.Term, error) {
return computeTermSet(union)
}
-func computeTermSet(typ types.Type) ([]*Term, error) {
+func computeTermSet(typ types.Type) ([]*types.Term, error) {
tset, err := computeTermSetInternal(typ, make(map[types.Type]*termSet), 0)
if err != nil {
return nil, err
@@ -103,9 +103,9 @@ func computeTermSet(typ types.Type) ([]*Term, error) {
if tset.terms.isAll() {
return nil, nil
}
- var terms []*Term
+ var terms []*types.Term
for _, term := range tset.terms {
- terms = append(terms, NewTerm(term.tilde, term.typ))
+ terms = append(terms, types.NewTerm(term.tilde, term.typ))
}
return terms, nil
}
@@ -162,7 +162,7 @@ func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth in
tset.terms = allTermlist
for i := 0; i < u.NumEmbeddeds(); i++ {
embedded := u.EmbeddedType(i)
- if _, ok := embedded.Underlying().(*TypeParam); ok {
+ if _, ok := embedded.Underlying().(*types.TypeParam); ok {
return nil, fmt.Errorf("invalid embedded type %T", embedded)
}
tset2, err := computeTermSetInternal(embedded, seen, depth+1)
@@ -171,7 +171,7 @@ func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth in
}
tset.terms = tset.terms.intersect(tset2.terms)
}
- case *Union:
+ case *types.Union:
// The term set of a union is the union of term sets of its terms.
tset.terms = nil
for i := 0; i < u.Len(); i++ {
@@ -184,7 +184,7 @@ func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth in
return nil, err
}
terms = tset2.terms
- case *TypeParam, *Union:
+ case *types.TypeParam, *types.Union:
// A stand-alone type parameter or union is not permitted as union
// term.
return nil, fmt.Errorf("invalid union term %T", t)
@@ -199,7 +199,7 @@ func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth in
return nil, fmt.Errorf("exceeded max term count %d", maxTermCount)
}
}
- case *TypeParam:
+ case *types.TypeParam:
panic("unreachable")
default:
// For all other types, the term set is just a single non-tilde term
diff --git a/vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go b/vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go
deleted file mode 100644
index 7ed86e17..00000000
--- a/vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go
+++ /dev/null
@@ -1,197 +0,0 @@
-// Copyright 2021 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build !go1.18
-// +build !go1.18
-
-package typeparams
-
-import (
- "go/ast"
- "go/token"
- "go/types"
-)
-
-func unsupported() {
- panic("type parameters are unsupported at this go version")
-}
-
-// IndexListExpr is a placeholder type, as type parameters are not supported at
-// this Go version. Its methods panic on use.
-type IndexListExpr struct {
- ast.Expr
- X ast.Expr // expression
- Lbrack token.Pos // position of "["
- Indices []ast.Expr // index expressions
- Rbrack token.Pos // position of "]"
-}
-
-// ForTypeSpec returns an empty field list, as type parameters on not supported
-// at this Go version.
-func ForTypeSpec(*ast.TypeSpec) *ast.FieldList {
- return nil
-}
-
-// ForFuncType returns an empty field list, as type parameters are not
-// supported at this Go version.
-func ForFuncType(*ast.FuncType) *ast.FieldList {
- return nil
-}
-
-// TypeParam is a placeholder type, as type parameters are not supported at
-// this Go version. Its methods panic on use.
-type TypeParam struct{ types.Type }
-
-func (*TypeParam) Index() int { unsupported(); return 0 }
-func (*TypeParam) Constraint() types.Type { unsupported(); return nil }
-func (*TypeParam) Obj() *types.TypeName { unsupported(); return nil }
-
-// TypeParamList is a placeholder for an empty type parameter list.
-type TypeParamList struct{}
-
-func (*TypeParamList) Len() int { return 0 }
-func (*TypeParamList) At(int) *TypeParam { unsupported(); return nil }
-
-// TypeList is a placeholder for an empty type list.
-type TypeList struct{}
-
-func (*TypeList) Len() int { return 0 }
-func (*TypeList) At(int) types.Type { unsupported(); return nil }
-
-// NewTypeParam is unsupported at this Go version, and panics.
-func NewTypeParam(name *types.TypeName, constraint types.Type) *TypeParam {
- unsupported()
- return nil
-}
-
-// SetTypeParamConstraint is unsupported at this Go version, and panics.
-func SetTypeParamConstraint(tparam *TypeParam, constraint types.Type) {
- unsupported()
-}
-
-// NewSignatureType calls types.NewSignature, panicking if recvTypeParams or
-// typeParams is non-empty.
-func NewSignatureType(recv *types.Var, recvTypeParams, typeParams []*TypeParam, params, results *types.Tuple, variadic bool) *types.Signature {
- if len(recvTypeParams) != 0 || len(typeParams) != 0 {
- panic("signatures cannot have type parameters at this Go version")
- }
- return types.NewSignature(recv, params, results, variadic)
-}
-
-// ForSignature returns an empty slice.
-func ForSignature(*types.Signature) *TypeParamList {
- return nil
-}
-
-// RecvTypeParams returns a nil slice.
-func RecvTypeParams(sig *types.Signature) *TypeParamList {
- return nil
-}
-
-// IsComparable returns false, as no interfaces are type-restricted at this Go
-// version.
-func IsComparable(*types.Interface) bool {
- return false
-}
-
-// IsMethodSet returns true, as no interfaces are type-restricted at this Go
-// version.
-func IsMethodSet(*types.Interface) bool {
- return true
-}
-
-// IsImplicit returns false, as no interfaces are implicit at this Go version.
-func IsImplicit(*types.Interface) bool {
- return false
-}
-
-// MarkImplicit does nothing, because this Go version does not have implicit
-// interfaces.
-func MarkImplicit(*types.Interface) {}
-
-// ForNamed returns an empty type parameter list, as type parameters are not
-// supported at this Go version.
-func ForNamed(*types.Named) *TypeParamList {
- return nil
-}
-
-// SetForNamed panics if tparams is non-empty.
-func SetForNamed(_ *types.Named, tparams []*TypeParam) {
- if len(tparams) > 0 {
- unsupported()
- }
-}
-
-// NamedTypeArgs returns nil.
-func NamedTypeArgs(*types.Named) *TypeList {
- return nil
-}
-
-// NamedTypeOrigin is the identity method at this Go version.
-func NamedTypeOrigin(named *types.Named) *types.Named {
- return named
-}
-
-// Term holds information about a structural type restriction.
-type Term struct {
- tilde bool
- typ types.Type
-}
-
-func (m *Term) Tilde() bool { return m.tilde }
-func (m *Term) Type() types.Type { return m.typ }
-func (m *Term) String() string {
- pre := ""
- if m.tilde {
- pre = "~"
- }
- return pre + m.typ.String()
-}
-
-// NewTerm is unsupported at this Go version, and panics.
-func NewTerm(tilde bool, typ types.Type) *Term {
- return &Term{tilde, typ}
-}
-
-// Union is a placeholder type, as type parameters are not supported at this Go
-// version. Its methods panic on use.
-type Union struct{ types.Type }
-
-func (*Union) Len() int { return 0 }
-func (*Union) Term(i int) *Term { unsupported(); return nil }
-
-// NewUnion is unsupported at this Go version, and panics.
-func NewUnion(terms []*Term) *Union {
- unsupported()
- return nil
-}
-
-// InitInstanceInfo is a noop at this Go version.
-func InitInstanceInfo(*types.Info) {}
-
-// Instance is a placeholder type, as type parameters are not supported at this
-// Go version.
-type Instance struct {
- TypeArgs *TypeList
- Type types.Type
-}
-
-// GetInstances returns a nil map, as type parameters are not supported at this
-// Go version.
-func GetInstances(info *types.Info) map[*ast.Ident]Instance { return nil }
-
-// Context is a placeholder type, as type parameters are not supported at
-// this Go version.
-type Context struct{}
-
-// NewContext returns a placeholder Context instance.
-func NewContext() *Context {
- return &Context{}
-}
-
-// Instantiate is unsupported on this Go version, and panics.
-func Instantiate(ctxt *Context, typ types.Type, targs []types.Type, validate bool) (types.Type, error) {
- unsupported()
- return nil, nil
-}
diff --git a/vendor/golang.org/x/tools/internal/typeparams/typeparams_go118.go b/vendor/golang.org/x/tools/internal/typeparams/typeparams_go118.go
deleted file mode 100644
index cf301af1..00000000
--- a/vendor/golang.org/x/tools/internal/typeparams/typeparams_go118.go
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright 2021 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build go1.18
-// +build go1.18
-
-package typeparams
-
-import (
- "go/ast"
- "go/types"
-)
-
-// IndexListExpr is an alias for ast.IndexListExpr.
-type IndexListExpr = ast.IndexListExpr
-
-// ForTypeSpec returns n.TypeParams.
-func ForTypeSpec(n *ast.TypeSpec) *ast.FieldList {
- if n == nil {
- return nil
- }
- return n.TypeParams
-}
-
-// ForFuncType returns n.TypeParams.
-func ForFuncType(n *ast.FuncType) *ast.FieldList {
- if n == nil {
- return nil
- }
- return n.TypeParams
-}
-
-// TypeParam is an alias for types.TypeParam
-type TypeParam = types.TypeParam
-
-// TypeParamList is an alias for types.TypeParamList
-type TypeParamList = types.TypeParamList
-
-// TypeList is an alias for types.TypeList
-type TypeList = types.TypeList
-
-// NewTypeParam calls types.NewTypeParam.
-func NewTypeParam(name *types.TypeName, constraint types.Type) *TypeParam {
- return types.NewTypeParam(name, constraint)
-}
-
-// SetTypeParamConstraint calls tparam.SetConstraint(constraint).
-func SetTypeParamConstraint(tparam *TypeParam, constraint types.Type) {
- tparam.SetConstraint(constraint)
-}
-
-// NewSignatureType calls types.NewSignatureType.
-func NewSignatureType(recv *types.Var, recvTypeParams, typeParams []*TypeParam, params, results *types.Tuple, variadic bool) *types.Signature {
- return types.NewSignatureType(recv, recvTypeParams, typeParams, params, results, variadic)
-}
-
-// ForSignature returns sig.TypeParams()
-func ForSignature(sig *types.Signature) *TypeParamList {
- return sig.TypeParams()
-}
-
-// RecvTypeParams returns sig.RecvTypeParams().
-func RecvTypeParams(sig *types.Signature) *TypeParamList {
- return sig.RecvTypeParams()
-}
-
-// IsComparable calls iface.IsComparable().
-func IsComparable(iface *types.Interface) bool {
- return iface.IsComparable()
-}
-
-// IsMethodSet calls iface.IsMethodSet().
-func IsMethodSet(iface *types.Interface) bool {
- return iface.IsMethodSet()
-}
-
-// IsImplicit calls iface.IsImplicit().
-func IsImplicit(iface *types.Interface) bool {
- return iface.IsImplicit()
-}
-
-// MarkImplicit calls iface.MarkImplicit().
-func MarkImplicit(iface *types.Interface) {
- iface.MarkImplicit()
-}
-
-// ForNamed extracts the (possibly empty) type parameter object list from
-// named.
-func ForNamed(named *types.Named) *TypeParamList {
- return named.TypeParams()
-}
-
-// SetForNamed sets the type params tparams on n. Each tparam must be of
-// dynamic type *types.TypeParam.
-func SetForNamed(n *types.Named, tparams []*TypeParam) {
- n.SetTypeParams(tparams)
-}
-
-// NamedTypeArgs returns named.TypeArgs().
-func NamedTypeArgs(named *types.Named) *TypeList {
- return named.TypeArgs()
-}
-
-// NamedTypeOrigin returns named.Orig().
-func NamedTypeOrigin(named *types.Named) *types.Named {
- return named.Origin()
-}
-
-// Term is an alias for types.Term.
-type Term = types.Term
-
-// NewTerm calls types.NewTerm.
-func NewTerm(tilde bool, typ types.Type) *Term {
- return types.NewTerm(tilde, typ)
-}
-
-// Union is an alias for types.Union
-type Union = types.Union
-
-// NewUnion calls types.NewUnion.
-func NewUnion(terms []*Term) *Union {
- return types.NewUnion(terms)
-}
-
-// InitInstanceInfo initializes info to record information about type and
-// function instances.
-func InitInstanceInfo(info *types.Info) {
- info.Instances = make(map[*ast.Ident]types.Instance)
-}
-
-// Instance is an alias for types.Instance.
-type Instance = types.Instance
-
-// GetInstances returns info.Instances.
-func GetInstances(info *types.Info) map[*ast.Ident]Instance {
- return info.Instances
-}
-
-// Context is an alias for types.Context.
-type Context = types.Context
-
-// NewContext calls types.NewContext.
-func NewContext() *Context {
- return types.NewContext()
-}
-
-// Instantiate calls types.Instantiate.
-func Instantiate(ctxt *Context, typ types.Type, targs []types.Type, validate bool) (types.Type, error) {
- return types.Instantiate(ctxt, typ, targs, validate)
-}
diff --git a/vendor/golang.org/x/tools/internal/typesinternal/objectpath.go b/vendor/golang.org/x/tools/internal/typesinternal/objectpath.go
deleted file mode 100644
index 5e96e895..00000000
--- a/vendor/golang.org/x/tools/internal/typesinternal/objectpath.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2023 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package typesinternal
-
-import "go/types"
-
-// This file contains back doors that allow gopls to avoid method sorting when
-// using the objectpath package.
-//
-// This is performance-critical in certain repositories, but changing the
-// behavior of the objectpath package is still being discussed in
-// golang/go#61443. If we decide to remove the sorting in objectpath we can
-// simply delete these back doors. Otherwise, we should add a new API to
-// objectpath that allows controlling the sorting.
-
-// SkipEncoderMethodSorting marks enc (which must be an *objectpath.Encoder) as
-// not requiring sorted methods.
-var SkipEncoderMethodSorting func(enc interface{})
-
-// ObjectpathObject is like objectpath.Object, but allows suppressing method
-// sorting.
-var ObjectpathObject func(pkg *types.Package, p string, skipMethodSorting bool) (types.Object, error)
diff --git a/vendor/golang.org/x/tools/internal/versions/gover.go b/vendor/golang.org/x/tools/internal/versions/gover.go
new file mode 100644
index 00000000..bbabcd22
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/versions/gover.go
@@ -0,0 +1,172 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This is a fork of internal/gover for use by x/tools until
+// go1.21 and earlier are no longer supported by x/tools.
+
+package versions
+
+import "strings"
+
+// A gover is a parsed Go gover: major[.Minor[.Patch]][kind[pre]]
+// The numbers are the original decimal strings to avoid integer overflows
+// and since there is very little actual math. (Probably overflow doesn't matter in practice,
+// but at the time this code was written, there was an existing test that used
+// go1.99999999999, which does not fit in an int on 32-bit platforms.
+// The "big decimal" representation avoids the problem entirely.)
+type gover struct {
+ major string // decimal
+ minor string // decimal or ""
+ patch string // decimal or ""
+ kind string // "", "alpha", "beta", "rc"
+ pre string // decimal or ""
+}
+
+// compare returns -1, 0, or +1 depending on whether
+// x < y, x == y, or x > y, interpreted as toolchain versions.
+// The versions x and y must not begin with a "go" prefix: just "1.21" not "go1.21".
+// Malformed versions compare less than well-formed versions and equal to each other.
+// The language version "1.21" compares less than the release candidate and eventual releases "1.21rc1" and "1.21.0".
+func compare(x, y string) int {
+ vx := parse(x)
+ vy := parse(y)
+
+ if c := cmpInt(vx.major, vy.major); c != 0 {
+ return c
+ }
+ if c := cmpInt(vx.minor, vy.minor); c != 0 {
+ return c
+ }
+ if c := cmpInt(vx.patch, vy.patch); c != 0 {
+ return c
+ }
+ if c := strings.Compare(vx.kind, vy.kind); c != 0 { // "" < alpha < beta < rc
+ return c
+ }
+ if c := cmpInt(vx.pre, vy.pre); c != 0 {
+ return c
+ }
+ return 0
+}
+
+// lang returns the Go language version. For example, lang("1.2.3") == "1.2".
+func lang(x string) string {
+ v := parse(x)
+ if v.minor == "" || v.major == "1" && v.minor == "0" {
+ return v.major
+ }
+ return v.major + "." + v.minor
+}
+
+// isValid reports whether the version x is valid.
+func isValid(x string) bool {
+ return parse(x) != gover{}
+}
+
+// parse parses the Go version string x into a version.
+// It returns the zero version if x is malformed.
+func parse(x string) gover {
+ var v gover
+
+ // Parse major version.
+ var ok bool
+ v.major, x, ok = cutInt(x)
+ if !ok {
+ return gover{}
+ }
+ if x == "" {
+ // Interpret "1" as "1.0.0".
+ v.minor = "0"
+ v.patch = "0"
+ return v
+ }
+
+ // Parse . before minor version.
+ if x[0] != '.' {
+ return gover{}
+ }
+
+ // Parse minor version.
+ v.minor, x, ok = cutInt(x[1:])
+ if !ok {
+ return gover{}
+ }
+ if x == "" {
+ // Patch missing is same as "0" for older versions.
+ // Starting in Go 1.21, patch missing is different from explicit .0.
+ if cmpInt(v.minor, "21") < 0 {
+ v.patch = "0"
+ }
+ return v
+ }
+
+ // Parse patch if present.
+ if x[0] == '.' {
+ v.patch, x, ok = cutInt(x[1:])
+ if !ok || x != "" {
+ // Note that we are disallowing prereleases (alpha, beta, rc) for patch releases here (x != "").
+ // Allowing them would be a bit confusing because we already have:
+ // 1.21 < 1.21rc1
+ // But a prerelease of a patch would have the opposite effect:
+ // 1.21.3rc1 < 1.21.3
+ // We've never needed them before, so let's not start now.
+ return gover{}
+ }
+ return v
+ }
+
+ // Parse prerelease.
+ i := 0
+ for i < len(x) && (x[i] < '0' || '9' < x[i]) {
+ if x[i] < 'a' || 'z' < x[i] {
+ return gover{}
+ }
+ i++
+ }
+ if i == 0 {
+ return gover{}
+ }
+ v.kind, x = x[:i], x[i:]
+ if x == "" {
+ return v
+ }
+ v.pre, x, ok = cutInt(x)
+ if !ok || x != "" {
+ return gover{}
+ }
+
+ return v
+}
+
+// cutInt scans the leading decimal number at the start of x to an integer
+// and returns that value and the rest of the string.
+func cutInt(x string) (n, rest string, ok bool) {
+ i := 0
+ for i < len(x) && '0' <= x[i] && x[i] <= '9' {
+ i++
+ }
+ if i == 0 || x[0] == '0' && i != 1 { // no digits or unnecessary leading zero
+ return "", "", false
+ }
+ return x[:i], x[i:], true
+}
+
+// cmpInt returns cmp.Compare(x, y) interpreting x and y as decimal numbers.
+// (Copied from golang.org/x/mod/semver's compareInt.)
+func cmpInt(x, y string) int {
+ if x == y {
+ return 0
+ }
+ if len(x) < len(y) {
+ return -1
+ }
+ if len(x) > len(y) {
+ return +1
+ }
+ if x < y {
+ return -1
+ } else {
+ return +1
+ }
+}
diff --git a/vendor/golang.org/x/tools/internal/versions/types.go b/vendor/golang.org/x/tools/internal/versions/types.go
new file mode 100644
index 00000000..562eef21
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/versions/types.go
@@ -0,0 +1,19 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package versions
+
+import (
+ "go/types"
+)
+
+// GoVersion returns the Go version of the type package.
+// It returns zero if no version can be determined.
+func GoVersion(pkg *types.Package) string {
+ // TODO(taking): x/tools can call GoVersion() [from 1.21] after 1.25.
+ if pkg, ok := any(pkg).(interface{ GoVersion() string }); ok {
+ return pkg.GoVersion()
+ }
+ return ""
+}
diff --git a/vendor/golang.org/x/tools/internal/versions/types_go121.go b/vendor/golang.org/x/tools/internal/versions/types_go121.go
new file mode 100644
index 00000000..a7b79207
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/versions/types_go121.go
@@ -0,0 +1,20 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !go1.22
+// +build !go1.22
+
+package versions
+
+import (
+ "go/ast"
+ "go/types"
+)
+
+// FileVersions always reports the a file's Go version as the
+// zero version at this Go version.
+func FileVersions(info *types.Info, file *ast.File) string { return "" }
+
+// InitFileVersions is a noop at this Go version.
+func InitFileVersions(*types.Info) {}
diff --git a/vendor/golang.org/x/tools/internal/versions/types_go122.go b/vendor/golang.org/x/tools/internal/versions/types_go122.go
new file mode 100644
index 00000000..7b9ba89a
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/versions/types_go122.go
@@ -0,0 +1,24 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build go1.22
+// +build go1.22
+
+package versions
+
+import (
+ "go/ast"
+ "go/types"
+)
+
+// FileVersions maps a file to the file's semantic Go version.
+// The reported version is the zero version if a version cannot be determined.
+func FileVersions(info *types.Info, file *ast.File) string {
+ return info.FileVersions[file]
+}
+
+// InitFileVersions initializes info to record Go versions for Go files.
+func InitFileVersions(info *types.Info) {
+ info.FileVersions = make(map[*ast.File]string)
+}
diff --git a/vendor/golang.org/x/tools/internal/versions/versions.go b/vendor/golang.org/x/tools/internal/versions/versions.go
new file mode 100644
index 00000000..e16f6c33
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/versions/versions.go
@@ -0,0 +1,52 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package versions
+
+// Note: If we use build tags to use go/versions when go >=1.22,
+// we run into go.dev/issue/53737. Under some operations users would see an
+// import of "go/versions" even if they would not compile the file.
+// For example, during `go get -u ./...` (go.dev/issue/64490) we do not try to include
+// For this reason, this library just a clone of go/versions for the moment.
+
+// Lang returns the Go language version for version x.
+// If x is not a valid version, Lang returns the empty string.
+// For example:
+//
+// Lang("go1.21rc2") = "go1.21"
+// Lang("go1.21.2") = "go1.21"
+// Lang("go1.21") = "go1.21"
+// Lang("go1") = "go1"
+// Lang("bad") = ""
+// Lang("1.21") = ""
+func Lang(x string) string {
+ v := lang(stripGo(x))
+ if v == "" {
+ return ""
+ }
+ return x[:2+len(v)] // "go"+v without allocation
+}
+
+// Compare returns -1, 0, or +1 depending on whether
+// x < y, x == y, or x > y, interpreted as Go versions.
+// The versions x and y must begin with a "go" prefix: "go1.21" not "1.21".
+// Invalid versions, including the empty string, compare less than
+// valid versions and equal to each other.
+// The language version "go1.21" compares less than the
+// release candidate and eventual releases "go1.21rc1" and "go1.21.0".
+// Custom toolchain suffixes are ignored during comparison:
+// "go1.21.0" and "go1.21.0-bigcorp" are equal.
+func Compare(x, y string) int { return compare(stripGo(x), stripGo(y)) }
+
+// IsValid reports whether the version x is valid.
+func IsValid(x string) bool { return isValid(stripGo(x)) }
+
+// stripGo converts from a "go1.21" version to a "1.21" version.
+// If v does not start with "go", stripGo returns the empty string (a known invalid version).
+func stripGo(v string) string {
+ if len(v) < 2 || v[:2] != "go" {
+ return ""
+ }
+ return v[2:]
+}
diff --git a/vendor/google.golang.org/grpc/README.md b/vendor/google.golang.org/grpc/README.md
index 0e6ae69a..ab0fbb79 100644
--- a/vendor/google.golang.org/grpc/README.md
+++ b/vendor/google.golang.org/grpc/README.md
@@ -1,8 +1,8 @@
# gRPC-Go
-[](https://travis-ci.org/grpc/grpc-go)
[][API]
[](https://goreportcard.com/report/github.com/grpc/grpc-go)
+[](https://codecov.io/gh/grpc/grpc-go)
The [Go][] implementation of [gRPC][]: A high performance, open source, general
RPC framework that puts mobile and HTTP/2 first. For more information see the
@@ -14,21 +14,14 @@ RPC framework that puts mobile and HTTP/2 first. For more information see the
## Installation
-With [Go module][] support (Go 1.11+), simply add the following import
+Simply add the following import to your code, and then `go [build|run|test]`
+will automatically fetch the necessary dependencies:
+
```go
import "google.golang.org/grpc"
```
-to your code, and then `go [build|run|test]` will automatically fetch the
-necessary dependencies.
-
-Otherwise, to install the `grpc-go` package, run the following command:
-
-```console
-$ go get -u google.golang.org/grpc
-```
-
> **Note:** If you are trying to access `grpc-go` from **China**, see the
> [FAQ](#FAQ) below.
@@ -56,15 +49,6 @@ To build Go code, there are several options:
- Set up a VPN and access google.golang.org through that.
-- Without Go module support: `git clone` the repo manually:
-
- ```sh
- git clone https://github.com/grpc/grpc-go.git $GOPATH/src/google.golang.org/grpc
- ```
-
- You will need to do the same for all of grpc's dependencies in `golang.org`,
- e.g. `golang.org/x/net`.
-
- With Go module support: it is possible to use the `replace` feature of `go
mod` to create aliases for golang.org packages. In your project's directory:
@@ -76,33 +60,13 @@ To build Go code, there are several options:
```
Again, this will need to be done for all transitive dependencies hosted on
- golang.org as well. For details, refer to [golang/go issue #28652](https://github.com/golang/go/issues/28652).
+ golang.org as well. For details, refer to [golang/go issue
+ #28652](https://github.com/golang/go/issues/28652).
### Compiling error, undefined: grpc.SupportPackageIsVersion
-#### If you are using Go modules:
-
-Ensure your gRPC-Go version is `require`d at the appropriate version in
-the same module containing the generated `.pb.go` files. For example,
-`SupportPackageIsVersion6` needs `v1.27.0`, so in your `go.mod` file:
-
-```go
-module
-
-require (
- google.golang.org/grpc v1.27.0
-)
-```
-
-#### If you are *not* using Go modules:
-
-Update the `proto` package, gRPC package, and rebuild the `.proto` files:
-
-```sh
-go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
-go get -u google.golang.org/grpc
-protoc --go_out=plugins=grpc:. *.proto
-```
+Please update to the latest version of gRPC-Go using
+`go get google.golang.org/grpc`.
### How to turn on logging
@@ -121,9 +85,11 @@ possible reasons, including:
1. mis-configured transport credentials, connection failed on handshaking
1. bytes disrupted, possibly by a proxy in between
1. server shutdown
- 1. Keepalive parameters caused connection shutdown, for example if you have configured
- your server to terminate connections regularly to [trigger DNS lookups](https://github.com/grpc/grpc-go/issues/3170#issuecomment-552517779).
- If this is the case, you may want to increase your [MaxConnectionAgeGrace](https://pkg.go.dev/google.golang.org/grpc/keepalive?tab=doc#ServerParameters),
+ 1. Keepalive parameters caused connection shutdown, for example if you have
+ configured your server to terminate connections regularly to [trigger DNS
+ lookups](https://github.com/grpc/grpc-go/issues/3170#issuecomment-552517779).
+ If this is the case, you may want to increase your
+ [MaxConnectionAgeGrace](https://pkg.go.dev/google.golang.org/grpc/keepalive?tab=doc#ServerParameters),
to allow longer RPC calls to finish.
It can be tricky to debug this because the error happens on the client side but
diff --git a/vendor/google.golang.org/grpc/attributes/attributes.go b/vendor/google.golang.org/grpc/attributes/attributes.go
index 3efca459..52d530d7 100644
--- a/vendor/google.golang.org/grpc/attributes/attributes.go
+++ b/vendor/google.golang.org/grpc/attributes/attributes.go
@@ -34,26 +34,26 @@ import (
// key/value pairs. Keys must be hashable, and users should define their own
// types for keys. Values should not be modified after they are added to an
// Attributes or if they were received from one. If values implement 'Equal(o
-// interface{}) bool', it will be called by (*Attributes).Equal to determine
-// whether two values with the same key should be considered equal.
+// 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[interface{}]interface{}
+ m map[any]any
}
// New returns a new Attributes containing the key/value pair.
-func New(key, value interface{}) *Attributes {
- return &Attributes{m: map[interface{}]interface{}{key: value}}
+func New(key, value any) *Attributes {
+ return &Attributes{m: map[any]any{key: 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.
-func (a *Attributes) WithValue(key, value interface{}) *Attributes {
+func (a *Attributes) WithValue(key, value any) *Attributes {
if a == nil {
return New(key, value)
}
- n := &Attributes{m: make(map[interface{}]interface{}, len(a.m)+1)}
+ n := &Attributes{m: make(map[any]any, len(a.m)+1)}
for k, v := range a.m {
n.m[k] = v
}
@@ -63,20 +63,19 @@ func (a *Attributes) WithValue(key, value interface{}) *Attributes {
// 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 interface{}) interface{} {
+func (a *Attributes) Value(key any) any {
if a == nil {
return nil
}
return a.m[key]
}
-// Equal returns whether a and o are equivalent. If 'Equal(o interface{})
-// bool' is implemented for a value in the attributes, it is called to
-// determine if the value matches the one stored in the other attributes. If
-// Equal is not implemented, standard equality is used to determine if the two
-// values are equal. Note that some types (e.g. maps) aren't comparable by
-// default, so they must be wrapped in a struct, or in an alias type, with Equal
-// defined.
+// Equal returns whether a and o are equivalent. If 'Equal(o any) bool' is
+// implemented for a value in the attributes, it is called to determine if the
+// value matches the one stored in the other attributes. If Equal is not
+// implemented, standard equality is used to determine if the two values are
+// equal. Note that some types (e.g. maps) aren't comparable by default, so
+// they must be wrapped in a struct, or in an alias type, with Equal defined.
func (a *Attributes) Equal(o *Attributes) bool {
if a == nil && o == nil {
return true
@@ -93,7 +92,7 @@ func (a *Attributes) Equal(o *Attributes) bool {
// o missing element of a
return false
}
- if eq, ok := v.(interface{ Equal(o interface{}) bool }); ok {
+ if eq, ok := v.(interface{ Equal(o any) bool }); ok {
if !eq.Equal(ov) {
return false
}
@@ -112,19 +111,31 @@ func (a *Attributes) String() string {
sb.WriteString("{")
first := true
for k, v := range a.m {
- var key, val string
- if str, ok := k.(interface{ String() string }); ok {
- key = str.String()
- }
- if str, ok := v.(interface{ String() string }); ok {
- val = str.String()
- }
if !first {
sb.WriteString(", ")
}
- sb.WriteString(fmt.Sprintf("%q: %q, ", key, val))
+ sb.WriteString(fmt.Sprintf("%q: %q ", str(k), str(v)))
first = false
}
sb.WriteString("}")
return sb.String()
}
+
+func str(x any) (s string) {
+ if v, ok := x.(fmt.Stringer); ok {
+ return fmt.Sprint(v)
+ } else if v, ok := x.(string); ok {
+ return v
+ }
+ return fmt.Sprintf("<%p>", x)
+}
+
+// MarshalJSON helps implement the json.Marshaler interface, thereby rendering
+// the Attributes correctly when printing (via pretty.JSON) structs containing
+// Attributes as fields.
+//
+// Is it impossible to unmarshal attributes from a JSON representation and this
+// method is meant only for debugging purposes.
+func (a *Attributes) MarshalJSON() ([]byte, error) {
+ return []byte(a.String()), nil
+}
diff --git a/vendor/google.golang.org/grpc/balancer/balancer.go b/vendor/google.golang.org/grpc/balancer/balancer.go
index 8f00523c..d79560a2 100644
--- a/vendor/google.golang.org/grpc/balancer/balancer.go
+++ b/vendor/google.golang.org/grpc/balancer/balancer.go
@@ -30,6 +30,7 @@ import (
"google.golang.org/grpc/channelz"
"google.golang.org/grpc/connectivity"
"google.golang.org/grpc/credentials"
+ "google.golang.org/grpc/grpclog"
"google.golang.org/grpc/internal"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/resolver"
@@ -39,6 +40,8 @@ import (
var (
// m is a map from name to balancer builder.
m = make(map[string]Builder)
+
+ logger = grpclog.Component("balancer")
)
// Register registers the balancer builder to the balancer map. b.Name
@@ -51,6 +54,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) {
+ if strings.ToLower(b.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())
+ }
m[strings.ToLower(b.Name())] = b
}
@@ -70,6 +79,12 @@ func init() {
// Note that the compare is done in a case-insensitive 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 b, ok := m[strings.ToLower(name)]; ok {
return b
}
@@ -105,8 +120,8 @@ type SubConn interface {
//
// This will trigger a state transition for the SubConn.
//
- // Deprecated: This method is now part of the ClientConn interface and will
- // eventually be removed from here.
+ // Deprecated: this method will be removed. Create new SubConns for new
+ // addresses instead.
UpdateAddresses([]resolver.Address)
// Connect starts the connecting for this SubConn.
Connect()
@@ -115,6 +130,13 @@ type SubConn interface {
// creates a new one and returns it. Returns a close function which must
// be called when the Producer is no longer needed.
GetOrBuildProducer(ProducerBuilder) (p Producer, close func())
+ // Shutdown shuts down the SubConn gracefully. Any started RPCs will be
+ // allowed to complete. No future calls should be made on the SubConn.
+ // One final state update will be delivered to the StateListener (or
+ // UpdateSubConnState; deprecated) with ConnectivityState of Shutdown to
+ // indicate the shutdown operation. This may be delivered before
+ // in-progress RPCs are complete and the actual connection is closed.
+ Shutdown()
}
// NewSubConnOptions contains options to create new SubConn.
@@ -129,6 +151,11 @@ type NewSubConnOptions struct {
// HealthCheckEnabled indicates whether health check service should be
// enabled on this SubConn
HealthCheckEnabled bool
+ // StateListener is called when the state of the subconn changes. If nil,
+ // Balancer.UpdateSubConnState will be called instead. Will never be
+ // invoked until after Connect() is called on the SubConn created with
+ // these options.
+ StateListener func(SubConnState)
}
// State contains the balancer's state relevant to the gRPC ClientConn.
@@ -150,16 +177,24 @@ type ClientConn interface {
// NewSubConn is called by balancer to create a new SubConn.
// It doesn't block and wait for the connections to be established.
// Behaviors of the SubConn can be controlled by options.
+ //
+ // Deprecated: please be aware that in a future version, SubConns will only
+ // support one address per SubConn.
NewSubConn([]resolver.Address, NewSubConnOptions) (SubConn, error)
// RemoveSubConn removes the SubConn from ClientConn.
// The SubConn will be shutdown.
+ //
+ // Deprecated: use SubConn.Shutdown instead.
RemoveSubConn(SubConn)
// UpdateAddresses updates the addresses used in the passed in SubConn.
// gRPC checks if the currently connected address is still in the new list.
// If so, the connection will be kept. Else, the connection will be
// gracefully closed, and a new connection will be created.
//
- // This will trigger a state transition for the SubConn.
+ // This may trigger a state transition for the SubConn.
+ //
+ // Deprecated: this method will be removed. Create new SubConns for new
+ // addresses instead.
UpdateAddresses(SubConn, []resolver.Address)
// UpdateState notifies gRPC that the balancer's internal state has
@@ -250,7 +285,7 @@ type DoneInfo struct {
// trailing metadata.
//
// The only supported type now is *orca_v3.LoadReport.
- ServerLoad interface{}
+ ServerLoad any
}
var (
@@ -343,9 +378,13 @@ type Balancer interface {
ResolverError(error)
// UpdateSubConnState is called by gRPC when the state of a SubConn
// changes.
+ //
+ // Deprecated: Use NewSubConnOptions.StateListener when creating the
+ // SubConn instead.
UpdateSubConnState(SubConn, SubConnState)
- // Close closes the balancer. The balancer is not required to call
- // ClientConn.RemoveSubConn for its existing SubConns.
+ // Close closes the balancer. The balancer is not currently required to
+ // call SubConn.Shutdown for its existing SubConns; however, this will be
+ // required in a future release, so it is recommended.
Close()
}
@@ -390,15 +429,14 @@ var ErrBadResolverState = errors.New("bad resolver state")
type ProducerBuilder interface {
// Build creates a Producer. The first parameter is always a
// grpc.ClientConnInterface (a type to allow creating RPCs/streams on the
- // associated SubConn), but is declared as interface{} to avoid a
- // dependency cycle. Should also return a close function that will be
- // called when all references to the Producer have been given up.
- Build(grpcClientConnInterface interface{}) (p Producer, close func())
+ // associated SubConn), but is declared as `any` to avoid a dependency
+ // cycle. Should also return a close function that will be called when all
+ // references to the Producer have been given up.
+ Build(grpcClientConnInterface any) (p Producer, close func())
}
// A Producer is a type shared among potentially many consumers. It is
// associated with a SubConn, and an implementation will typically contain
// other methods to provide additional functionality, e.g. configuration or
// subscription registration.
-type Producer interface {
-}
+type Producer any
diff --git a/vendor/google.golang.org/grpc/balancer/base/balancer.go b/vendor/google.golang.org/grpc/balancer/base/balancer.go
index 3929c26d..a7f1eeec 100644
--- a/vendor/google.golang.org/grpc/balancer/base/balancer.go
+++ b/vendor/google.golang.org/grpc/balancer/base/balancer.go
@@ -105,7 +105,12 @@ func (b *baseBalancer) UpdateClientConnState(s balancer.ClientConnState) error {
addrsSet.Set(a, nil)
if _, ok := b.subConns.Get(a); !ok {
// a is a new address (not existing in b.subConns).
- sc, err := b.cc.NewSubConn([]resolver.Address{a}, balancer.NewSubConnOptions{HealthCheckEnabled: b.config.HealthCheck})
+ var sc balancer.SubConn
+ opts := balancer.NewSubConnOptions{
+ HealthCheckEnabled: b.config.HealthCheck,
+ StateListener: func(scs balancer.SubConnState) { b.updateSubConnState(sc, scs) },
+ }
+ sc, err := b.cc.NewSubConn([]resolver.Address{a}, opts)
if err != nil {
logger.Warningf("base.baseBalancer: failed to create new SubConn: %v", err)
continue
@@ -121,10 +126,10 @@ func (b *baseBalancer) UpdateClientConnState(s balancer.ClientConnState) error {
sc := sci.(balancer.SubConn)
// a was removed by resolver.
if _, ok := addrsSet.Get(a); !ok {
- b.cc.RemoveSubConn(sc)
+ sc.Shutdown()
b.subConns.Delete(a)
// Keep the state of this sc in b.scStates until sc's state becomes Shutdown.
- // The entry will be deleted in UpdateSubConnState.
+ // The entry will be deleted in updateSubConnState.
}
}
// If resolver state contains no addresses, return an error so ClientConn
@@ -177,7 +182,12 @@ func (b *baseBalancer) regeneratePicker() {
b.picker = b.pickerBuilder.Build(PickerBuildInfo{ReadySCs: readySCs})
}
+// UpdateSubConnState is a nop because a StateListener is always set in NewSubConn.
func (b *baseBalancer) UpdateSubConnState(sc balancer.SubConn, state balancer.SubConnState) {
+ logger.Errorf("base.baseBalancer: UpdateSubConnState(%v, %+v) called unexpectedly", sc, state)
+}
+
+func (b *baseBalancer) updateSubConnState(sc balancer.SubConn, state balancer.SubConnState) {
s := state.ConnectivityState
if logger.V(2) {
logger.Infof("base.baseBalancer: handle SubConn state change: %p, %v", sc, s)
@@ -204,8 +214,8 @@ func (b *baseBalancer) UpdateSubConnState(sc balancer.SubConn, state balancer.Su
case connectivity.Idle:
sc.Connect()
case connectivity.Shutdown:
- // When an address was removed by resolver, b called RemoveSubConn but
- // kept the sc's state in scStates. Remove state for this sc here.
+ // When an address was removed by resolver, b called Shutdown but kept
+ // the sc's state in scStates. Remove state for this sc here.
delete(b.scStates, sc)
case connectivity.TransientFailure:
// Save error to be reported via picker.
@@ -226,7 +236,7 @@ func (b *baseBalancer) UpdateSubConnState(sc balancer.SubConn, state balancer.Su
}
// Close is a nop because base balancer doesn't have internal state to clean up,
-// and it doesn't need to call RemoveSubConn for the SubConns.
+// and it doesn't need to call Shutdown for the SubConns.
func (b *baseBalancer) Close() {
}
diff --git a/vendor/google.golang.org/grpc/balancer_conn_wrappers.go b/vendor/google.golang.org/grpc/balancer_wrapper.go
similarity index 52%
rename from vendor/google.golang.org/grpc/balancer_conn_wrappers.go
rename to vendor/google.golang.org/grpc/balancer_wrapper.go
index 04b9ad41..b5e30cff 100644
--- a/vendor/google.golang.org/grpc/balancer_conn_wrappers.go
+++ b/vendor/google.golang.org/grpc/balancer_wrapper.go
@@ -32,21 +32,13 @@ import (
"google.golang.org/grpc/resolver"
)
-type ccbMode int
-
-const (
- ccbModeActive = iota
- ccbModeIdle
- ccbModeClosed
- ccbModeExitingIdle
-)
-
// ccBalancerWrapper sits between the ClientConn and the Balancer.
//
// ccBalancerWrapper implements methods corresponding to the ones on the
// balancer.Balancer interface. The ClientConn is free to call these methods
// concurrently and the ccBalancerWrapper ensures that calls from the ClientConn
-// to the Balancer happen synchronously and in order.
+// to the Balancer happen in order by performing them in the serializer, without
+// any mutexes held.
//
// ccBalancerWrapper also implements the balancer.ClientConn interface and is
// passed to the Balancer implementations. It invokes unexported methods on the
@@ -57,99 +49,75 @@ const (
type ccBalancerWrapper struct {
// The following fields are initialized when the wrapper is created and are
// read-only afterwards, and therefore can be accessed without a mutex.
- cc *ClientConn
- opts balancer.BuildOptions
+ cc *ClientConn
+ opts balancer.BuildOptions
+ serializer *grpcsync.CallbackSerializer
+ serializerCancel context.CancelFunc
- // Outgoing (gRPC --> balancer) calls are guaranteed to execute in a
- // mutually exclusive manner as they are scheduled in the serializer. Fields
- // accessed *only* in these serializer callbacks, can therefore be accessed
- // without a mutex.
- balancer *gracefulswitch.Balancer
+ // The following fields are only accessed within the serializer or during
+ // initialization.
curBalancerName string
+ balancer *gracefulswitch.Balancer
- // mu guards access to the below fields. Access to the serializer and its
- // cancel function needs to be mutex protected because they are overwritten
- // when the wrapper exits idle mode.
- mu sync.Mutex
- serializer *grpcsync.CallbackSerializer // To serialize all outoing calls.
- serializerCancel context.CancelFunc // To close the seralizer at close/enterIdle time.
- mode ccbMode // Tracks the current mode of the wrapper.
+ // The following field is protected by mu. Caller must take cc.mu before
+ // taking mu.
+ mu sync.Mutex
+ closed bool
}
-// newCCBalancerWrapper creates a new balancer wrapper. The underlying balancer
-// is not created until the switchTo() method is invoked.
-func newCCBalancerWrapper(cc *ClientConn, bopts balancer.BuildOptions) *ccBalancerWrapper {
- ctx, cancel := context.WithCancel(context.Background())
+// newCCBalancerWrapper creates a new balancer wrapper in idle state. The
+// underlying balancer is not created until the switchTo() method is invoked.
+func newCCBalancerWrapper(cc *ClientConn) *ccBalancerWrapper {
+ ctx, cancel := context.WithCancel(cc.ctx)
ccb := &ccBalancerWrapper{
- cc: cc,
- opts: bopts,
+ cc: cc,
+ opts: balancer.BuildOptions{
+ DialCreds: cc.dopts.copts.TransportCredentials,
+ CredsBundle: cc.dopts.copts.CredsBundle,
+ Dialer: cc.dopts.copts.Dialer,
+ Authority: cc.authority,
+ CustomUserAgent: cc.dopts.copts.UserAgent,
+ ChannelzParentID: cc.channelzID,
+ Target: cc.parsedTarget,
+ },
serializer: grpcsync.NewCallbackSerializer(ctx),
serializerCancel: cancel,
}
- ccb.balancer = gracefulswitch.NewBalancer(ccb, bopts)
+ ccb.balancer = gracefulswitch.NewBalancer(ccb, ccb.opts)
return ccb
}
// updateClientConnState is invoked by grpc to push a ClientConnState update to
-// the underlying balancer.
+// the underlying balancer. This is always executed from the serializer, so
+// it is safe to call into the balancer here.
func (ccb *ccBalancerWrapper) updateClientConnState(ccs *balancer.ClientConnState) error {
- ccb.mu.Lock()
- errCh := make(chan error, 1)
- // Here and everywhere else where Schedule() is called, it is done with the
- // lock held. But the lock guards only the scheduling part. The actual
- // callback is called asynchronously without the lock being held.
- ok := ccb.serializer.Schedule(func(_ context.Context) {
- // If the addresses specified in the update contain addresses of type
- // "grpclb" and the selected LB policy is not "grpclb", these addresses
- // will be filtered out and ccs will be modified with the updated
- // address list.
- if ccb.curBalancerName != grpclbName {
- var addrs []resolver.Address
- for _, addr := range ccs.ResolverState.Addresses {
- if addr.Type == resolver.GRPCLB {
- continue
- }
- addrs = append(addrs, addr)
- }
- ccs.ResolverState.Addresses = addrs
+ errCh := make(chan error)
+ ok := ccb.serializer.Schedule(func(ctx context.Context) {
+ defer close(errCh)
+ if ctx.Err() != nil || ccb.balancer == nil {
+ return
+ }
+ err := ccb.balancer.UpdateClientConnState(*ccs)
+ if logger.V(2) && err != nil {
+ logger.Infof("error from balancer.UpdateClientConnState: %v", err)
}
- errCh <- ccb.balancer.UpdateClientConnState(*ccs)
+ errCh <- err
})
if !ok {
- // If we are unable to schedule a function with the serializer, it
- // indicates that it has been closed. A serializer is only closed when
- // the wrapper is closed or is in idle.
- ccb.mu.Unlock()
- return fmt.Errorf("grpc: cannot send state update to a closed or idle balancer")
- }
- ccb.mu.Unlock()
-
- // We get here only if the above call to Schedule succeeds, in which case it
- // is guaranteed that the scheduled function will run. Therefore it is safe
- // to block on this channel.
- err := <-errCh
- if logger.V(2) && err != nil {
- logger.Infof("error from balancer.UpdateClientConnState: %v", err)
+ return nil
}
- return err
-}
-
-// updateSubConnState is invoked by grpc to push a subConn state update to the
-// underlying balancer.
-func (ccb *ccBalancerWrapper) updateSubConnState(sc balancer.SubConn, s connectivity.State, err error) {
- ccb.mu.Lock()
- ccb.serializer.Schedule(func(_ context.Context) {
- ccb.balancer.UpdateSubConnState(sc, balancer.SubConnState{ConnectivityState: s, ConnectionError: err})
- })
- ccb.mu.Unlock()
+ return <-errCh
}
+// resolverError is invoked by grpc to push a resolver error to the underlying
+// balancer. The call to the balancer is executed from the serializer.
func (ccb *ccBalancerWrapper) resolverError(err error) {
- ccb.mu.Lock()
- ccb.serializer.Schedule(func(_ context.Context) {
+ ccb.serializer.Schedule(func(ctx context.Context) {
+ if ctx.Err() != nil || ccb.balancer == nil {
+ return
+ }
ccb.balancer.ResolverError(err)
})
- ccb.mu.Unlock()
}
// switchTo is invoked by grpc to instruct the balancer wrapper to switch to the
@@ -163,8 +131,10 @@ func (ccb *ccBalancerWrapper) resolverError(err error) {
// the ccBalancerWrapper keeps track of the current LB policy name, and skips
// the graceful balancer switching process if the name does not change.
func (ccb *ccBalancerWrapper) switchTo(name string) {
- ccb.mu.Lock()
- ccb.serializer.Schedule(func(_ context.Context) {
+ ccb.serializer.Schedule(func(ctx context.Context) {
+ if ctx.Err() != nil || ccb.balancer == nil {
+ return
+ }
// TODO: Other languages use case-sensitive balancer registries. We should
// switch as well. See: https://github.com/grpc/grpc-go/issues/5288.
if strings.EqualFold(ccb.curBalancerName, name) {
@@ -172,7 +142,6 @@ func (ccb *ccBalancerWrapper) switchTo(name string) {
}
ccb.buildLoadBalancingPolicy(name)
})
- ccb.mu.Unlock()
}
// buildLoadBalancingPolicy performs the following:
@@ -199,151 +168,69 @@ func (ccb *ccBalancerWrapper) buildLoadBalancingPolicy(name string) {
ccb.curBalancerName = builder.Name()
}
+// close initiates async shutdown of the wrapper. cc.mu must be held when
+// calling this function. To determine the wrapper has finished shutting down,
+// the channel should block on ccb.serializer.Done() without cc.mu held.
func (ccb *ccBalancerWrapper) close() {
- channelz.Info(logger, ccb.cc.channelzID, "ccBalancerWrapper: closing")
- ccb.closeBalancer(ccbModeClosed)
-}
-
-// enterIdleMode is invoked by grpc when the channel enters idle mode upon
-// expiry of idle_timeout. This call blocks until the balancer is closed.
-func (ccb *ccBalancerWrapper) enterIdleMode() {
- channelz.Info(logger, ccb.cc.channelzID, "ccBalancerWrapper: entering idle mode")
- ccb.closeBalancer(ccbModeIdle)
-}
-
-// closeBalancer is invoked when the channel is being closed or when it enters
-// idle mode upon expiry of idle_timeout.
-func (ccb *ccBalancerWrapper) closeBalancer(m ccbMode) {
ccb.mu.Lock()
- if ccb.mode == ccbModeClosed || ccb.mode == ccbModeIdle {
- ccb.mu.Unlock()
- return
- }
-
- ccb.mode = m
- done := ccb.serializer.Done
- b := ccb.balancer
- ok := ccb.serializer.Schedule(func(_ context.Context) {
- // Close the serializer to ensure that no more calls from gRPC are sent
- // to the balancer.
- ccb.serializerCancel()
- // Empty the current balancer name because we don't have a balancer
- // anymore and also so that we act on the next call to switchTo by
- // creating a new balancer specified by the new resolver.
- ccb.curBalancerName = ""
- })
- if !ok {
- ccb.mu.Unlock()
- return
- }
+ ccb.closed = true
ccb.mu.Unlock()
-
- // Give enqueued callbacks a chance to finish.
- <-done
- // Spawn a goroutine to close the balancer (since it may block trying to
- // cleanup all allocated resources) and return early.
- go b.Close()
-}
-
-// exitIdleMode is invoked by grpc when the channel exits idle mode either
-// because of an RPC or because of an invocation of the Connect() API. This
-// recreates the balancer that was closed previously when entering idle mode.
-//
-// If the channel is not in idle mode, we know for a fact that we are here as a
-// result of the user calling the Connect() method on the ClientConn. In this
-// case, we can simply forward the call to the underlying balancer, instructing
-// it to reconnect to the backends.
-func (ccb *ccBalancerWrapper) exitIdleMode() {
- ccb.mu.Lock()
- if ccb.mode == ccbModeClosed {
- // Request to exit idle is a no-op when wrapper is already closed.
- ccb.mu.Unlock()
- return
- }
-
- if ccb.mode == ccbModeIdle {
- // Recreate the serializer which was closed when we entered idle.
- ctx, cancel := context.WithCancel(context.Background())
- ccb.serializer = grpcsync.NewCallbackSerializer(ctx)
- ccb.serializerCancel = cancel
- }
-
- // The ClientConn guarantees that mutual exclusion between close() and
- // exitIdleMode(), and since we just created a new serializer, we can be
- // sure that the below function will be scheduled.
- done := make(chan struct{})
- ccb.serializer.Schedule(func(_ context.Context) {
- defer close(done)
-
- ccb.mu.Lock()
- defer ccb.mu.Unlock()
-
- if ccb.mode != ccbModeIdle {
- ccb.balancer.ExitIdle()
+ channelz.Info(logger, ccb.cc.channelzID, "ccBalancerWrapper: closing")
+ ccb.serializer.Schedule(func(context.Context) {
+ if ccb.balancer == nil {
return
}
-
- // Gracefulswitch balancer does not support a switchTo operation after
- // being closed. Hence we need to create a new one here.
- ccb.balancer = gracefulswitch.NewBalancer(ccb, ccb.opts)
- ccb.mode = ccbModeActive
- channelz.Info(logger, ccb.cc.channelzID, "ccBalancerWrapper: exiting idle mode")
-
+ ccb.balancer.Close()
+ ccb.balancer = nil
})
- ccb.mu.Unlock()
-
- <-done
+ ccb.serializerCancel()
}
-func (ccb *ccBalancerWrapper) isIdleOrClosed() bool {
- ccb.mu.Lock()
- defer ccb.mu.Unlock()
- return ccb.mode == ccbModeIdle || ccb.mode == ccbModeClosed
+// exitIdle invokes the balancer's exitIdle method in the serializer.
+func (ccb *ccBalancerWrapper) exitIdle() {
+ ccb.serializer.Schedule(func(ctx context.Context) {
+ if ctx.Err() != nil || ccb.balancer == nil {
+ return
+ }
+ ccb.balancer.ExitIdle()
+ })
}
func (ccb *ccBalancerWrapper) NewSubConn(addrs []resolver.Address, opts balancer.NewSubConnOptions) (balancer.SubConn, error) {
- if ccb.isIdleOrClosed() {
- return nil, fmt.Errorf("grpc: cannot create SubConn when balancer is closed or idle")
+ ccb.cc.mu.Lock()
+ defer ccb.cc.mu.Unlock()
+
+ ccb.mu.Lock()
+ if ccb.closed {
+ ccb.mu.Unlock()
+ return nil, fmt.Errorf("balancer is being closed; no new SubConns allowed")
}
+ ccb.mu.Unlock()
if len(addrs) == 0 {
return nil, fmt.Errorf("grpc: cannot create SubConn with empty address list")
}
- ac, err := ccb.cc.newAddrConn(addrs, opts)
+ ac, err := ccb.cc.newAddrConnLocked(addrs, opts)
if err != nil {
channelz.Warningf(logger, ccb.cc.channelzID, "acBalancerWrapper: NewSubConn: failed to newAddrConn: %v", err)
return nil, err
}
- acbw := &acBalancerWrapper{ac: ac, producers: make(map[balancer.ProducerBuilder]*refCountedProducer)}
+ acbw := &acBalancerWrapper{
+ ccb: ccb,
+ ac: ac,
+ producers: make(map[balancer.ProducerBuilder]*refCountedProducer),
+ stateListener: opts.StateListener,
+ }
ac.acbw = acbw
return acbw, nil
}
func (ccb *ccBalancerWrapper) RemoveSubConn(sc balancer.SubConn) {
- if ccb.isIdleOrClosed() {
- // It it safe to ignore this call when the balancer is closed or in idle
- // because the ClientConn takes care of closing the connections.
- //
- // Not returning early from here when the balancer is closed or in idle
- // leads to a deadlock though, because of the following sequence of
- // calls when holding cc.mu:
- // cc.exitIdleMode --> ccb.enterIdleMode --> gsw.Close -->
- // ccb.RemoveAddrConn --> cc.removeAddrConn
- return
- }
-
- acbw, ok := sc.(*acBalancerWrapper)
- if !ok {
- return
- }
- ccb.cc.removeAddrConn(acbw.ac, errConnDrain)
+ // The graceful switch balancer will never call this.
+ logger.Errorf("ccb RemoveSubConn(%v) called unexpectedly, sc")
}
func (ccb *ccBalancerWrapper) UpdateAddresses(sc balancer.SubConn, addrs []resolver.Address) {
- if ccb.isIdleOrClosed() {
- return
- }
-
acbw, ok := sc.(*acBalancerWrapper)
if !ok {
return
@@ -352,25 +239,39 @@ func (ccb *ccBalancerWrapper) UpdateAddresses(sc balancer.SubConn, addrs []resol
}
func (ccb *ccBalancerWrapper) UpdateState(s balancer.State) {
- if ccb.isIdleOrClosed() {
+ ccb.cc.mu.Lock()
+ defer ccb.cc.mu.Unlock()
+
+ ccb.mu.Lock()
+ if ccb.closed {
+ ccb.mu.Unlock()
return
}
-
+ ccb.mu.Unlock()
// Update picker before updating state. Even though the ordering here does
// not matter, it can lead to multiple calls of Pick in the common start-up
// case where we wait for ready and then perform an RPC. If the picker is
// updated later, we could call the "connecting" picker when the state is
// updated, and then call the "ready" picker after the picker gets updated.
- ccb.cc.blockingpicker.updatePicker(s.Picker)
+
+ // Note that there is no need to check if the balancer wrapper was closed,
+ // as we know the graceful switch LB policy will not call cc if it has been
+ // closed.
+ ccb.cc.pickerWrapper.updatePicker(s.Picker)
ccb.cc.csMgr.updateState(s.ConnectivityState)
}
func (ccb *ccBalancerWrapper) ResolveNow(o resolver.ResolveNowOptions) {
- if ccb.isIdleOrClosed() {
+ ccb.cc.mu.RLock()
+ defer ccb.cc.mu.RUnlock()
+
+ ccb.mu.Lock()
+ if ccb.closed {
+ ccb.mu.Unlock()
return
}
-
- ccb.cc.resolveNow(o)
+ ccb.mu.Unlock()
+ ccb.cc.resolveNowLocked(o)
}
func (ccb *ccBalancerWrapper) Target() string {
@@ -380,12 +281,28 @@ func (ccb *ccBalancerWrapper) Target() string {
// acBalancerWrapper is a wrapper on top of ac for balancers.
// It implements balancer.SubConn interface.
type acBalancerWrapper struct {
- ac *addrConn // read-only
+ ac *addrConn // read-only
+ ccb *ccBalancerWrapper // read-only
+ stateListener func(balancer.SubConnState)
mu sync.Mutex
producers map[balancer.ProducerBuilder]*refCountedProducer
}
+// updateState is invoked by grpc to push a subConn state update to the
+// underlying balancer.
+func (acbw *acBalancerWrapper) updateState(s connectivity.State, err error) {
+ acbw.ccb.serializer.Schedule(func(ctx context.Context) {
+ if ctx.Err() != nil || acbw.ccb.balancer == nil {
+ return
+ }
+ // Even though it is optional for balancers, gracefulswitch ensures
+ // opts.StateListener is set, so this cannot ever be nil.
+ // TODO: delete this comment when UpdateSubConnState is removed.
+ acbw.stateListener(balancer.SubConnState{ConnectivityState: s, ConnectionError: err})
+ })
+}
+
func (acbw *acBalancerWrapper) String() string {
return fmt.Sprintf("SubConn(id:%d)", acbw.ac.channelzID.Int())
}
@@ -398,6 +315,10 @@ func (acbw *acBalancerWrapper) Connect() {
go acbw.ac.connect()
}
+func (acbw *acBalancerWrapper) Shutdown() {
+ acbw.ccb.cc.removeAddrConn(acbw.ac, errConnDrain)
+}
+
// NewStream begins a streaming RPC on the addrConn. If the addrConn is not
// ready, blocks until it is or ctx expires. Returns an error when the context
// expires or the addrConn is shut down.
@@ -411,7 +332,7 @@ func (acbw *acBalancerWrapper) NewStream(ctx context.Context, desc *StreamDesc,
// Invoke performs a unary RPC. If the addrConn is not ready, returns
// errSubConnNotReady.
-func (acbw *acBalancerWrapper) Invoke(ctx context.Context, method string, args interface{}, reply interface{}, opts ...CallOption) error {
+func (acbw *acBalancerWrapper) Invoke(ctx context.Context, method string, args any, reply any, opts ...CallOption) error {
cs, err := acbw.NewStream(ctx, unaryStreamDesc, method, opts...)
if err != nil {
return err
diff --git a/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go b/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go
index ec2c2fa1..e9e97d45 100644
--- a/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go
+++ b/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go
@@ -18,7 +18,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.30.0
+// protoc-gen-go v1.31.0
// protoc v4.22.0
// source: grpc/binlog/v1/binarylog.proto
@@ -430,7 +430,7 @@ type ClientHeader struct {
MethodName string `protobuf:"bytes,2,opt,name=method_name,json=methodName,proto3" json:"method_name,omitempty"`
// A single process may be used to run multiple virtual
// servers with different identities.
- // The authority is the name of such a server identitiy.
+ // The authority is the name of such a server identity.
// It is typically a portion of the URI in the form of
// or : .
Authority string `protobuf:"bytes,3,opt,name=authority,proto3" json:"authority,omitempty"`
diff --git a/vendor/google.golang.org/grpc/call.go b/vendor/google.golang.org/grpc/call.go
index e6a1dc5d..788c89c1 100644
--- a/vendor/google.golang.org/grpc/call.go
+++ b/vendor/google.golang.org/grpc/call.go
@@ -26,12 +26,7 @@ import (
// received. This is typically called by generated code.
//
// All errors returned by Invoke are compatible with the status package.
-func (cc *ClientConn) Invoke(ctx context.Context, method string, args, reply interface{}, opts ...CallOption) error {
- if err := cc.idlenessMgr.onCallBegin(); err != nil {
- return err
- }
- defer cc.idlenessMgr.onCallEnd()
-
+func (cc *ClientConn) Invoke(ctx context.Context, method string, args, reply any, opts ...CallOption) error {
// allow interceptor to see all applicable call options, which means those
// configured as defaults from dial option as well as per-call options
opts = combine(cc.dopts.callOptions, opts)
@@ -61,13 +56,13 @@ func combine(o1 []CallOption, o2 []CallOption) []CallOption {
// received. This is typically called by generated code.
//
// DEPRECATED: Use ClientConn.Invoke instead.
-func Invoke(ctx context.Context, method string, args, reply interface{}, cc *ClientConn, opts ...CallOption) error {
+func Invoke(ctx context.Context, method string, args, reply any, cc *ClientConn, opts ...CallOption) error {
return cc.Invoke(ctx, method, args, reply, opts...)
}
var unaryStreamDesc = &StreamDesc{ServerStreams: false, ClientStreams: false}
-func invoke(ctx context.Context, method string, req, reply interface{}, cc *ClientConn, opts ...CallOption) error {
+func invoke(ctx context.Context, method string, req, reply any, cc *ClientConn, opts ...CallOption) error {
cs, err := newClientStream(ctx, unaryStreamDesc, cc, method, opts...)
if err != nil {
return err
diff --git a/vendor/google.golang.org/grpc/clientconn.go b/vendor/google.golang.org/grpc/clientconn.go
index 95a7459b..f6e815e6 100644
--- a/vendor/google.golang.org/grpc/clientconn.go
+++ b/vendor/google.golang.org/grpc/clientconn.go
@@ -33,10 +33,11 @@ import (
"google.golang.org/grpc/balancer/base"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/connectivity"
- "google.golang.org/grpc/credentials"
- "google.golang.org/grpc/internal/backoff"
+ "google.golang.org/grpc/internal"
"google.golang.org/grpc/internal/channelz"
"google.golang.org/grpc/internal/grpcsync"
+ "google.golang.org/grpc/internal/idle"
+ "google.golang.org/grpc/internal/pretty"
iresolver "google.golang.org/grpc/internal/resolver"
"google.golang.org/grpc/internal/transport"
"google.golang.org/grpc/keepalive"
@@ -45,16 +46,14 @@ import (
"google.golang.org/grpc/status"
_ "google.golang.org/grpc/balancer/roundrobin" // To register roundrobin.
- _ "google.golang.org/grpc/internal/resolver/dns" // To register dns resolver.
_ "google.golang.org/grpc/internal/resolver/passthrough" // To register passthrough resolver.
_ "google.golang.org/grpc/internal/resolver/unix" // To register unix resolver.
+ _ "google.golang.org/grpc/resolver/dns" // To register dns resolver.
)
const (
// minimum time to give a connection to complete
minConnectTimeout = 20 * time.Second
- // must match grpclbName in grpclb/grpclb.go
- grpclbName = "grpclb"
)
var (
@@ -118,48 +117,20 @@ func (dcs *defaultConfigSelector) SelectConfig(rpcInfo iresolver.RPCInfo) (*ires
}, nil
}
-// DialContext creates a client connection to the given target. By default, it's
-// a non-blocking dial (the function won't wait for connections to be
-// established, and connecting happens in the background). To make it a blocking
-// dial, use WithBlock() dial option.
-//
-// In the non-blocking case, the ctx does not act against the connection. It
-// only controls the setup steps.
-//
-// In the blocking case, ctx can be used to cancel or expire the pending
-// connection. Once this function returns, the cancellation and expiration of
-// ctx will be noop. Users should call ClientConn.Close to terminate all the
-// pending operations after this function returns.
-//
-// The target name syntax is defined in
-// https://github.com/grpc/grpc/blob/master/doc/naming.md.
-// e.g. to use dns resolver, a "dns:///" prefix should be applied to the target.
-func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *ClientConn, err error) {
+// newClient returns a new client in idle mode.
+func newClient(target string, opts ...DialOption) (conn *ClientConn, err error) {
cc := &ClientConn{
target: target,
- csMgr: &connectivityStateManager{},
conns: make(map[*addrConn]struct{}),
dopts: defaultDialOptions(),
czData: new(channelzData),
}
- // We start the channel off in idle mode, but kick it out of idle at the end
- // of this method, instead of waiting for the first RPC. Other gRPC
- // implementations do wait for the first RPC to kick the channel out of
- // idle. But doing so would be a major behavior change for our users who are
- // used to seeing the channel active after Dial.
- //
- // Taking this approach of kicking it out of idle at the end of this method
- // allows us to share the code between channel creation and exiting idle
- // mode. This will also make it easy for us to switch to starting the
- // channel off in idle, if at all we ever get to do that.
- cc.idlenessState = ccIdlenessStateIdle
-
cc.retryThrottler.Store((*retryThrottler)(nil))
cc.safeConfigSelector.UpdateConfigSelector(&defaultConfigSelector{nil})
cc.ctx, cc.cancel = context.WithCancel(context.Background())
- cc.exitIdleCond = sync.NewCond(&cc.mu)
+ // Apply dial options.
disableGlobalOpts := false
for _, opt := range opts {
if _, ok := opt.(*disableGlobalDialOptions); ok {
@@ -177,19 +148,9 @@ func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *
for _, opt := range opts {
opt.apply(&cc.dopts)
}
-
chainUnaryClientInterceptors(cc)
chainStreamClientInterceptors(cc)
- defer func() {
- if err != nil {
- cc.Close()
- }
- }()
-
- // Register ClientConn with channelz.
- cc.channelzRegistration(target)
-
if err := cc.validateTransportCredentials(); err != nil {
return nil, err
}
@@ -203,10 +164,80 @@ func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *
}
cc.mkp = cc.dopts.copts.KeepaliveParams
- if cc.dopts.copts.UserAgent != "" {
- cc.dopts.copts.UserAgent += " " + grpcUA
- } else {
- cc.dopts.copts.UserAgent = grpcUA
+ // Register ClientConn with channelz.
+ cc.channelzRegistration(target)
+
+ // TODO: Ideally it should be impossible to error from this function after
+ // 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.channelzID)
+ return nil, err
+ }
+ if err = cc.determineAuthority(); err != nil {
+ channelz.RemoveEntry(cc.channelzID)
+ return nil, err
+ }
+
+ cc.csMgr = newConnectivityStateManager(cc.ctx, cc.channelzID)
+ cc.pickerWrapper = newPickerWrapper(cc.dopts.copts.StatsHandlers)
+
+ cc.initIdleStateLocked() // Safe to call without the lock, since nothing else has a reference to cc.
+ cc.idlenessMgr = idle.NewManager((*idler)(cc), cc.dopts.idleTimeout)
+ return cc, nil
+}
+
+// DialContext creates a client connection to the given target. By default, it's
+// a non-blocking dial (the function won't wait for connections to be
+// established, and connecting happens in the background). To make it a blocking
+// dial, use WithBlock() dial option.
+//
+// In the non-blocking case, the ctx does not act against the connection. It
+// only controls the setup steps.
+//
+// In the blocking case, ctx can be used to cancel or expire the pending
+// connection. Once this function returns, the cancellation and expiration of
+// ctx will be noop. Users should call ClientConn.Close to terminate all the
+// pending operations after this function returns.
+//
+// The target name syntax is defined in
+// https://github.com/grpc/grpc/blob/master/doc/naming.md.
+// e.g. to use dns resolver, a "dns:///" prefix should be applied to the target.
+func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *ClientConn, err error) {
+ cc, err := newClient(target, opts...)
+ if err != nil {
+ return nil, err
+ }
+
+ // We start the channel off in idle mode, but kick it out of idle now,
+ // instead of waiting for the first RPC. Other gRPC implementations do wait
+ // for the first RPC to kick the channel out of idle. But doing so would be
+ // a major behavior change for our users who are used to seeing the channel
+ // active after Dial.
+ //
+ // Taking this approach of kicking it out of idle at the end of this method
+ // allows us to share the code between channel creation and exiting idle
+ // mode. This will also make it easy for us to switch to starting the
+ // channel off in idle, i.e. by making newClient exported.
+
+ defer func() {
+ if err != nil {
+ cc.Close()
+ }
+ }()
+
+ // This creates the name resolver, load balancer, etc.
+ if err := cc.idlenessMgr.ExitIdleMode(); err != nil {
+ return nil, err
+ }
+
+ // Return now for non-blocking dials.
+ if !cc.dopts.block {
+ return cc, nil
}
if cc.dopts.timeout > 0 {
@@ -229,49 +260,6 @@ func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *
}
}()
- if cc.dopts.bs == nil {
- cc.dopts.bs = backoff.DefaultExponential
- }
-
- // Determine the resolver to use.
- if err := cc.parseTargetAndFindResolver(); err != nil {
- return nil, err
- }
- if err = cc.determineAuthority(); err != nil {
- return nil, err
- }
-
- if cc.dopts.scChan != nil {
- // Blocking wait for the initial service config.
- select {
- case sc, ok := <-cc.dopts.scChan:
- if ok {
- cc.sc = &sc
- cc.safeConfigSelector.UpdateConfigSelector(&defaultConfigSelector{&sc})
- }
- case <-ctx.Done():
- return nil, ctx.Err()
- }
- }
- if cc.dopts.scChan != nil {
- go cc.scWatcher()
- }
-
- // This creates the name resolver, load balancer, blocking picker etc.
- if err := cc.exitIdleMode(); err != nil {
- return nil, err
- }
-
- // Configure idleness support with configured idle timeout or default idle
- // timeout duration. Idleness can be explicitly disabled by the user, by
- // setting the dial option to 0.
- cc.idlenessMgr = newIdlenessManager(cc, cc.dopts.idleTimeout)
-
- // Return early for non-blocking dials.
- if !cc.dopts.block {
- return cc, nil
- }
-
// A blocking dial blocks until the clientConn is ready.
for {
s := cc.GetState()
@@ -316,117 +304,82 @@ func (cc *ClientConn) addTraceEvent(msg string) {
channelz.AddTraceEvent(logger, cc.channelzID, 0, ted)
}
+type idler ClientConn
+
+func (i *idler) EnterIdleMode() {
+ (*ClientConn)(i).enterIdleMode()
+}
+
+func (i *idler) ExitIdleMode() error {
+ return (*ClientConn)(i).exitIdleMode()
+}
+
// exitIdleMode moves the channel out of idle mode by recreating the name
-// resolver and load balancer.
-func (cc *ClientConn) exitIdleMode() error {
+// resolver and load balancer. This should never be called directly; use
+// cc.idlenessMgr.ExitIdleMode instead.
+func (cc *ClientConn) exitIdleMode() (err error) {
cc.mu.Lock()
if cc.conns == nil {
cc.mu.Unlock()
return errConnClosing
}
- if cc.idlenessState != ccIdlenessStateIdle {
- cc.mu.Unlock()
- logger.Info("ClientConn asked to exit idle mode when not in idle mode")
- return nil
- }
-
- defer func() {
- // When Close() and exitIdleMode() race against each other, one of the
- // following two can happen:
- // - Close() wins the race and runs first. exitIdleMode() runs after, and
- // sees that the ClientConn is already closed and hence returns early.
- // - exitIdleMode() wins the race and runs first and recreates the balancer
- // and releases the lock before recreating the resolver. If Close() runs
- // in this window, it will wait for exitIdleMode to complete.
- //
- // We achieve this synchronization using the below condition variable.
- cc.mu.Lock()
- cc.idlenessState = ccIdlenessStateActive
- cc.exitIdleCond.Signal()
- cc.mu.Unlock()
- }()
-
- cc.idlenessState = ccIdlenessStateExitingIdle
- exitedIdle := false
- if cc.blockingpicker == nil {
- cc.blockingpicker = newPickerWrapper()
- } else {
- cc.blockingpicker.exitIdleMode()
- exitedIdle = true
- }
-
- var credsClone credentials.TransportCredentials
- if creds := cc.dopts.copts.TransportCredentials; creds != nil {
- credsClone = creds.Clone()
- }
- if cc.balancerWrapper == nil {
- cc.balancerWrapper = newCCBalancerWrapper(cc, balancer.BuildOptions{
- DialCreds: credsClone,
- CredsBundle: cc.dopts.copts.CredsBundle,
- Dialer: cc.dopts.copts.Dialer,
- Authority: cc.authority,
- CustomUserAgent: cc.dopts.copts.UserAgent,
- ChannelzParentID: cc.channelzID,
- Target: cc.parsedTarget,
- })
- } else {
- cc.balancerWrapper.exitIdleMode()
- }
- cc.firstResolveEvent = grpcsync.NewEvent()
cc.mu.Unlock()
// This needs to be called without cc.mu because this builds a new resolver
- // which might update state or report error inline which needs to be handled
- // by cc.updateResolverState() which also grabs cc.mu.
- if err := cc.initResolverWrapper(credsClone); err != nil {
+ // which might update state or report error inline, which would then need to
+ // acquire cc.mu.
+ if err := cc.resolverWrapper.start(); err != nil {
return err
}
- if exitedIdle {
- cc.addTraceEvent("exiting idle mode")
- }
+ cc.addTraceEvent("exiting idle mode")
return nil
}
+// initIdleStateLocked initializes common state to how it should be while idle.
+func (cc *ClientConn) initIdleStateLocked() {
+ cc.resolverWrapper = newCCResolverWrapper(cc)
+ cc.balancerWrapper = newCCBalancerWrapper(cc)
+ cc.firstResolveEvent = grpcsync.NewEvent()
+ // cc.conns == nil is a proxy for the ClientConn being closed. So, instead
+ // of setting it to nil here, we recreate the map. This also means that we
+ // don't have to do this when exiting idle mode.
+ cc.conns = make(map[*addrConn]struct{})
+}
+
// enterIdleMode puts the channel in idle mode, and as part of it shuts down the
-// name resolver, load balancer and any subchannels.
-func (cc *ClientConn) enterIdleMode() error {
+// name resolver, load balancer, and any subchannels. This should never be
+// called directly; use cc.idlenessMgr.EnterIdleMode instead.
+func (cc *ClientConn) enterIdleMode() {
cc.mu.Lock()
+
if cc.conns == nil {
cc.mu.Unlock()
- return ErrClientConnClosing
- }
- if cc.idlenessState != ccIdlenessStateActive {
- logger.Error("ClientConn asked to enter idle mode when not active")
- return nil
+ return
}
- // cc.conns == nil is a proxy for the ClientConn being closed. So, instead
- // of setting it to nil here, we recreate the map. This also means that we
- // don't have to do this when exiting idle mode.
conns := cc.conns
- cc.conns = make(map[*addrConn]struct{})
- // TODO: Currently, we close the resolver wrapper upon entering idle mode
- // and create a new one upon exiting idle mode. This means that the
- // `cc.resolverWrapper` field would be overwritten everytime we exit idle
- // mode. While this means that we need to hold `cc.mu` when accessing
- // `cc.resolverWrapper`, it makes the code simpler in the wrapper. We should
- // try to do the same for the balancer and picker wrappers too.
- cc.resolverWrapper.close()
- cc.blockingpicker.enterIdleMode()
- cc.balancerWrapper.enterIdleMode()
+ rWrapper := cc.resolverWrapper
+ rWrapper.close()
+ cc.pickerWrapper.reset()
+ bWrapper := cc.balancerWrapper
+ bWrapper.close()
cc.csMgr.updateState(connectivity.Idle)
- cc.idlenessState = ccIdlenessStateIdle
+ cc.addTraceEvent("entering idle mode")
+
+ cc.initIdleStateLocked()
+
cc.mu.Unlock()
- go func() {
- cc.addTraceEvent("entering idle mode")
- for ac := range conns {
- ac.tearDown(errConnIdling)
- }
- }()
- return nil
+ // Block until the name resolver and LB policy are closed.
+ <-rWrapper.serializer.Done()
+ <-bWrapper.serializer.Done()
+
+ // Close all subchannels after the LB policy is closed.
+ for ac := range conns {
+ ac.tearDown(errConnIdling)
+ }
}
// validateTransportCredentials performs a series of checks on the configured
@@ -474,7 +427,6 @@ func (cc *ClientConn) validateTransportCredentials() error {
func (cc *ClientConn) channelzRegistration(target string) {
cc.channelzID = channelz.RegisterChannel(&channelzChannel{cc}, cc.dopts.channelzParentID, target)
cc.addTraceEvent("created")
- cc.csMgr.channelzID = cc.channelzID
}
// chainUnaryClientInterceptors chains all unary client interceptors into one.
@@ -491,7 +443,7 @@ func chainUnaryClientInterceptors(cc *ClientConn) {
} else if len(interceptors) == 1 {
chainedInt = interceptors[0]
} else {
- chainedInt = func(ctx context.Context, method string, req, reply interface{}, cc *ClientConn, invoker UnaryInvoker, opts ...CallOption) error {
+ chainedInt = func(ctx context.Context, method string, req, reply any, cc *ClientConn, invoker UnaryInvoker, opts ...CallOption) error {
return interceptors[0](ctx, method, req, reply, cc, getChainUnaryInvoker(interceptors, 0, invoker), opts...)
}
}
@@ -503,7 +455,7 @@ func getChainUnaryInvoker(interceptors []UnaryClientInterceptor, curr int, final
if curr == len(interceptors)-1 {
return finalInvoker
}
- return func(ctx context.Context, method string, req, reply interface{}, cc *ClientConn, opts ...CallOption) error {
+ return func(ctx context.Context, method string, req, reply any, cc *ClientConn, opts ...CallOption) error {
return interceptors[curr+1](ctx, method, req, reply, cc, getChainUnaryInvoker(interceptors, curr+1, finalInvoker), opts...)
}
}
@@ -539,13 +491,27 @@ func getChainStreamer(interceptors []StreamClientInterceptor, curr int, finalStr
}
}
+// newConnectivityStateManager creates an connectivityStateManager with
+// the specified id.
+func newConnectivityStateManager(ctx context.Context, id *channelz.Identifier) *connectivityStateManager {
+ return &connectivityStateManager{
+ channelzID: id,
+ pubSub: grpcsync.NewPubSub(ctx),
+ }
+}
+
// connectivityStateManager keeps the connectivity.State of ClientConn.
// This struct will eventually be exported so the balancers can access it.
+//
+// TODO: If possible, get rid of the `connectivityStateManager` type, and
+// provide this functionality using the `PubSub`, to avoid keeping track of
+// the connectivity state at two places.
type connectivityStateManager struct {
mu sync.Mutex
state connectivity.State
notifyChan chan struct{}
channelzID *channelz.Identifier
+ pubSub *grpcsync.PubSub
}
// updateState updates the connectivity.State of ClientConn.
@@ -561,6 +527,8 @@ func (csm *connectivityStateManager) updateState(state connectivity.State) {
return
}
csm.state = state
+ csm.pubSub.Publish(state)
+
channelz.Infof(logger, csm.channelzID, "Channel Connectivity change to %v", state)
if csm.notifyChan != nil {
// There are other goroutines waiting on this channel.
@@ -590,7 +558,7 @@ func (csm *connectivityStateManager) getNotifyChan() <-chan struct{} {
type ClientConnInterface interface {
// Invoke performs a unary RPC and returns after the response is received
// into reply.
- Invoke(ctx context.Context, method string, args interface{}, reply interface{}, opts ...CallOption) error
+ Invoke(ctx context.Context, method string, args any, reply any, opts ...CallOption) error
// NewStream begins a streaming RPC.
NewStream(ctx context.Context, desc *StreamDesc, method string, opts ...CallOption) (ClientStream, error)
}
@@ -621,53 +589,35 @@ type ClientConn struct {
dopts dialOptions // Default and user specified dial options.
channelzID *channelz.Identifier // Channelz identifier for the channel.
resolverBuilder resolver.Builder // See parseTargetAndFindResolver().
- balancerWrapper *ccBalancerWrapper // Uses gracefulswitch.balancer underneath.
- idlenessMgr idlenessManager
+ idlenessMgr *idle.Manager
// The following provide their own synchronization, and therefore don't
// require cc.mu to be held to access them.
csMgr *connectivityStateManager
- blockingpicker *pickerWrapper
+ pickerWrapper *pickerWrapper
safeConfigSelector iresolver.SafeConfigSelector
czData *channelzData
retryThrottler atomic.Value // Updated from service config.
- // firstResolveEvent is used to track whether the name resolver sent us at
- // least one update. RPCs block on this event.
- firstResolveEvent *grpcsync.Event
-
// mu protects the following fields.
// TODO: split mu so the same mutex isn't used for everything.
mu sync.RWMutex
- resolverWrapper *ccResolverWrapper // Initialized in Dial; cleared in Close.
+ resolverWrapper *ccResolverWrapper // Always recreated whenever entering idle to simplify Close.
+ balancerWrapper *ccBalancerWrapper // Always recreated whenever entering idle to simplify Close.
sc *ServiceConfig // Latest service config received from the resolver.
conns map[*addrConn]struct{} // Set to nil on close.
mkp keepalive.ClientParameters // May be updated upon receipt of a GoAway.
- idlenessState ccIdlenessState // Tracks idleness state of the channel.
- exitIdleCond *sync.Cond // Signalled when channel exits idle.
+ // firstResolveEvent is used to track whether the name resolver sent us at
+ // least one update. RPCs block on this event. May be accessed without mu
+ // if we know we cannot be asked to enter idle mode while accessing it (e.g.
+ // when the idle manager has already been closed, or if we are already
+ // entering idle mode).
+ firstResolveEvent *grpcsync.Event
lceMu sync.Mutex // protects lastConnectionError
lastConnectionError error
}
-// ccIdlenessState tracks the idleness state of the channel.
-//
-// Channels start off in `active` and move to `idle` after a period of
-// inactivity. When moving back to `active` upon an incoming RPC, they
-// transition through `exiting_idle`. This state is useful for synchronization
-// with Close().
-//
-// This state tracking is mostly for self-protection. The idlenessManager is
-// expected to keep track of the state as well, and is expected not to call into
-// the ClientConn unnecessarily.
-type ccIdlenessState int8
-
-const (
- ccIdlenessStateActive ccIdlenessState = iota
- ccIdlenessStateIdle
- ccIdlenessStateExitingIdle
-)
-
// WaitForStateChange waits until the connectivity.State of ClientConn changes from sourceState or
// ctx expires. A true value is returned in former case and false in latter.
//
@@ -707,29 +657,15 @@ func (cc *ClientConn) GetState() connectivity.State {
// Notice: This API is EXPERIMENTAL and may be changed or removed in a later
// release.
func (cc *ClientConn) Connect() {
- cc.exitIdleMode()
+ if err := cc.idlenessMgr.ExitIdleMode(); err != nil {
+ cc.addTraceEvent(err.Error())
+ return
+ }
// If the ClientConn was not in idle mode, we need to call ExitIdle on the
// LB policy so that connections can be created.
- cc.balancerWrapper.exitIdleMode()
-}
-
-func (cc *ClientConn) scWatcher() {
- for {
- select {
- case sc, ok := <-cc.dopts.scChan:
- if !ok {
- return
- }
- cc.mu.Lock()
- // TODO: load balance policy runtime change is ignored.
- // We may revisit this decision in the future.
- cc.sc = &sc
- cc.safeConfigSelector.UpdateConfigSelector(&defaultConfigSelector{&sc})
- cc.mu.Unlock()
- case <-cc.ctx.Done():
- return
- }
- }
+ cc.mu.Lock()
+ cc.balancerWrapper.exitIdle()
+ cc.mu.Unlock()
}
// waitForResolvedAddrs blocks until the resolver has provided addresses or the
@@ -759,6 +695,16 @@ func init() {
panic(fmt.Sprintf("impossible error parsing empty service config: %v", cfg.Err))
}
emptyServiceConfig = cfg.Config.(*ServiceConfig)
+
+ internal.SubscribeToConnectivityStateChanges = func(cc *ClientConn, s grpcsync.Subscriber) func() {
+ return cc.csMgr.pubSub.Subscribe(s)
+ }
+ internal.EnterIdleModeForTesting = func(cc *ClientConn) {
+ cc.idlenessMgr.EnterIdleModeForTesting()
+ }
+ internal.ExitIdleModeForTesting = func(cc *ClientConn) error {
+ return cc.idlenessMgr.ExitIdleMode()
+ }
}
func (cc *ClientConn) maybeApplyDefaultServiceConfig(addrs []resolver.Address) {
@@ -773,9 +719,8 @@ func (cc *ClientConn) maybeApplyDefaultServiceConfig(addrs []resolver.Address) {
}
}
-func (cc *ClientConn) updateResolverState(s resolver.State, err error) error {
+func (cc *ClientConn) updateResolverStateAndUnlock(s resolver.State, err error) error {
defer cc.firstResolveEvent.Fire()
- cc.mu.Lock()
// Check if the ClientConn is already closed. Some fields (e.g.
// balancerWrapper) are set to nil when closing the ClientConn, and could
// cause nil pointer panic if we don't have this check.
@@ -821,7 +766,7 @@ func (cc *ClientConn) updateResolverState(s resolver.State, err error) error {
if cc.sc == nil {
// Apply the failing LB only if we haven't received valid service config
// from the name resolver in the past.
- cc.applyFailingLB(s.ServiceConfig)
+ cc.applyFailingLBLocked(s.ServiceConfig)
cc.mu.Unlock()
return ret
}
@@ -843,15 +788,13 @@ func (cc *ClientConn) updateResolverState(s resolver.State, err error) error {
return ret
}
-// applyFailingLB is akin to configuring an LB policy on the channel which
+// applyFailingLBLocked is akin to configuring an LB policy on the channel which
// always fails RPCs. Here, an actual LB policy is not configured, but an always
// erroring picker is configured, which returns errors with information about
// what was invalid in the received service config. A config selector with no
// service config is configured, and the connectivity state of the channel is
// set to TransientFailure.
-//
-// Caller must hold cc.mu.
-func (cc *ClientConn) applyFailingLB(sc *serviceconfig.ParseResult) {
+func (cc *ClientConn) applyFailingLBLocked(sc *serviceconfig.ParseResult) {
var err error
if sc.Err != nil {
err = status.Errorf(codes.Unavailable, "error parsing service config: %v", sc.Err)
@@ -859,22 +802,36 @@ func (cc *ClientConn) applyFailingLB(sc *serviceconfig.ParseResult) {
err = status.Errorf(codes.Unavailable, "illegal service config type: %T", sc.Config)
}
cc.safeConfigSelector.UpdateConfigSelector(&defaultConfigSelector{nil})
- cc.blockingpicker.updatePicker(base.NewErrPicker(err))
+ cc.pickerWrapper.updatePicker(base.NewErrPicker(err))
cc.csMgr.updateState(connectivity.TransientFailure)
}
-func (cc *ClientConn) handleSubConnStateChange(sc balancer.SubConn, s connectivity.State, err error) {
- cc.balancerWrapper.updateSubConnState(sc, s, err)
+// Makes a copy of the input addresses slice and clears out the balancer
+// attributes field. Addresses are passed during subconn creation and address
+// update operations. In both cases, we will clear the balancer attributes by
+// calling this function, and therefore we will be able to use the Equal method
+// provided by the resolver.Address type for comparison.
+func copyAddressesWithoutBalancerAttributes(in []resolver.Address) []resolver.Address {
+ out := make([]resolver.Address, len(in))
+ for i := range in {
+ out[i] = in[i]
+ out[i].BalancerAttributes = nil
+ }
+ return out
}
-// newAddrConn creates an addrConn for addrs and adds it to cc.conns.
+// newAddrConnLocked creates an addrConn for addrs and adds it to cc.conns.
//
// Caller needs to make sure len(addrs) > 0.
-func (cc *ClientConn) newAddrConn(addrs []resolver.Address, opts balancer.NewSubConnOptions) (*addrConn, error) {
+func (cc *ClientConn) newAddrConnLocked(addrs []resolver.Address, opts balancer.NewSubConnOptions) (*addrConn, error) {
+ if cc.conns == nil {
+ return nil, ErrClientConnClosing
+ }
+
ac := &addrConn{
state: connectivity.Idle,
cc: cc,
- addrs: addrs,
+ addrs: copyAddressesWithoutBalancerAttributes(addrs),
scopts: opts,
dopts: cc.dopts,
czData: new(channelzData),
@@ -882,12 +839,6 @@ func (cc *ClientConn) newAddrConn(addrs []resolver.Address, opts balancer.NewSub
stateChan: make(chan struct{}),
}
ac.ctx, ac.cancel = context.WithCancel(cc.ctx)
- // Track ac in cc. This needs to be done before any getTransport(...) is called.
- cc.mu.Lock()
- defer cc.mu.Unlock()
- if cc.conns == nil {
- return nil, ErrClientConnClosing
- }
var err error
ac.channelzID, err = channelz.RegisterSubChannel(ac, cc.channelzID, "")
@@ -903,6 +854,7 @@ func (cc *ClientConn) newAddrConn(addrs []resolver.Address, opts balancer.NewSub
},
})
+ // Track ac in cc. This needs to be done before any getTransport(...) is called.
cc.conns[ac] = struct{}{}
return ac, nil
}
@@ -995,8 +947,9 @@ func equalAddresses(a, b []resolver.Address) bool {
// connections or connection attempts.
func (ac *addrConn) updateAddrs(addrs []resolver.Address) {
ac.mu.Lock()
- channelz.Infof(logger, ac.channelzID, "addrConn: updateAddrs curAddr: %v, addrs: %v", ac.curAddr, addrs)
+ channelz.Infof(logger, ac.channelzID, "addrConn: updateAddrs curAddr: %v, addrs: %v", pretty.ToJSON(ac.curAddr), pretty.ToJSON(addrs))
+ addrs = copyAddressesWithoutBalancerAttributes(addrs)
if equalAddresses(ac.addrs, addrs) {
ac.mu.Unlock()
return
@@ -1031,8 +984,8 @@ func (ac *addrConn) updateAddrs(addrs []resolver.Address) {
ac.cancel()
ac.ctx, ac.cancel = context.WithCancel(ac.cc.ctx)
- // We have to defer here because GracefulClose => Close => onClose, which
- // requires locking ac.mu.
+ // We have to defer here because GracefulClose => onClose, which requires
+ // locking ac.mu.
if ac.transport != nil {
defer ac.transport.GracefulClose()
ac.transport = nil
@@ -1108,7 +1061,7 @@ func (cc *ClientConn) healthCheckConfig() *healthCheckConfig {
}
func (cc *ClientConn) getTransport(ctx context.Context, failfast bool, method string) (transport.ClientTransport, balancer.PickResult, error) {
- return cc.blockingpicker.pick(ctx, failfast, balancer.PickInfo{
+ return cc.pickerWrapper.pick(ctx, failfast, balancer.PickInfo{
Ctx: ctx,
FullMethodName: method,
})
@@ -1137,35 +1090,25 @@ func (cc *ClientConn) applyServiceConfigAndBalancer(sc *ServiceConfig, configSel
}
var newBalancerName string
- if cc.sc != nil && cc.sc.lbConfig != nil {
+ if cc.sc == nil || (cc.sc.lbConfig == nil && cc.sc.LB == nil) {
+ // No service config or no LB policy specified in config.
+ newBalancerName = PickFirstBalancerName
+ } else if cc.sc.lbConfig != nil {
newBalancerName = cc.sc.lbConfig.name
- } else {
- var isGRPCLB bool
- for _, a := range addrs {
- if a.Type == resolver.GRPCLB {
- isGRPCLB = true
- break
- }
- }
- if isGRPCLB {
- newBalancerName = grpclbName
- } else if cc.sc != nil && cc.sc.LB != nil {
- newBalancerName = *cc.sc.LB
- } else {
- newBalancerName = PickFirstBalancerName
- }
+ } else { // cc.sc.LB != nil
+ newBalancerName = *cc.sc.LB
}
cc.balancerWrapper.switchTo(newBalancerName)
}
func (cc *ClientConn) resolveNow(o resolver.ResolveNowOptions) {
cc.mu.RLock()
- r := cc.resolverWrapper
+ cc.resolverWrapper.resolveNow(o)
cc.mu.RUnlock()
- if r == nil {
- return
- }
- go r.resolveNow(o)
+}
+
+func (cc *ClientConn) resolveNowLocked(o resolver.ResolveNowOptions) {
+ cc.resolverWrapper.resolveNow(o)
}
// ResetConnectBackoff wakes up all subchannels in transient failure and causes
@@ -1192,7 +1135,14 @@ func (cc *ClientConn) ResetConnectBackoff() {
// Close tears down the ClientConn and all underlying connections.
func (cc *ClientConn) Close() error {
- defer cc.cancel()
+ defer func() {
+ cc.cancel()
+ <-cc.csMgr.pubSub.Done()
+ }()
+
+ // Prevent calls to enter/exit idle immediately, and ensure we are not
+ // currently entering/exiting idle mode.
+ cc.idlenessMgr.Close()
cc.mu.Lock()
if cc.conns == nil {
@@ -1200,34 +1150,22 @@ func (cc *ClientConn) Close() error {
return ErrClientConnClosing
}
- for cc.idlenessState == ccIdlenessStateExitingIdle {
- cc.exitIdleCond.Wait()
- }
-
conns := cc.conns
cc.conns = nil
cc.csMgr.updateState(connectivity.Shutdown)
- pWrapper := cc.blockingpicker
- rWrapper := cc.resolverWrapper
- bWrapper := cc.balancerWrapper
- idlenessMgr := cc.idlenessMgr
+ // We can safely unlock and continue to access all fields now as
+ // cc.conns==nil, preventing any further operations on cc.
cc.mu.Unlock()
+ cc.resolverWrapper.close()
// The order of closing matters here since the balancer wrapper assumes the
// picker is closed before it is closed.
- if pWrapper != nil {
- pWrapper.close()
- }
- if bWrapper != nil {
- bWrapper.close()
- }
- if rWrapper != nil {
- rWrapper.close()
- }
- if idlenessMgr != nil {
- idlenessMgr.close()
- }
+ cc.pickerWrapper.close()
+ cc.balancerWrapper.close()
+
+ <-cc.resolverWrapper.serializer.Done()
+ <-cc.balancerWrapper.serializer.Done()
for ac := range conns {
ac.tearDown(ErrClientConnClosing)
@@ -1248,7 +1186,7 @@ type addrConn struct {
cc *ClientConn
dopts dialOptions
- acbw balancer.SubConn
+ acbw *acBalancerWrapper
scopts balancer.NewSubConnOptions
// transport is set when there's a viable transport (note: ac state may not be READY as LB channel
@@ -1286,7 +1224,7 @@ func (ac *addrConn) updateConnectivityState(s connectivity.State, lastErr error)
} else {
channelz.Infof(logger, ac.channelzID, "Subchannel Connectivity change to %v, last error: %s", s, lastErr)
}
- ac.cc.handleSubConnStateChange(ac.acbw, s, lastErr)
+ ac.acbw.updateState(s, lastErr)
}
// adjustParams updates parameters used to create transports upon
@@ -1336,12 +1274,14 @@ func (ac *addrConn) resetTransport() {
if err := ac.tryAllAddrs(acCtx, addrs, connectDeadline); err != nil {
ac.cc.resolveNow(resolver.ResolveNowOptions{})
- // After exhausting all addresses, the addrConn enters
- // TRANSIENT_FAILURE.
+ ac.mu.Lock()
if acCtx.Err() != nil {
+ // addrConn was torn down.
+ ac.mu.Unlock()
return
}
- ac.mu.Lock()
+ // After exhausting all addresses, the addrConn enters
+ // TRANSIENT_FAILURE.
ac.updateConnectivityState(connectivity.TransientFailure, err)
// Backoff.
@@ -1537,7 +1477,7 @@ func (ac *addrConn) startHealthCheck(ctx context.Context) {
// Set up the health check helper functions.
currentTr := ac.transport
- newStream := func(method string) (interface{}, error) {
+ newStream := func(method string) (any, error) {
ac.mu.Lock()
if ac.transport != currentTr {
ac.mu.Unlock()
@@ -1625,16 +1565,7 @@ func (ac *addrConn) tearDown(err error) {
ac.updateConnectivityState(connectivity.Shutdown, nil)
ac.cancel()
ac.curAddr = resolver.Address{}
- if err == errConnDrain && curTr != nil {
- // GracefulClose(...) may be executed multiple times when
- // i) receiving multiple GoAway frames from the server; or
- // ii) there are concurrent name resolver/Balancer triggered
- // address removal and GoAway.
- // We have to unlock and re-lock here because GracefulClose => Close => onClose, which requires locking ac.mu.
- ac.mu.Unlock()
- curTr.GracefulClose()
- ac.mu.Lock()
- }
+
channelz.AddTraceEvent(logger, ac.channelzID, 0, &channelz.TraceEventDesc{
Desc: "Subchannel deleted",
Severity: channelz.CtInfo,
@@ -1648,6 +1579,29 @@ func (ac *addrConn) tearDown(err error) {
// being deleted right away.
channelz.RemoveEntry(ac.channelzID)
ac.mu.Unlock()
+
+ // We have to release the lock before the call to GracefulClose/Close here
+ // because both of them call onClose(), which requires locking ac.mu.
+ if curTr != nil {
+ if err == errConnDrain {
+ // Close the transport gracefully when the subConn is being shutdown.
+ //
+ // GracefulClose() may be executed multiple times if:
+ // - multiple GoAway frames are received from the server
+ // - there are concurrent name resolver or balancer triggered
+ // address removal and GoAway
+ curTr.GracefulClose()
+ } else {
+ // Hard close the transport when the channel is entering idle or is
+ // being shutdown. In the case where the channel is being shutdown,
+ // closing of transports is also taken care of by cancelation of cc.ctx.
+ // But in the case where the channel is entering idle, we need to
+ // explicitly close the transports here. Instead of distinguishing
+ // between these two cases, it is simpler to close the transport
+ // unconditionally here.
+ curTr.Close(err)
+ }
+ }
}
func (ac *addrConn) getState() connectivity.State {
@@ -1774,7 +1728,7 @@ func (cc *ClientConn) parseTargetAndFindResolver() error {
if err != nil {
channelz.Infof(logger, cc.channelzID, "dial target %q parse failed: %v", cc.target, err)
} else {
- channelz.Infof(logger, cc.channelzID, "parsed dial target is: %+v", parsedTarget)
+ channelz.Infof(logger, cc.channelzID, "parsed dial target is: %#v", parsedTarget)
rb = cc.getResolver(parsedTarget.URL.Scheme)
if rb != nil {
cc.parsedTarget = parsedTarget
@@ -1807,19 +1761,70 @@ func (cc *ClientConn) parseTargetAndFindResolver() error {
}
// parseTarget uses RFC 3986 semantics to parse the given target into a
-// resolver.Target struct containing scheme, authority and url. Query
-// params are stripped from the endpoint.
+// resolver.Target struct containing url. Query params are stripped from the
+// endpoint.
func parseTarget(target string) (resolver.Target, error) {
u, err := url.Parse(target)
if err != nil {
return resolver.Target{}, err
}
- return resolver.Target{
- Scheme: u.Scheme,
- Authority: u.Host,
- URL: *u,
- }, nil
+ return resolver.Target{URL: *u}, nil
+}
+
+func encodeAuthority(authority string) string {
+ const upperhex = "0123456789ABCDEF"
+
+ // Return for characters that must be escaped as per
+ // Valid chars are mentioned here:
+ // https://datatracker.ietf.org/doc/html/rfc3986#section-3.2
+ shouldEscape := func(c byte) bool {
+ // Alphanum are always allowed.
+ if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' {
+ return false
+ }
+ switch c {
+ case '-', '_', '.', '~': // Unreserved characters
+ return false
+ case '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=': // Subdelim characters
+ return false
+ case ':', '[', ']', '@': // Authority related delimeters
+ return false
+ }
+ // Everything else must be escaped.
+ return true
+ }
+
+ hexCount := 0
+ for i := 0; i < len(authority); i++ {
+ c := authority[i]
+ if shouldEscape(c) {
+ hexCount++
+ }
+ }
+
+ if hexCount == 0 {
+ return authority
+ }
+
+ required := len(authority) + 2*hexCount
+ t := make([]byte, required)
+
+ j := 0
+ // This logic is a barebones version of escape in the go net/url library.
+ for i := 0; i < len(authority); i++ {
+ switch c := authority[i]; {
+ case shouldEscape(c):
+ t[j] = '%'
+ t[j+1] = upperhex[c>>4]
+ t[j+2] = upperhex[c&15]
+ j += 3
+ default:
+ t[j] = authority[i]
+ j++
+ }
+ }
+ return string(t)
}
// Determine channel authority. The order of precedence is as follows:
@@ -1855,54 +1860,17 @@ func (cc *ClientConn) determineAuthority() error {
}
endpoint := cc.parsedTarget.Endpoint()
- target := cc.target
- switch {
- case authorityFromDialOption != "":
+ if authorityFromDialOption != "" {
cc.authority = authorityFromDialOption
- case authorityFromCreds != "":
+ } else if authorityFromCreds != "" {
cc.authority = authorityFromCreds
- case strings.HasPrefix(target, "unix:") || strings.HasPrefix(target, "unix-abstract:"):
- // TODO: remove when the unix resolver implements optional interface to
- // return channel authority.
- cc.authority = "localhost"
- case strings.HasPrefix(endpoint, ":"):
+ } else if auth, ok := cc.resolverBuilder.(resolver.AuthorityOverrider); ok {
+ cc.authority = auth.OverrideAuthority(cc.parsedTarget)
+ } else if strings.HasPrefix(endpoint, ":") {
cc.authority = "localhost" + endpoint
- default:
- // TODO: Define an optional interface on the resolver builder to return
- // the channel authority given the user's dial target. For resolvers
- // which don't implement this interface, we will use the endpoint from
- // "scheme://authority/endpoint" as the default authority.
- cc.authority = endpoint
+ } else {
+ cc.authority = encodeAuthority(endpoint)
}
channelz.Infof(logger, cc.channelzID, "Channel authority set to %q", cc.authority)
return nil
}
-
-// initResolverWrapper creates a ccResolverWrapper, which builds the name
-// resolver. This method grabs the lock to assign the newly built resolver
-// wrapper to the cc.resolverWrapper field.
-func (cc *ClientConn) initResolverWrapper(creds credentials.TransportCredentials) error {
- rw, err := newCCResolverWrapper(cc, ccResolverWrapperOpts{
- target: cc.parsedTarget,
- builder: cc.resolverBuilder,
- bOpts: resolver.BuildOptions{
- DisableServiceConfig: cc.dopts.disableServiceConfig,
- DialCreds: creds,
- CredsBundle: cc.dopts.copts.CredsBundle,
- Dialer: cc.dopts.copts.Dialer,
- },
- channelzID: cc.channelzID,
- })
- if err != nil {
- return fmt.Errorf("failed to build resolver: %v", err)
- }
- // Resolver implementations may report state update or error inline when
- // built (or right after), and this is handled in cc.updateResolverState.
- // Also, an error from the resolver might lead to a re-resolution request
- // from the balancer, which is handled in resolveNow() where
- // `cc.resolverWrapper` is accessed. Hence, we need to hold the lock here.
- cc.mu.Lock()
- cc.resolverWrapper = rw
- cc.mu.Unlock()
- return nil
-}
diff --git a/vendor/google.golang.org/grpc/codec.go b/vendor/google.golang.org/grpc/codec.go
index 12977654..411e3dfd 100644
--- a/vendor/google.golang.org/grpc/codec.go
+++ b/vendor/google.golang.org/grpc/codec.go
@@ -27,8 +27,8 @@ import (
// omits the name/string, which vary between the two and are not needed for
// anything besides the registry in the encoding package.
type baseCodec interface {
- Marshal(v interface{}) ([]byte, error)
- Unmarshal(data []byte, v interface{}) error
+ Marshal(v any) ([]byte, error)
+ Unmarshal(data []byte, v any) error
}
var _ baseCodec = Codec(nil)
@@ -41,9 +41,9 @@ var _ baseCodec = encoding.Codec(nil)
// Deprecated: use encoding.Codec instead.
type Codec interface {
// Marshal returns the wire format of v.
- Marshal(v interface{}) ([]byte, error)
+ Marshal(v any) ([]byte, error)
// Unmarshal parses the wire format into v.
- Unmarshal(data []byte, v interface{}) error
+ Unmarshal(data []byte, v any) error
// String returns the name of the Codec implementation. This is unused by
// gRPC.
String() string
diff --git a/vendor/google.golang.org/grpc/codes/codes.go b/vendor/google.golang.org/grpc/codes/codes.go
index 11b10618..08476ad1 100644
--- a/vendor/google.golang.org/grpc/codes/codes.go
+++ b/vendor/google.golang.org/grpc/codes/codes.go
@@ -25,7 +25,13 @@ import (
"strconv"
)
-// A Code is an unsigned 32-bit error code as defined in the gRPC spec.
+// A Code is a status code defined according to the [gRPC documentation].
+//
+// Only the codes defined as consts in this package are valid codes. Do not use
+// other code values. Behavior of other codes is implementation-specific and
+// interoperability between implementations is not guaranteed.
+//
+// [gRPC documentation]: https://github.com/grpc/grpc/blob/master/doc/statuscodes.md
type Code uint32
const (
diff --git a/vendor/google.golang.org/grpc/credentials/tls.go b/vendor/google.golang.org/grpc/credentials/tls.go
index 877b7cd2..5dafd34e 100644
--- a/vendor/google.golang.org/grpc/credentials/tls.go
+++ b/vendor/google.golang.org/grpc/credentials/tls.go
@@ -44,10 +44,25 @@ func (t TLSInfo) AuthType() string {
return "tls"
}
+// cipherSuiteLookup returns the string version of a TLS cipher suite ID.
+func cipherSuiteLookup(cipherSuiteID uint16) string {
+ for _, s := range tls.CipherSuites() {
+ if s.ID == cipherSuiteID {
+ return s.Name
+ }
+ }
+ for _, s := range tls.InsecureCipherSuites() {
+ if s.ID == cipherSuiteID {
+ return s.Name
+ }
+ }
+ return fmt.Sprintf("unknown ID: %v", cipherSuiteID)
+}
+
// GetSecurityValue returns security info requested by channelz.
func (t TLSInfo) GetSecurityValue() ChannelzSecurityValue {
v := &TLSChannelzSecurityValue{
- StandardName: cipherSuiteLookup[t.State.CipherSuite],
+ StandardName: cipherSuiteLookup(t.State.CipherSuite),
}
// Currently there's no way to get LocalCertificate info from tls package.
if len(t.State.PeerCertificates) > 0 {
@@ -138,10 +153,39 @@ func (c *tlsCreds) OverrideServerName(serverNameOverride string) error {
return nil
}
+// The following cipher suites are forbidden for use with HTTP/2 by
+// https://datatracker.ietf.org/doc/html/rfc7540#appendix-A
+var tls12ForbiddenCipherSuites = map[uint16]struct{}{
+ tls.TLS_RSA_WITH_AES_128_CBC_SHA: {},
+ tls.TLS_RSA_WITH_AES_256_CBC_SHA: {},
+ tls.TLS_RSA_WITH_AES_128_GCM_SHA256: {},
+ tls.TLS_RSA_WITH_AES_256_GCM_SHA384: {},
+ tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: {},
+ tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: {},
+ tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: {},
+ tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: {},
+}
+
// NewTLS uses c to construct a TransportCredentials based on TLS.
func NewTLS(c *tls.Config) TransportCredentials {
tc := &tlsCreds{credinternal.CloneTLSConfig(c)}
tc.config.NextProtos = credinternal.AppendH2ToNextProtos(tc.config.NextProtos)
+ // If the user did not configure a MinVersion and did not configure a
+ // MaxVersion < 1.2, use MinVersion=1.2, which is required by
+ // https://datatracker.ietf.org/doc/html/rfc7540#section-9.2
+ if tc.config.MinVersion == 0 && (tc.config.MaxVersion == 0 || tc.config.MaxVersion >= tls.VersionTLS12) {
+ tc.config.MinVersion = tls.VersionTLS12
+ }
+ // If the user did not configure CipherSuites, use all "secure" cipher
+ // suites reported by the TLS package, but remove some explicitly forbidden
+ // by https://datatracker.ietf.org/doc/html/rfc7540#appendix-A
+ if tc.config.CipherSuites == nil {
+ for _, cs := range tls.CipherSuites() {
+ if _, ok := tls12ForbiddenCipherSuites[cs.ID]; !ok {
+ tc.config.CipherSuites = append(tc.config.CipherSuites, cs.ID)
+ }
+ }
+ }
return tc
}
@@ -205,32 +249,3 @@ type TLSChannelzSecurityValue struct {
LocalCertificate []byte
RemoteCertificate []byte
}
-
-var cipherSuiteLookup = map[uint16]string{
- tls.TLS_RSA_WITH_RC4_128_SHA: "TLS_RSA_WITH_RC4_128_SHA",
- tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA: "TLS_RSA_WITH_3DES_EDE_CBC_SHA",
- tls.TLS_RSA_WITH_AES_128_CBC_SHA: "TLS_RSA_WITH_AES_128_CBC_SHA",
- tls.TLS_RSA_WITH_AES_256_CBC_SHA: "TLS_RSA_WITH_AES_256_CBC_SHA",
- tls.TLS_RSA_WITH_AES_128_GCM_SHA256: "TLS_RSA_WITH_AES_128_GCM_SHA256",
- tls.TLS_RSA_WITH_AES_256_GCM_SHA384: "TLS_RSA_WITH_AES_256_GCM_SHA384",
- tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
- tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
- tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
- tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA: "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
- tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
- tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
- tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
- tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
- tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
- tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
- tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
- tls.TLS_FALLBACK_SCSV: "TLS_FALLBACK_SCSV",
- tls.TLS_RSA_WITH_AES_128_CBC_SHA256: "TLS_RSA_WITH_AES_128_CBC_SHA256",
- tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
- tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
- tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
- tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
- tls.TLS_AES_128_GCM_SHA256: "TLS_AES_128_GCM_SHA256",
- tls.TLS_AES_256_GCM_SHA384: "TLS_AES_256_GCM_SHA384",
- tls.TLS_CHACHA20_POLY1305_SHA256: "TLS_CHACHA20_POLY1305_SHA256",
-}
diff --git a/vendor/google.golang.org/grpc/dialoptions.go b/vendor/google.golang.org/grpc/dialoptions.go
index 15a3d510..ba242618 100644
--- a/vendor/google.golang.org/grpc/dialoptions.go
+++ b/vendor/google.golang.org/grpc/dialoptions.go
@@ -46,6 +46,7 @@ func init() {
internal.WithBinaryLogger = withBinaryLogger
internal.JoinDialOptions = newJoinDialOption
internal.DisableGlobalDialOptions = newDisableGlobalDialOptions
+ internal.WithRecvBufferPool = withRecvBufferPool
}
// dialOptions configure a Dial call. dialOptions are set by the DialOption
@@ -63,7 +64,6 @@ type dialOptions struct {
block bool
returnLastError bool
timeout time.Duration
- scChan <-chan ServiceConfig
authority string
binaryLogger binarylog.Logger
copts transport.ConnectOptions
@@ -78,6 +78,7 @@ type dialOptions struct {
defaultServiceConfigRawJSON *string
resolvers []resolver.Builder
idleTimeout time.Duration
+ recvBufferPool SharedBufferPool
}
// DialOption configures how we set up the connection.
@@ -138,6 +139,20 @@ func newJoinDialOption(opts ...DialOption) DialOption {
return &joinDialOption{opts: opts}
}
+// WithSharedWriteBuffer allows reusing per-connection transport write buffer.
+// If this option is set to true every connection will release the buffer after
+// flushing the data on the wire.
+//
+// # Experimental
+//
+// Notice: This API is EXPERIMENTAL and may be changed or removed in a
+// later release.
+func WithSharedWriteBuffer(val bool) DialOption {
+ return newFuncDialOption(func(o *dialOptions) {
+ o.copts.SharedWriteBuffer = val
+ })
+}
+
// WithWriteBufferSize determines how much data can be batched before doing a
// write on the wire. The corresponding memory allocation for this buffer will
// be twice the size to keep syscalls low. The default value for this buffer is
@@ -235,19 +250,6 @@ func WithDecompressor(dc Decompressor) DialOption {
})
}
-// WithServiceConfig returns a DialOption which has a channel to read the
-// service configuration.
-//
-// Deprecated: service config should be received through name resolver or via
-// WithDefaultServiceConfig, as specified at
-// https://github.com/grpc/grpc/blob/master/doc/service_config.md. Will be
-// removed in a future 1.x release.
-func WithServiceConfig(c <-chan ServiceConfig) DialOption {
- return newFuncDialOption(func(o *dialOptions) {
- o.scChan = c
- })
-}
-
// WithConnectParams configures the ClientConn to use the provided ConnectParams
// for creating and maintaining connections to servers.
//
@@ -398,6 +400,17 @@ func WithTimeout(d time.Duration) DialOption {
// connections. If FailOnNonTempDialError() is set to true, and an error is
// returned by f, gRPC checks the error's Temporary() method to decide if it
// should try to reconnect to the network address.
+//
+// Note: All supported releases of Go (as of December 2023) override the OS
+// defaults for TCP keepalive time and interval to 15s. To enable TCP keepalive
+// with OS defaults for keepalive time and interval, use a net.Dialer that sets
+// the KeepAlive field to a negative value, and sets the SO_KEEPALIVE socket
+// option to true from the Control field. For a concrete example of how to do
+// this, see internal.NetDialerWithTCPKeepalive().
+//
+// For more information, please see [issue 23459] in the Go github repo.
+//
+// [issue 23459]: https://github.com/golang/go/issues/23459
func WithContextDialer(f func(context.Context, string) (net.Conn, error)) DialOption {
return newFuncDialOption(func(o *dialOptions) {
o.copts.Dialer = f
@@ -472,7 +485,7 @@ func FailOnNonTempDialError(f bool) DialOption {
// the RPCs.
func WithUserAgent(s string) DialOption {
return newFuncDialOption(func(o *dialOptions) {
- o.copts.UserAgent = s
+ o.copts.UserAgent = s + " " + grpcUA
})
}
@@ -622,12 +635,16 @@ func withHealthCheckFunc(f internal.HealthChecker) DialOption {
func defaultDialOptions() dialOptions {
return dialOptions{
- healthCheckFunc: internal.HealthCheckFunc,
copts: transport.ConnectOptions{
- WriteBufferSize: defaultWriteBufSize,
ReadBufferSize: defaultReadBufSize,
+ WriteBufferSize: defaultWriteBufSize,
UseProxy: true,
+ UserAgent: grpcUA,
},
+ bs: internalbackoff.DefaultExponential,
+ healthCheckFunc: internal.HealthCheckFunc,
+ idleTimeout: 30 * time.Minute,
+ recvBufferPool: nopBufferPool{},
}
}
@@ -664,8 +681,8 @@ func WithResolvers(rs ...resolver.Builder) DialOption {
// channel will exit idle mode when the Connect() method is called or when an
// RPC is initiated.
//
-// By default this feature is disabled, which can also be explicitly configured
-// by passing zero to this function.
+// A default timeout of 30 minutes will be used if this dial option is not set
+// at dial time and idleness can be disabled by passing a timeout of zero.
//
// # Experimental
//
@@ -676,3 +693,26 @@ func WithIdleTimeout(d time.Duration) DialOption {
o.idleTimeout = d
})
}
+
+// WithRecvBufferPool returns a DialOption that configures the ClientConn
+// to use the provided shared buffer pool for parsing incoming messages. Depending
+// on the application's workload, this could result in reduced memory allocation.
+//
+// If you are unsure about how to implement a memory pool but want to utilize one,
+// begin with grpc.NewSharedBufferPool.
+//
+// Note: The shared buffer pool feature will not be active if any of the following
+// options are used: WithStatsHandler, EnableTracing, or binary logging. In such
+// cases, the shared buffer pool will be ignored.
+//
+// Deprecated: use experimental.WithRecvBufferPool instead. Will be deleted in
+// v1.60.0 or later.
+func WithRecvBufferPool(bufferPool SharedBufferPool) DialOption {
+ return withRecvBufferPool(bufferPool)
+}
+
+func withRecvBufferPool(bufferPool SharedBufferPool) DialOption {
+ return newFuncDialOption(func(o *dialOptions) {
+ o.recvBufferPool = bufferPool
+ })
+}
diff --git a/vendor/google.golang.org/grpc/encoding/encoding.go b/vendor/google.golang.org/grpc/encoding/encoding.go
index 07a58613..5ebf88d7 100644
--- a/vendor/google.golang.org/grpc/encoding/encoding.go
+++ b/vendor/google.golang.org/grpc/encoding/encoding.go
@@ -38,6 +38,10 @@ const Identity = "identity"
// Compressor is used for compressing and decompressing when sending or
// receiving messages.
+//
+// If a Compressor implements `DecompressedSize(compressedBytes []byte) int`,
+// gRPC will invoke it to determine the size of the buffer allocated for the
+// result of decompression. A return value of -1 indicates unknown size.
type Compressor interface {
// Compress writes the data written to wc to w after compressing it. If an
// error occurs while initializing the compressor, that error is returned
@@ -51,15 +55,6 @@ type Compressor interface {
// coding header. The result must be static; the result cannot change
// between calls.
Name() string
- // If a Compressor implements
- // DecompressedSize(compressedBytes []byte) int, gRPC will call it
- // to determine the size of the buffer allocated for the result of decompression.
- // Return -1 to indicate unknown size.
- //
- // Experimental
- //
- // Notice: This API is EXPERIMENTAL and may be changed or removed in a
- // later release.
}
var registeredCompressor = make(map[string]Compressor)
@@ -90,9 +85,9 @@ func GetCompressor(name string) Compressor {
// methods can be called from concurrent goroutines.
type Codec interface {
// Marshal returns the wire format of v.
- Marshal(v interface{}) ([]byte, error)
+ Marshal(v any) ([]byte, error)
// Unmarshal parses the wire format into v.
- Unmarshal(data []byte, v interface{}) error
+ Unmarshal(data []byte, v any) error
// Name returns the name of the Codec implementation. The returned string
// will be used as part of content type in transmission. The result must be
// static; the result cannot change between calls.
diff --git a/vendor/google.golang.org/grpc/encoding/proto/proto.go b/vendor/google.golang.org/grpc/encoding/proto/proto.go
index 3009b35a..0ee3d3ba 100644
--- a/vendor/google.golang.org/grpc/encoding/proto/proto.go
+++ b/vendor/google.golang.org/grpc/encoding/proto/proto.go
@@ -37,7 +37,7 @@ func init() {
// codec is a Codec implementation with protobuf. It is the default codec for gRPC.
type codec struct{}
-func (codec) Marshal(v interface{}) ([]byte, error) {
+func (codec) Marshal(v any) ([]byte, error) {
vv, ok := v.(proto.Message)
if !ok {
return nil, fmt.Errorf("failed to marshal, message is %T, want proto.Message", v)
@@ -45,7 +45,7 @@ func (codec) Marshal(v interface{}) ([]byte, error) {
return proto.Marshal(vv)
}
-func (codec) Unmarshal(data []byte, v interface{}) error {
+func (codec) Unmarshal(data []byte, v any) error {
vv, ok := v.(proto.Message)
if !ok {
return fmt.Errorf("failed to unmarshal, message is %T, want proto.Message", v)
diff --git a/vendor/google.golang.org/grpc/grpclog/component.go b/vendor/google.golang.org/grpc/grpclog/component.go
index 8358dd6e..ac73c9ce 100644
--- a/vendor/google.golang.org/grpc/grpclog/component.go
+++ b/vendor/google.golang.org/grpc/grpclog/component.go
@@ -31,71 +31,71 @@ type componentData struct {
var cache = map[string]*componentData{}
-func (c *componentData) InfoDepth(depth int, args ...interface{}) {
- args = append([]interface{}{"[" + string(c.name) + "]"}, args...)
+func (c *componentData) InfoDepth(depth int, args ...any) {
+ args = append([]any{"[" + string(c.name) + "]"}, args...)
grpclog.InfoDepth(depth+1, args...)
}
-func (c *componentData) WarningDepth(depth int, args ...interface{}) {
- args = append([]interface{}{"[" + string(c.name) + "]"}, args...)
+func (c *componentData) WarningDepth(depth int, args ...any) {
+ args = append([]any{"[" + string(c.name) + "]"}, args...)
grpclog.WarningDepth(depth+1, args...)
}
-func (c *componentData) ErrorDepth(depth int, args ...interface{}) {
- args = append([]interface{}{"[" + string(c.name) + "]"}, args...)
+func (c *componentData) ErrorDepth(depth int, args ...any) {
+ args = append([]any{"[" + string(c.name) + "]"}, args...)
grpclog.ErrorDepth(depth+1, args...)
}
-func (c *componentData) FatalDepth(depth int, args ...interface{}) {
- args = append([]interface{}{"[" + string(c.name) + "]"}, args...)
+func (c *componentData) FatalDepth(depth int, args ...any) {
+ args = append([]any{"[" + string(c.name) + "]"}, args...)
grpclog.FatalDepth(depth+1, args...)
}
-func (c *componentData) Info(args ...interface{}) {
+func (c *componentData) Info(args ...any) {
c.InfoDepth(1, args...)
}
-func (c *componentData) Warning(args ...interface{}) {
+func (c *componentData) Warning(args ...any) {
c.WarningDepth(1, args...)
}
-func (c *componentData) Error(args ...interface{}) {
+func (c *componentData) Error(args ...any) {
c.ErrorDepth(1, args...)
}
-func (c *componentData) Fatal(args ...interface{}) {
+func (c *componentData) Fatal(args ...any) {
c.FatalDepth(1, args...)
}
-func (c *componentData) Infof(format string, args ...interface{}) {
+func (c *componentData) Infof(format string, args ...any) {
c.InfoDepth(1, fmt.Sprintf(format, args...))
}
-func (c *componentData) Warningf(format string, args ...interface{}) {
+func (c *componentData) Warningf(format string, args ...any) {
c.WarningDepth(1, fmt.Sprintf(format, args...))
}
-func (c *componentData) Errorf(format string, args ...interface{}) {
+func (c *componentData) Errorf(format string, args ...any) {
c.ErrorDepth(1, fmt.Sprintf(format, args...))
}
-func (c *componentData) Fatalf(format string, args ...interface{}) {
+func (c *componentData) Fatalf(format string, args ...any) {
c.FatalDepth(1, fmt.Sprintf(format, args...))
}
-func (c *componentData) Infoln(args ...interface{}) {
+func (c *componentData) Infoln(args ...any) {
c.InfoDepth(1, args...)
}
-func (c *componentData) Warningln(args ...interface{}) {
+func (c *componentData) Warningln(args ...any) {
c.WarningDepth(1, args...)
}
-func (c *componentData) Errorln(args ...interface{}) {
+func (c *componentData) Errorln(args ...any) {
c.ErrorDepth(1, args...)
}
-func (c *componentData) Fatalln(args ...interface{}) {
+func (c *componentData) Fatalln(args ...any) {
c.FatalDepth(1, args...)
}
diff --git a/vendor/google.golang.org/grpc/grpclog/grpclog.go b/vendor/google.golang.org/grpc/grpclog/grpclog.go
index c8bb2be3..16928c9c 100644
--- a/vendor/google.golang.org/grpc/grpclog/grpclog.go
+++ b/vendor/google.golang.org/grpc/grpclog/grpclog.go
@@ -42,53 +42,53 @@ func V(l int) bool {
}
// Info logs to the INFO log.
-func Info(args ...interface{}) {
+func Info(args ...any) {
grpclog.Logger.Info(args...)
}
// Infof logs to the INFO log. Arguments are handled in the manner of fmt.Printf.
-func Infof(format string, args ...interface{}) {
+func Infof(format string, args ...any) {
grpclog.Logger.Infof(format, args...)
}
// Infoln logs to the INFO log. Arguments are handled in the manner of fmt.Println.
-func Infoln(args ...interface{}) {
+func Infoln(args ...any) {
grpclog.Logger.Infoln(args...)
}
// Warning logs to the WARNING log.
-func Warning(args ...interface{}) {
+func Warning(args ...any) {
grpclog.Logger.Warning(args...)
}
// Warningf logs to the WARNING log. Arguments are handled in the manner of fmt.Printf.
-func Warningf(format string, args ...interface{}) {
+func Warningf(format string, args ...any) {
grpclog.Logger.Warningf(format, args...)
}
// Warningln logs to the WARNING log. Arguments are handled in the manner of fmt.Println.
-func Warningln(args ...interface{}) {
+func Warningln(args ...any) {
grpclog.Logger.Warningln(args...)
}
// Error logs to the ERROR log.
-func Error(args ...interface{}) {
+func Error(args ...any) {
grpclog.Logger.Error(args...)
}
// Errorf logs to the ERROR log. Arguments are handled in the manner of fmt.Printf.
-func Errorf(format string, args ...interface{}) {
+func Errorf(format string, args ...any) {
grpclog.Logger.Errorf(format, args...)
}
// Errorln logs to the ERROR log. Arguments are handled in the manner of fmt.Println.
-func Errorln(args ...interface{}) {
+func Errorln(args ...any) {
grpclog.Logger.Errorln(args...)
}
// Fatal logs to the FATAL log. Arguments are handled in the manner of fmt.Print.
// It calls os.Exit() with exit code 1.
-func Fatal(args ...interface{}) {
+func Fatal(args ...any) {
grpclog.Logger.Fatal(args...)
// Make sure fatal logs will exit.
os.Exit(1)
@@ -96,7 +96,7 @@ func Fatal(args ...interface{}) {
// Fatalf logs to the FATAL log. Arguments are handled in the manner of fmt.Printf.
// It calls os.Exit() with exit code 1.
-func Fatalf(format string, args ...interface{}) {
+func Fatalf(format string, args ...any) {
grpclog.Logger.Fatalf(format, args...)
// Make sure fatal logs will exit.
os.Exit(1)
@@ -104,7 +104,7 @@ func Fatalf(format string, args ...interface{}) {
// Fatalln logs to the FATAL log. Arguments are handled in the manner of fmt.Println.
// It calle os.Exit()) with exit code 1.
-func Fatalln(args ...interface{}) {
+func Fatalln(args ...any) {
grpclog.Logger.Fatalln(args...)
// Make sure fatal logs will exit.
os.Exit(1)
@@ -113,20 +113,20 @@ func Fatalln(args ...interface{}) {
// Print prints to the logger. Arguments are handled in the manner of fmt.Print.
//
// Deprecated: use Info.
-func Print(args ...interface{}) {
+func Print(args ...any) {
grpclog.Logger.Info(args...)
}
// Printf prints to the logger. Arguments are handled in the manner of fmt.Printf.
//
// Deprecated: use Infof.
-func Printf(format string, args ...interface{}) {
+func Printf(format string, args ...any) {
grpclog.Logger.Infof(format, args...)
}
// Println prints to the logger. Arguments are handled in the manner of fmt.Println.
//
// Deprecated: use Infoln.
-func Println(args ...interface{}) {
+func Println(args ...any) {
grpclog.Logger.Infoln(args...)
}
diff --git a/vendor/google.golang.org/grpc/grpclog/logger.go b/vendor/google.golang.org/grpc/grpclog/logger.go
index ef06a482..b1674d82 100644
--- a/vendor/google.golang.org/grpc/grpclog/logger.go
+++ b/vendor/google.golang.org/grpc/grpclog/logger.go
@@ -24,12 +24,12 @@ import "google.golang.org/grpc/internal/grpclog"
//
// Deprecated: use LoggerV2.
type Logger interface {
- Fatal(args ...interface{})
- Fatalf(format string, args ...interface{})
- Fatalln(args ...interface{})
- Print(args ...interface{})
- Printf(format string, args ...interface{})
- Println(args ...interface{})
+ Fatal(args ...any)
+ Fatalf(format string, args ...any)
+ Fatalln(args ...any)
+ Print(args ...any)
+ Printf(format string, args ...any)
+ Println(args ...any)
}
// SetLogger sets the logger that is used in grpc. Call only from
@@ -45,39 +45,39 @@ type loggerWrapper struct {
Logger
}
-func (g *loggerWrapper) Info(args ...interface{}) {
+func (g *loggerWrapper) Info(args ...any) {
g.Logger.Print(args...)
}
-func (g *loggerWrapper) Infoln(args ...interface{}) {
+func (g *loggerWrapper) Infoln(args ...any) {
g.Logger.Println(args...)
}
-func (g *loggerWrapper) Infof(format string, args ...interface{}) {
+func (g *loggerWrapper) Infof(format string, args ...any) {
g.Logger.Printf(format, args...)
}
-func (g *loggerWrapper) Warning(args ...interface{}) {
+func (g *loggerWrapper) Warning(args ...any) {
g.Logger.Print(args...)
}
-func (g *loggerWrapper) Warningln(args ...interface{}) {
+func (g *loggerWrapper) Warningln(args ...any) {
g.Logger.Println(args...)
}
-func (g *loggerWrapper) Warningf(format string, args ...interface{}) {
+func (g *loggerWrapper) Warningf(format string, args ...any) {
g.Logger.Printf(format, args...)
}
-func (g *loggerWrapper) Error(args ...interface{}) {
+func (g *loggerWrapper) Error(args ...any) {
g.Logger.Print(args...)
}
-func (g *loggerWrapper) Errorln(args ...interface{}) {
+func (g *loggerWrapper) Errorln(args ...any) {
g.Logger.Println(args...)
}
-func (g *loggerWrapper) Errorf(format string, args ...interface{}) {
+func (g *loggerWrapper) Errorf(format string, args ...any) {
g.Logger.Printf(format, args...)
}
diff --git a/vendor/google.golang.org/grpc/grpclog/loggerv2.go b/vendor/google.golang.org/grpc/grpclog/loggerv2.go
index 5de66e40..ecfd36d7 100644
--- a/vendor/google.golang.org/grpc/grpclog/loggerv2.go
+++ b/vendor/google.golang.org/grpc/grpclog/loggerv2.go
@@ -33,35 +33,35 @@ import (
// LoggerV2 does underlying logging work for grpclog.
type LoggerV2 interface {
// Info logs to INFO log. Arguments are handled in the manner of fmt.Print.
- Info(args ...interface{})
+ Info(args ...any)
// Infoln logs to INFO log. Arguments are handled in the manner of fmt.Println.
- Infoln(args ...interface{})
+ Infoln(args ...any)
// Infof logs to INFO log. Arguments are handled in the manner of fmt.Printf.
- Infof(format string, args ...interface{})
+ Infof(format string, args ...any)
// Warning logs to WARNING log. Arguments are handled in the manner of fmt.Print.
- Warning(args ...interface{})
+ Warning(args ...any)
// Warningln logs to WARNING log. Arguments are handled in the manner of fmt.Println.
- Warningln(args ...interface{})
+ Warningln(args ...any)
// Warningf logs to WARNING log. Arguments are handled in the manner of fmt.Printf.
- Warningf(format string, args ...interface{})
+ Warningf(format string, args ...any)
// Error logs to ERROR log. Arguments are handled in the manner of fmt.Print.
- Error(args ...interface{})
+ Error(args ...any)
// Errorln logs to ERROR log. Arguments are handled in the manner of fmt.Println.
- Errorln(args ...interface{})
+ Errorln(args ...any)
// Errorf logs to ERROR log. Arguments are handled in the manner of fmt.Printf.
- Errorf(format string, args ...interface{})
+ Errorf(format string, args ...any)
// Fatal logs to ERROR log. Arguments are handled in the manner of fmt.Print.
// gRPC ensures that all Fatal logs will exit with os.Exit(1).
// Implementations may also call os.Exit() with a non-zero exit code.
- Fatal(args ...interface{})
+ Fatal(args ...any)
// Fatalln logs to ERROR log. Arguments are handled in the manner of fmt.Println.
// gRPC ensures that all Fatal logs will exit with os.Exit(1).
// Implementations may also call os.Exit() with a non-zero exit code.
- Fatalln(args ...interface{})
+ Fatalln(args ...any)
// Fatalf logs to ERROR log. Arguments are handled in the manner of fmt.Printf.
// gRPC ensures that all Fatal logs will exit with os.Exit(1).
// Implementations may also call os.Exit() with a non-zero exit code.
- Fatalf(format string, args ...interface{})
+ Fatalf(format string, args ...any)
// V reports whether verbosity level l is at least the requested verbose level.
V(l int) bool
}
@@ -182,53 +182,53 @@ func (g *loggerT) output(severity int, s string) {
g.m[severity].Output(2, string(b))
}
-func (g *loggerT) Info(args ...interface{}) {
+func (g *loggerT) Info(args ...any) {
g.output(infoLog, fmt.Sprint(args...))
}
-func (g *loggerT) Infoln(args ...interface{}) {
+func (g *loggerT) Infoln(args ...any) {
g.output(infoLog, fmt.Sprintln(args...))
}
-func (g *loggerT) Infof(format string, args ...interface{}) {
+func (g *loggerT) Infof(format string, args ...any) {
g.output(infoLog, fmt.Sprintf(format, args...))
}
-func (g *loggerT) Warning(args ...interface{}) {
+func (g *loggerT) Warning(args ...any) {
g.output(warningLog, fmt.Sprint(args...))
}
-func (g *loggerT) Warningln(args ...interface{}) {
+func (g *loggerT) Warningln(args ...any) {
g.output(warningLog, fmt.Sprintln(args...))
}
-func (g *loggerT) Warningf(format string, args ...interface{}) {
+func (g *loggerT) Warningf(format string, args ...any) {
g.output(warningLog, fmt.Sprintf(format, args...))
}
-func (g *loggerT) Error(args ...interface{}) {
+func (g *loggerT) Error(args ...any) {
g.output(errorLog, fmt.Sprint(args...))
}
-func (g *loggerT) Errorln(args ...interface{}) {
+func (g *loggerT) Errorln(args ...any) {
g.output(errorLog, fmt.Sprintln(args...))
}
-func (g *loggerT) Errorf(format string, args ...interface{}) {
+func (g *loggerT) Errorf(format string, args ...any) {
g.output(errorLog, fmt.Sprintf(format, args...))
}
-func (g *loggerT) Fatal(args ...interface{}) {
+func (g *loggerT) Fatal(args ...any) {
g.output(fatalLog, fmt.Sprint(args...))
os.Exit(1)
}
-func (g *loggerT) Fatalln(args ...interface{}) {
+func (g *loggerT) Fatalln(args ...any) {
g.output(fatalLog, fmt.Sprintln(args...))
os.Exit(1)
}
-func (g *loggerT) Fatalf(format string, args ...interface{}) {
+func (g *loggerT) Fatalf(format string, args ...any) {
g.output(fatalLog, fmt.Sprintf(format, args...))
os.Exit(1)
}
@@ -248,11 +248,11 @@ func (g *loggerT) V(l int) bool {
type DepthLoggerV2 interface {
LoggerV2
// InfoDepth logs to INFO log at the specified depth. Arguments are handled in the manner of fmt.Println.
- InfoDepth(depth int, args ...interface{})
+ InfoDepth(depth int, args ...any)
// WarningDepth logs to WARNING log at the specified depth. Arguments are handled in the manner of fmt.Println.
- WarningDepth(depth int, args ...interface{})
+ WarningDepth(depth int, args ...any)
// ErrorDepth logs to ERROR log at the specified depth. Arguments are handled in the manner of fmt.Println.
- ErrorDepth(depth int, args ...interface{})
+ ErrorDepth(depth int, args ...any)
// FatalDepth logs to FATAL log at the specified depth. Arguments are handled in the manner of fmt.Println.
- FatalDepth(depth int, args ...interface{})
+ FatalDepth(depth int, args ...any)
}
diff --git a/vendor/google.golang.org/grpc/idle.go b/vendor/google.golang.org/grpc/idle.go
deleted file mode 100644
index dc3dc72f..00000000
--- a/vendor/google.golang.org/grpc/idle.go
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- *
- * Copyright 2023 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 grpc
-
-import (
- "fmt"
- "math"
- "sync"
- "sync/atomic"
- "time"
-)
-
-// For overriding in unit tests.
-var timeAfterFunc = func(d time.Duration, f func()) *time.Timer {
- return time.AfterFunc(d, f)
-}
-
-// idlenessEnforcer is the functionality provided by grpc.ClientConn to enter
-// and exit from idle mode.
-type idlenessEnforcer interface {
- exitIdleMode() error
- enterIdleMode() error
-}
-
-// idlenessManager defines the functionality required to track RPC activity on a
-// channel.
-type idlenessManager interface {
- onCallBegin() error
- onCallEnd()
- close()
-}
-
-type noopIdlenessManager struct{}
-
-func (noopIdlenessManager) onCallBegin() error { return nil }
-func (noopIdlenessManager) onCallEnd() {}
-func (noopIdlenessManager) close() {}
-
-// idlenessManagerImpl implements the idlenessManager interface. It uses atomic
-// operations to synchronize access to shared state and a mutex to guarantee
-// mutual exclusion in a critical section.
-type idlenessManagerImpl struct {
- // State accessed atomically.
- lastCallEndTime int64 // Unix timestamp in nanos; time when the most recent RPC completed.
- activeCallsCount int32 // Count of active RPCs; -math.MaxInt32 means channel is idle or is trying to get there.
- activeSinceLastTimerCheck int32 // Boolean; True if there was an RPC since the last timer callback.
- closed int32 // Boolean; True when the manager is closed.
-
- // Can be accessed without atomics or mutex since these are set at creation
- // time and read-only after that.
- enforcer idlenessEnforcer // Functionality provided by grpc.ClientConn.
- timeout int64 // Idle timeout duration nanos stored as an int64.
-
- // idleMu is used to guarantee mutual exclusion in two scenarios:
- // - Opposing intentions:
- // - a: Idle timeout has fired and handleIdleTimeout() is trying to put
- // the channel in idle mode because the channel has been inactive.
- // - b: At the same time an RPC is made on the channel, and onCallBegin()
- // is trying to prevent the channel from going idle.
- // - Competing intentions:
- // - The channel is in idle mode and there are multiple RPCs starting at
- // the same time, all trying to move the channel out of idle. Only one
- // of them should succeed in doing so, while the other RPCs should
- // piggyback on the first one and be successfully handled.
- idleMu sync.RWMutex
- actuallyIdle bool
- timer *time.Timer
-}
-
-// newIdlenessManager creates a new idleness manager implementation for the
-// given idle timeout.
-func newIdlenessManager(enforcer idlenessEnforcer, idleTimeout time.Duration) idlenessManager {
- if idleTimeout == 0 {
- return noopIdlenessManager{}
- }
-
- i := &idlenessManagerImpl{
- enforcer: enforcer,
- timeout: int64(idleTimeout),
- }
- i.timer = timeAfterFunc(idleTimeout, i.handleIdleTimeout)
- return i
-}
-
-// resetIdleTimer resets the idle timer to the given duration. This method
-// should only be called from the timer callback.
-func (i *idlenessManagerImpl) resetIdleTimer(d time.Duration) {
- i.idleMu.Lock()
- defer i.idleMu.Unlock()
-
- if i.timer == nil {
- // Only close sets timer to nil. We are done.
- return
- }
-
- // It is safe to ignore the return value from Reset() because this method is
- // only ever called from the timer callback, which means the timer has
- // already fired.
- i.timer.Reset(d)
-}
-
-// handleIdleTimeout is the timer callback that is invoked upon expiry of the
-// configured idle timeout. The channel is considered inactive if there are no
-// ongoing calls and no RPC activity since the last time the timer fired.
-func (i *idlenessManagerImpl) handleIdleTimeout() {
- if i.isClosed() {
- return
- }
-
- if atomic.LoadInt32(&i.activeCallsCount) > 0 {
- i.resetIdleTimer(time.Duration(i.timeout))
- return
- }
-
- // There has been activity on the channel since we last got here. Reset the
- // timer and return.
- if atomic.LoadInt32(&i.activeSinceLastTimerCheck) == 1 {
- // Set the timer to fire after a duration of idle timeout, calculated
- // from the time the most recent RPC completed.
- atomic.StoreInt32(&i.activeSinceLastTimerCheck, 0)
- i.resetIdleTimer(time.Duration(atomic.LoadInt64(&i.lastCallEndTime) + i.timeout - time.Now().UnixNano()))
- return
- }
-
- // This CAS operation is extremely likely to succeed given that there has
- // been no activity since the last time we were here. Setting the
- // activeCallsCount to -math.MaxInt32 indicates to onCallBegin() that the
- // channel is either in idle mode or is trying to get there.
- if !atomic.CompareAndSwapInt32(&i.activeCallsCount, 0, -math.MaxInt32) {
- // This CAS operation can fail if an RPC started after we checked for
- // activity at the top of this method, or one was ongoing from before
- // the last time we were here. In both case, reset the timer and return.
- i.resetIdleTimer(time.Duration(i.timeout))
- return
- }
-
- // Now that we've set the active calls count to -math.MaxInt32, it's time to
- // actually move to idle mode.
- if i.tryEnterIdleMode() {
- // Successfully entered idle mode. No timer needed until we exit idle.
- return
- }
-
- // Failed to enter idle mode due to a concurrent RPC that kept the channel
- // active, or because of an error from the channel. Undo the attempt to
- // enter idle, and reset the timer to try again later.
- atomic.AddInt32(&i.activeCallsCount, math.MaxInt32)
- i.resetIdleTimer(time.Duration(i.timeout))
-}
-
-// tryEnterIdleMode instructs the channel to enter idle mode. But before
-// that, it performs a last minute check to ensure that no new RPC has come in,
-// making the channel active.
-//
-// Return value indicates whether or not the channel moved to idle mode.
-//
-// Holds idleMu which ensures mutual exclusion with exitIdleMode.
-func (i *idlenessManagerImpl) tryEnterIdleMode() bool {
- i.idleMu.Lock()
- defer i.idleMu.Unlock()
-
- if atomic.LoadInt32(&i.activeCallsCount) != -math.MaxInt32 {
- // We raced and lost to a new RPC. Very rare, but stop entering idle.
- return false
- }
- if atomic.LoadInt32(&i.activeSinceLastTimerCheck) == 1 {
- // An very short RPC could have come in (and also finished) after we
- // checked for calls count and activity in handleIdleTimeout(), but
- // before the CAS operation. So, we need to check for activity again.
- return false
- }
-
- // No new RPCs have come in since we last set the active calls count value
- // -math.MaxInt32 in the timer callback. And since we have the lock, it is
- // safe to enter idle mode now.
- if err := i.enforcer.enterIdleMode(); err != nil {
- logger.Errorf("Failed to enter idle mode: %v", err)
- return false
- }
-
- // Successfully entered idle mode.
- i.actuallyIdle = true
- return true
-}
-
-// onCallBegin is invoked at the start of every RPC.
-func (i *idlenessManagerImpl) onCallBegin() error {
- if i.isClosed() {
- return nil
- }
-
- if atomic.AddInt32(&i.activeCallsCount, 1) > 0 {
- // Channel is not idle now. Set the activity bit and allow the call.
- atomic.StoreInt32(&i.activeSinceLastTimerCheck, 1)
- return nil
- }
-
- // Channel is either in idle mode or is in the process of moving to idle
- // mode. Attempt to exit idle mode to allow this RPC.
- if err := i.exitIdleMode(); err != nil {
- // Undo the increment to calls count, and return an error causing the
- // RPC to fail.
- atomic.AddInt32(&i.activeCallsCount, -1)
- return err
- }
-
- atomic.StoreInt32(&i.activeSinceLastTimerCheck, 1)
- return nil
-}
-
-// exitIdleMode instructs the channel to exit idle mode.
-//
-// Holds idleMu which ensures mutual exclusion with tryEnterIdleMode.
-func (i *idlenessManagerImpl) exitIdleMode() error {
- i.idleMu.Lock()
- defer i.idleMu.Unlock()
-
- if !i.actuallyIdle {
- // This can happen in two scenarios:
- // - handleIdleTimeout() set the calls count to -math.MaxInt32 and called
- // tryEnterIdleMode(). But before the latter could grab the lock, an RPC
- // came in and onCallBegin() noticed that the calls count is negative.
- // - Channel is in idle mode, and multiple new RPCs come in at the same
- // time, all of them notice a negative calls count in onCallBegin and get
- // here. The first one to get the lock would got the channel to exit idle.
- //
- // Either way, nothing to do here.
- return nil
- }
-
- if err := i.enforcer.exitIdleMode(); err != nil {
- return fmt.Errorf("channel failed to exit idle mode: %v", err)
- }
-
- // Undo the idle entry process. This also respects any new RPC attempts.
- atomic.AddInt32(&i.activeCallsCount, math.MaxInt32)
- i.actuallyIdle = false
-
- // Start a new timer to fire after the configured idle timeout.
- i.timer = timeAfterFunc(time.Duration(i.timeout), i.handleIdleTimeout)
- return nil
-}
-
-// onCallEnd is invoked at the end of every RPC.
-func (i *idlenessManagerImpl) onCallEnd() {
- if i.isClosed() {
- return
- }
-
- // Record the time at which the most recent call finished.
- atomic.StoreInt64(&i.lastCallEndTime, time.Now().UnixNano())
-
- // Decrement the active calls count. This count can temporarily go negative
- // when the timer callback is in the process of moving the channel to idle
- // mode, but one or more RPCs come in and complete before the timer callback
- // can get done with the process of moving to idle mode.
- atomic.AddInt32(&i.activeCallsCount, -1)
-}
-
-func (i *idlenessManagerImpl) isClosed() bool {
- return atomic.LoadInt32(&i.closed) == 1
-}
-
-func (i *idlenessManagerImpl) close() {
- atomic.StoreInt32(&i.closed, 1)
-
- i.idleMu.Lock()
- i.timer.Stop()
- i.timer = nil
- i.idleMu.Unlock()
-}
diff --git a/vendor/google.golang.org/grpc/interceptor.go b/vendor/google.golang.org/grpc/interceptor.go
index bb96ef57..877d78fc 100644
--- a/vendor/google.golang.org/grpc/interceptor.go
+++ b/vendor/google.golang.org/grpc/interceptor.go
@@ -23,7 +23,7 @@ import (
)
// UnaryInvoker is called by UnaryClientInterceptor to complete RPCs.
-type UnaryInvoker func(ctx context.Context, method string, req, reply interface{}, cc *ClientConn, opts ...CallOption) error
+type UnaryInvoker func(ctx context.Context, method string, req, reply any, cc *ClientConn, opts ...CallOption) error
// UnaryClientInterceptor intercepts the execution of a unary RPC on the client.
// Unary interceptors can be specified as a DialOption, using
@@ -40,7 +40,7 @@ type UnaryInvoker func(ctx context.Context, method string, req, reply interface{
// defaults from the ClientConn as well as per-call options.
//
// The returned error must be compatible with the status package.
-type UnaryClientInterceptor func(ctx context.Context, method string, req, reply interface{}, cc *ClientConn, invoker UnaryInvoker, opts ...CallOption) error
+type UnaryClientInterceptor func(ctx context.Context, method string, req, reply any, cc *ClientConn, invoker UnaryInvoker, opts ...CallOption) error
// Streamer is called by StreamClientInterceptor to create a ClientStream.
type Streamer func(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, opts ...CallOption) (ClientStream, error)
@@ -66,7 +66,7 @@ type StreamClientInterceptor func(ctx context.Context, desc *StreamDesc, cc *Cli
// server side. All per-rpc information may be mutated by the interceptor.
type UnaryServerInfo struct {
// Server is the service implementation the user provides. This is read-only.
- Server interface{}
+ Server any
// FullMethod is the full RPC method string, i.e., /package.service/method.
FullMethod string
}
@@ -78,13 +78,13 @@ type UnaryServerInfo struct {
// status package, or be one of the context errors. Otherwise, gRPC will use
// codes.Unknown as the status code and err.Error() as the status message of the
// RPC.
-type UnaryHandler func(ctx context.Context, req interface{}) (interface{}, error)
+type UnaryHandler func(ctx context.Context, req any) (any, error)
// UnaryServerInterceptor provides a hook to intercept the execution of a unary RPC on the server. info
// contains all the information of this RPC the interceptor can operate on. And handler is the wrapper
// of the service method implementation. It is the responsibility of the interceptor to invoke handler
// to complete the RPC.
-type UnaryServerInterceptor func(ctx context.Context, req interface{}, info *UnaryServerInfo, handler UnaryHandler) (resp interface{}, err error)
+type UnaryServerInterceptor func(ctx context.Context, req any, info *UnaryServerInfo, handler UnaryHandler) (resp any, err error)
// StreamServerInfo consists of various information about a streaming RPC on
// server side. All per-rpc information may be mutated by the interceptor.
@@ -101,4 +101,4 @@ type StreamServerInfo struct {
// info contains all the information of this RPC the interceptor can operate on. And handler is the
// service method implementation. It is the responsibility of the interceptor to invoke handler to
// complete the RPC.
-type StreamServerInterceptor func(srv interface{}, ss ServerStream, info *StreamServerInfo, handler StreamHandler) error
+type StreamServerInterceptor func(srv any, ss ServerStream, info *StreamServerInfo, handler StreamHandler) error
diff --git a/vendor/google.golang.org/grpc/internal/backoff/backoff.go b/vendor/google.golang.org/grpc/internal/backoff/backoff.go
index 5fc0ee3d..fed1c011 100644
--- a/vendor/google.golang.org/grpc/internal/backoff/backoff.go
+++ b/vendor/google.golang.org/grpc/internal/backoff/backoff.go
@@ -23,6 +23,8 @@
package backoff
import (
+ "context"
+ "errors"
"time"
grpcbackoff "google.golang.org/grpc/backoff"
@@ -71,3 +73,37 @@ func (bc Exponential) Backoff(retries int) time.Duration {
}
return time.Duration(backoff)
}
+
+// ErrResetBackoff is the error to be returned by the function executed by RunF,
+// to instruct the latter to reset its backoff state.
+var ErrResetBackoff = errors.New("reset backoff state")
+
+// RunF provides a convenient way to run a function f repeatedly until the
+// context expires or f returns a non-nil error that is not ErrResetBackoff.
+// When f returns ErrResetBackoff, RunF continues to run f, but resets its
+// backoff state before doing so. backoff accepts an integer representing the
+// number of retries, and returns the amount of time to backoff.
+func RunF(ctx context.Context, f func() error, backoff func(int) time.Duration) {
+ attempt := 0
+ timer := time.NewTimer(0)
+ for ctx.Err() == nil {
+ select {
+ case <-timer.C:
+ case <-ctx.Done():
+ timer.Stop()
+ return
+ }
+
+ err := f()
+ if errors.Is(err, ErrResetBackoff) {
+ timer.Reset(0)
+ attempt = 0
+ continue
+ }
+ if err != nil {
+ return
+ }
+ timer.Reset(backoff(attempt))
+ attempt++
+ }
+}
diff --git a/vendor/google.golang.org/grpc/internal/balancer/gracefulswitch/gracefulswitch.go b/vendor/google.golang.org/grpc/internal/balancer/gracefulswitch/gracefulswitch.go
index 08666f62..3c594e6e 100644
--- a/vendor/google.golang.org/grpc/internal/balancer/gracefulswitch/gracefulswitch.go
+++ b/vendor/google.golang.org/grpc/internal/balancer/gracefulswitch/gracefulswitch.go
@@ -200,8 +200,8 @@ func (gsb *Balancer) ExitIdle() {
}
}
-// UpdateSubConnState forwards the update to the appropriate child.
-func (gsb *Balancer) UpdateSubConnState(sc balancer.SubConn, state balancer.SubConnState) {
+// updateSubConnState forwards the update to the appropriate child.
+func (gsb *Balancer) updateSubConnState(sc balancer.SubConn, state balancer.SubConnState, cb func(balancer.SubConnState)) {
gsb.currentMu.Lock()
defer gsb.currentMu.Unlock()
gsb.mu.Lock()
@@ -214,13 +214,26 @@ func (gsb *Balancer) UpdateSubConnState(sc balancer.SubConn, state balancer.SubC
} else if gsb.balancerPending != nil && gsb.balancerPending.subconns[sc] {
balToUpdate = gsb.balancerPending
}
- gsb.mu.Unlock()
if balToUpdate == nil {
// SubConn belonged to a stale lb policy that has not yet fully closed,
// or the balancer was already closed.
+ gsb.mu.Unlock()
return
}
- balToUpdate.UpdateSubConnState(sc, state)
+ if state.ConnectivityState == connectivity.Shutdown {
+ delete(balToUpdate.subconns, sc)
+ }
+ gsb.mu.Unlock()
+ if cb != nil {
+ cb(state)
+ } else {
+ balToUpdate.UpdateSubConnState(sc, state)
+ }
+}
+
+// UpdateSubConnState forwards the update to the appropriate child.
+func (gsb *Balancer) UpdateSubConnState(sc balancer.SubConn, state balancer.SubConnState) {
+ gsb.updateSubConnState(sc, state, nil)
}
// Close closes any active child balancers.
@@ -242,7 +255,7 @@ func (gsb *Balancer) Close() {
//
// It implements the balancer.ClientConn interface and is passed down in that
// capacity to the wrapped balancer. It maintains a set of subConns created by
-// the wrapped balancer and calls from the latter to create/update/remove
+// the wrapped balancer and calls from the latter to create/update/shutdown
// SubConns update this set before being forwarded to the parent ClientConn.
// State updates from the wrapped balancer can result in invocation of the
// graceful switch logic.
@@ -254,21 +267,10 @@ type balancerWrapper struct {
subconns map[balancer.SubConn]bool // subconns created by this balancer
}
-func (bw *balancerWrapper) UpdateSubConnState(sc balancer.SubConn, state balancer.SubConnState) {
- if state.ConnectivityState == connectivity.Shutdown {
- bw.gsb.mu.Lock()
- delete(bw.subconns, sc)
- bw.gsb.mu.Unlock()
- }
- // There is no need to protect this read with a mutex, as the write to the
- // Balancer field happens in SwitchTo, which completes before this can be
- // called.
- bw.Balancer.UpdateSubConnState(sc, state)
-}
-
-// Close closes the underlying LB policy and removes the subconns it created. bw
-// must not be referenced via balancerCurrent or balancerPending in gsb when
-// called. gsb.mu must not be held. Does not panic with a nil receiver.
+// Close closes the underlying LB policy and shuts down the subconns it
+// created. bw must not be referenced via balancerCurrent or balancerPending in
+// gsb when called. gsb.mu must not be held. Does not panic with a nil
+// receiver.
func (bw *balancerWrapper) Close() {
// before Close is called.
if bw == nil {
@@ -281,7 +283,7 @@ func (bw *balancerWrapper) Close() {
bw.Balancer.Close()
bw.gsb.mu.Lock()
for sc := range bw.subconns {
- bw.gsb.cc.RemoveSubConn(sc)
+ sc.Shutdown()
}
bw.gsb.mu.Unlock()
}
@@ -335,13 +337,16 @@ func (bw *balancerWrapper) NewSubConn(addrs []resolver.Address, opts balancer.Ne
}
bw.gsb.mu.Unlock()
+ var sc balancer.SubConn
+ oldListener := opts.StateListener
+ opts.StateListener = func(state balancer.SubConnState) { bw.gsb.updateSubConnState(sc, state, oldListener) }
sc, err := bw.gsb.cc.NewSubConn(addrs, opts)
if err != nil {
return nil, err
}
bw.gsb.mu.Lock()
if !bw.gsb.balancerCurrentOrPending(bw) { // balancer was closed during this call
- bw.gsb.cc.RemoveSubConn(sc)
+ sc.Shutdown()
bw.gsb.mu.Unlock()
return nil, fmt.Errorf("%T at address %p that called NewSubConn is deleted", bw, bw)
}
@@ -360,13 +365,9 @@ func (bw *balancerWrapper) ResolveNow(opts resolver.ResolveNowOptions) {
}
func (bw *balancerWrapper) RemoveSubConn(sc balancer.SubConn) {
- bw.gsb.mu.Lock()
- if !bw.gsb.balancerCurrentOrPending(bw) {
- bw.gsb.mu.Unlock()
- return
- }
- bw.gsb.mu.Unlock()
- bw.gsb.cc.RemoveSubConn(sc)
+ // Note: existing third party balancers may call this, so it must remain
+ // until RemoveSubConn is fully removed.
+ sc.Shutdown()
}
func (bw *balancerWrapper) UpdateAddresses(sc balancer.SubConn, addrs []resolver.Address) {
diff --git a/vendor/google.golang.org/grpc/internal/balancerload/load.go b/vendor/google.golang.org/grpc/internal/balancerload/load.go
index 3a905d96..94a08d68 100644
--- a/vendor/google.golang.org/grpc/internal/balancerload/load.go
+++ b/vendor/google.golang.org/grpc/internal/balancerload/load.go
@@ -25,7 +25,7 @@ import (
// Parser converts loads from metadata into a concrete type.
type Parser interface {
// Parse parses loads from metadata.
- Parse(md metadata.MD) interface{}
+ Parse(md metadata.MD) any
}
var parser Parser
@@ -38,7 +38,7 @@ func SetParser(lr Parser) {
}
// Parse calls parser.Read().
-func Parse(md metadata.MD) interface{} {
+func Parse(md metadata.MD) any {
if parser == nil {
return nil
}
diff --git a/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go b/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go
index 6c3f6322..0f31274a 100644
--- a/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go
+++ b/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go
@@ -230,7 +230,7 @@ type ClientMessage struct {
OnClientSide bool
// Message can be a proto.Message or []byte. Other messages formats are not
// supported.
- Message interface{}
+ Message any
}
func (c *ClientMessage) toProto() *binlogpb.GrpcLogEntry {
@@ -270,7 +270,7 @@ type ServerMessage struct {
OnClientSide bool
// Message can be a proto.Message or []byte. Other messages formats are not
// supported.
- Message interface{}
+ Message any
}
func (c *ServerMessage) toProto() *binlogpb.GrpcLogEntry {
diff --git a/vendor/google.golang.org/grpc/internal/buffer/unbounded.go b/vendor/google.golang.org/grpc/internal/buffer/unbounded.go
index 81c2f5fd..11f91668 100644
--- a/vendor/google.golang.org/grpc/internal/buffer/unbounded.go
+++ b/vendor/google.golang.org/grpc/internal/buffer/unbounded.go
@@ -18,7 +18,10 @@
// Package buffer provides an implementation of an unbounded buffer.
package buffer
-import "sync"
+import (
+ "errors"
+ "sync"
+)
// Unbounded is an implementation of an unbounded buffer which does not use
// extra goroutines. This is typically used for passing updates from one entity
@@ -28,49 +31,50 @@ import "sync"
// the underlying mutex used for synchronization.
//
// Unbounded supports values of any type to be stored in it by using a channel
-// of `interface{}`. This means that a call to Put() incurs an extra memory
-// allocation, and also that users need a type assertion while reading. For
-// performance critical code paths, using Unbounded is strongly discouraged and
-// defining a new type specific implementation of this buffer is preferred. See
+// of `any`. This means that a call to Put() incurs an extra memory allocation,
+// and also that users need a type assertion while reading. For performance
+// critical code paths, using Unbounded is strongly discouraged and defining a
+// new type specific implementation of this buffer is preferred. See
// internal/transport/transport.go for an example of this.
type Unbounded struct {
- c chan interface{}
+ c chan any
closed bool
+ closing bool
mu sync.Mutex
- backlog []interface{}
+ backlog []any
}
// NewUnbounded returns a new instance of Unbounded.
func NewUnbounded() *Unbounded {
- return &Unbounded{c: make(chan interface{}, 1)}
+ return &Unbounded{c: make(chan any, 1)}
}
+var errBufferClosed = errors.New("Put called on closed buffer.Unbounded")
+
// Put adds t to the unbounded buffer.
-func (b *Unbounded) Put(t interface{}) {
+func (b *Unbounded) Put(t any) error {
b.mu.Lock()
defer b.mu.Unlock()
- if b.closed {
- return
+ if b.closing {
+ return errBufferClosed
}
if len(b.backlog) == 0 {
select {
case b.c <- t:
- return
+ return nil
default:
}
}
b.backlog = append(b.backlog, t)
+ return nil
}
-// Load sends the earliest buffered data, if any, onto the read channel
-// returned by Get(). Users are expected to call this every time they read a
+// Load sends the earliest buffered data, if any, onto the read channel returned
+// by Get(). Users are expected to call this every time they successfully read a
// value from the read channel.
func (b *Unbounded) Load() {
b.mu.Lock()
defer b.mu.Unlock()
- if b.closed {
- return
- }
if len(b.backlog) > 0 {
select {
case b.c <- b.backlog[0]:
@@ -78,6 +82,8 @@ func (b *Unbounded) Load() {
b.backlog = b.backlog[1:]
default:
}
+ } else if b.closing && !b.closed {
+ close(b.c)
}
}
@@ -88,18 +94,23 @@ func (b *Unbounded) Load() {
// send the next buffered value onto the channel if there is any.
//
// If the unbounded buffer is closed, the read channel returned by this method
-// is closed.
-func (b *Unbounded) Get() <-chan interface{} {
+// is closed after all data is drained.
+func (b *Unbounded) Get() <-chan any {
return b.c
}
-// Close closes the unbounded buffer.
+// Close closes the unbounded buffer. No subsequent data may be Put(), and the
+// channel returned from Get() will be closed after all the data is read and
+// Load() is called for the final time.
func (b *Unbounded) Close() {
b.mu.Lock()
defer b.mu.Unlock()
- if b.closed {
+ if b.closing {
return
}
- b.closed = true
- close(b.c)
+ b.closing = true
+ if len(b.backlog) == 0 {
+ b.closed = true
+ close(b.c)
+ }
}
diff --git a/vendor/google.golang.org/grpc/internal/channelz/funcs.go b/vendor/google.golang.org/grpc/internal/channelz/funcs.go
index 777cbcd7..fc094f34 100644
--- a/vendor/google.golang.org/grpc/internal/channelz/funcs.go
+++ b/vendor/google.golang.org/grpc/internal/channelz/funcs.go
@@ -24,15 +24,14 @@
package channelz
import (
- "context"
"errors"
- "fmt"
"sort"
"sync"
"sync/atomic"
"time"
"google.golang.org/grpc/grpclog"
+ "google.golang.org/grpc/internal"
)
const (
@@ -40,8 +39,11 @@ const (
)
var (
- db dbWrapper
- idGen idGenerator
+ // IDGen is the global channelz entity ID generator. It should not be used
+ // outside this package except by tests.
+ IDGen IDGenerator
+
+ db dbWrapper
// EntryPerPage defines the number of channelz entries to be shown on a web page.
EntryPerPage = int64(50)
curState int32
@@ -52,14 +54,20 @@ var (
func TurnOn() {
if !IsOn() {
db.set(newChannelMap())
- idGen.reset()
+ IDGen.Reset()
atomic.StoreInt32(&curState, 1)
}
}
+func init() {
+ internal.ChannelzTurnOffForTesting = func() {
+ atomic.StoreInt32(&curState, 0)
+ }
+}
+
// IsOn returns whether channelz data collection is on.
func IsOn() bool {
- return atomic.CompareAndSwapInt32(&curState, 1, 1)
+ return atomic.LoadInt32(&curState) == 1
}
// SetMaxTraceEntry sets maximum number of trace entry per entity (i.e. channel/subchannel).
@@ -97,43 +105,6 @@ func (d *dbWrapper) get() *channelMap {
return d.DB
}
-// NewChannelzStorageForTesting initializes channelz data storage and id
-// generator for testing purposes.
-//
-// Returns a cleanup function to be invoked by the test, which waits for up to
-// 10s for all channelz state to be reset by the grpc goroutines when those
-// entities get closed. This cleanup function helps with ensuring that tests
-// don't mess up each other.
-func NewChannelzStorageForTesting() (cleanup func() error) {
- db.set(newChannelMap())
- idGen.reset()
-
- return func() error {
- cm := db.get()
- if cm == nil {
- return nil
- }
-
- ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
- defer cancel()
- ticker := time.NewTicker(10 * time.Millisecond)
- defer ticker.Stop()
- for {
- cm.mu.RLock()
- topLevelChannels, servers, channels, subChannels, listenSockets, normalSockets := len(cm.topLevelChannels), len(cm.servers), len(cm.channels), len(cm.subChannels), len(cm.listenSockets), len(cm.normalSockets)
- cm.mu.RUnlock()
-
- if err := ctx.Err(); err != nil {
- return fmt.Errorf("after 10s the channelz map has not been cleaned up yet, topchannels: %d, servers: %d, channels: %d, subchannels: %d, listen sockets: %d, normal sockets: %d", topLevelChannels, servers, channels, subChannels, listenSockets, normalSockets)
- }
- if topLevelChannels == 0 && servers == 0 && channels == 0 && subChannels == 0 && listenSockets == 0 && normalSockets == 0 {
- return nil
- }
- <-ticker.C
- }
- }
-}
-
// GetTopChannels returns a slice of top channel's ChannelMetric, along with a
// boolean indicating whether there's more top channels to be queried for.
//
@@ -193,7 +164,7 @@ func GetServer(id int64) *ServerMetric {
//
// If channelz is not turned ON, the channelz database is not mutated.
func RegisterChannel(c Channel, pid *Identifier, ref string) *Identifier {
- id := idGen.genID()
+ id := IDGen.genID()
var parent int64
isTopChannel := true
if pid != nil {
@@ -229,7 +200,7 @@ func RegisterSubChannel(c Channel, pid *Identifier, ref string) (*Identifier, er
if pid == nil {
return nil, errors.New("a SubChannel's parent id cannot be nil")
}
- id := idGen.genID()
+ id := IDGen.genID()
if !IsOn() {
return newIdentifer(RefSubChannel, id, pid), nil
}
@@ -251,7 +222,7 @@ func RegisterSubChannel(c Channel, pid *Identifier, ref string) (*Identifier, er
//
// If channelz is not turned ON, the channelz database is not mutated.
func RegisterServer(s Server, ref string) *Identifier {
- id := idGen.genID()
+ id := IDGen.genID()
if !IsOn() {
return newIdentifer(RefServer, id, nil)
}
@@ -277,7 +248,7 @@ func RegisterListenSocket(s Socket, pid *Identifier, ref string) (*Identifier, e
if pid == nil {
return nil, errors.New("a ListenSocket's parent id cannot be 0")
}
- id := idGen.genID()
+ id := IDGen.genID()
if !IsOn() {
return newIdentifer(RefListenSocket, id, pid), nil
}
@@ -297,7 +268,7 @@ func RegisterNormalSocket(s Socket, pid *Identifier, ref string) (*Identifier, e
if pid == nil {
return nil, errors.New("a NormalSocket's parent id cannot be 0")
}
- id := idGen.genID()
+ id := IDGen.genID()
if !IsOn() {
return newIdentifer(RefNormalSocket, id, pid), nil
}
@@ -776,14 +747,17 @@ func (c *channelMap) GetServer(id int64) *ServerMetric {
return sm
}
-type idGenerator struct {
+// IDGenerator is an incrementing atomic that tracks IDs for channelz entities.
+type IDGenerator struct {
id int64
}
-func (i *idGenerator) reset() {
+// Reset resets the generated ID back to zero. Should only be used at
+// initialization or by tests sensitive to the ID number.
+func (i *IDGenerator) Reset() {
atomic.StoreInt64(&i.id, 0)
}
-func (i *idGenerator) genID() int64 {
+func (i *IDGenerator) genID() int64 {
return atomic.AddInt64(&i.id, 1)
}
diff --git a/vendor/google.golang.org/grpc/internal/channelz/logging.go b/vendor/google.golang.org/grpc/internal/channelz/logging.go
index 8e13a3d2..f89e6f77 100644
--- a/vendor/google.golang.org/grpc/internal/channelz/logging.go
+++ b/vendor/google.golang.org/grpc/internal/channelz/logging.go
@@ -31,7 +31,7 @@ func withParens(id *Identifier) string {
}
// Info logs and adds a trace event if channelz is on.
-func Info(l grpclog.DepthLoggerV2, id *Identifier, args ...interface{}) {
+func Info(l grpclog.DepthLoggerV2, id *Identifier, args ...any) {
AddTraceEvent(l, id, 1, &TraceEventDesc{
Desc: fmt.Sprint(args...),
Severity: CtInfo,
@@ -39,7 +39,7 @@ func Info(l grpclog.DepthLoggerV2, id *Identifier, args ...interface{}) {
}
// Infof logs and adds a trace event if channelz is on.
-func Infof(l grpclog.DepthLoggerV2, id *Identifier, format string, args ...interface{}) {
+func Infof(l grpclog.DepthLoggerV2, id *Identifier, format string, args ...any) {
AddTraceEvent(l, id, 1, &TraceEventDesc{
Desc: fmt.Sprintf(format, args...),
Severity: CtInfo,
@@ -47,7 +47,7 @@ func Infof(l grpclog.DepthLoggerV2, id *Identifier, format string, args ...inter
}
// Warning logs and adds a trace event if channelz is on.
-func Warning(l grpclog.DepthLoggerV2, id *Identifier, args ...interface{}) {
+func Warning(l grpclog.DepthLoggerV2, id *Identifier, args ...any) {
AddTraceEvent(l, id, 1, &TraceEventDesc{
Desc: fmt.Sprint(args...),
Severity: CtWarning,
@@ -55,7 +55,7 @@ func Warning(l grpclog.DepthLoggerV2, id *Identifier, args ...interface{}) {
}
// Warningf logs and adds a trace event if channelz is on.
-func Warningf(l grpclog.DepthLoggerV2, id *Identifier, format string, args ...interface{}) {
+func Warningf(l grpclog.DepthLoggerV2, id *Identifier, format string, args ...any) {
AddTraceEvent(l, id, 1, &TraceEventDesc{
Desc: fmt.Sprintf(format, args...),
Severity: CtWarning,
@@ -63,7 +63,7 @@ func Warningf(l grpclog.DepthLoggerV2, id *Identifier, format string, args ...in
}
// Error logs and adds a trace event if channelz is on.
-func Error(l grpclog.DepthLoggerV2, id *Identifier, args ...interface{}) {
+func Error(l grpclog.DepthLoggerV2, id *Identifier, args ...any) {
AddTraceEvent(l, id, 1, &TraceEventDesc{
Desc: fmt.Sprint(args...),
Severity: CtError,
@@ -71,7 +71,7 @@ func Error(l grpclog.DepthLoggerV2, id *Identifier, args ...interface{}) {
}
// Errorf logs and adds a trace event if channelz is on.
-func Errorf(l grpclog.DepthLoggerV2, id *Identifier, format string, args ...interface{}) {
+func Errorf(l grpclog.DepthLoggerV2, id *Identifier, format string, args ...any) {
AddTraceEvent(l, id, 1, &TraceEventDesc{
Desc: fmt.Sprintf(format, args...),
Severity: CtError,
diff --git a/vendor/google.golang.org/grpc/internal/channelz/types.go b/vendor/google.golang.org/grpc/internal/channelz/types.go
index 7b2f350e..1d4020f5 100644
--- a/vendor/google.golang.org/grpc/internal/channelz/types.go
+++ b/vendor/google.golang.org/grpc/internal/channelz/types.go
@@ -628,6 +628,7 @@ type tracedChannel interface {
type channelTrace struct {
cm *channelMap
+ clearCalled bool
createdTime time.Time
eventCount int64
mu sync.Mutex
@@ -656,6 +657,10 @@ func (c *channelTrace) append(e *TraceEvent) {
}
func (c *channelTrace) clear() {
+ if c.clearCalled {
+ return
+ }
+ c.clearCalled = true
c.mu.Lock()
for _, e := range c.events {
if e.RefID != 0 {
diff --git a/vendor/google.golang.org/grpc/internal/channelz/util_linux.go b/vendor/google.golang.org/grpc/internal/channelz/util_linux.go
index 8d194e44..98288c3f 100644
--- a/vendor/google.golang.org/grpc/internal/channelz/util_linux.go
+++ b/vendor/google.golang.org/grpc/internal/channelz/util_linux.go
@@ -23,7 +23,7 @@ import (
)
// GetSocketOption gets the socket option info of the conn.
-func GetSocketOption(socket interface{}) *SocketOptionData {
+func GetSocketOption(socket any) *SocketOptionData {
c, ok := socket.(syscall.Conn)
if !ok {
return nil
diff --git a/vendor/google.golang.org/grpc/internal/channelz/util_nonlinux.go b/vendor/google.golang.org/grpc/internal/channelz/util_nonlinux.go
index 837ddc40..b5568b22 100644
--- a/vendor/google.golang.org/grpc/internal/channelz/util_nonlinux.go
+++ b/vendor/google.golang.org/grpc/internal/channelz/util_nonlinux.go
@@ -22,6 +22,6 @@
package channelz
// GetSocketOption gets the socket option info of the conn.
-func GetSocketOption(c interface{}) *SocketOptionData {
+func GetSocketOption(c any) *SocketOptionData {
return nil
}
diff --git a/vendor/google.golang.org/grpc/internal/credentials/credentials.go b/vendor/google.golang.org/grpc/internal/credentials/credentials.go
index 32c9b590..9deee7f6 100644
--- a/vendor/google.golang.org/grpc/internal/credentials/credentials.go
+++ b/vendor/google.golang.org/grpc/internal/credentials/credentials.go
@@ -25,12 +25,12 @@ import (
type requestInfoKey struct{}
// NewRequestInfoContext creates a context with ri.
-func NewRequestInfoContext(ctx context.Context, ri interface{}) context.Context {
+func NewRequestInfoContext(ctx context.Context, ri any) context.Context {
return context.WithValue(ctx, requestInfoKey{}, ri)
}
// RequestInfoFromContext extracts the RequestInfo from ctx.
-func RequestInfoFromContext(ctx context.Context) interface{} {
+func RequestInfoFromContext(ctx context.Context) any {
return ctx.Value(requestInfoKey{})
}
@@ -39,11 +39,11 @@ func RequestInfoFromContext(ctx context.Context) interface{} {
type clientHandshakeInfoKey struct{}
// ClientHandshakeInfoFromContext extracts the ClientHandshakeInfo from ctx.
-func ClientHandshakeInfoFromContext(ctx context.Context) interface{} {
+func ClientHandshakeInfoFromContext(ctx context.Context) any {
return ctx.Value(clientHandshakeInfoKey{})
}
// NewClientHandshakeInfoContext creates a context with chi.
-func NewClientHandshakeInfoContext(ctx context.Context, chi interface{}) context.Context {
+func NewClientHandshakeInfoContext(ctx context.Context, chi any) context.Context {
return context.WithValue(ctx, clientHandshakeInfoKey{}, chi)
}
diff --git a/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go b/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go
index 80fd5c7d..685a3cb4 100644
--- a/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go
+++ b/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go
@@ -36,10 +36,13 @@ var (
// "GRPC_RING_HASH_CAP". This does not override the default bounds
// checking which NACKs configs specifying ring sizes > 8*1024*1024 (~8M).
RingHashCap = uint64FromEnv("GRPC_RING_HASH_CAP", 4096, 1, 8*1024*1024)
- // PickFirstLBConfig is set if we should support configuration of the
- // pick_first LB policy, which can be enabled by setting the environment
- // variable "GRPC_EXPERIMENTAL_PICKFIRST_LB_CONFIG" to "true".
- PickFirstLBConfig = boolFromEnv("GRPC_EXPERIMENTAL_PICKFIRST_LB_CONFIG", false)
+ // LeastRequestLB is set if we should support the least_request_experimental
+ // LB policy, which can be enabled by setting the environment variable
+ // "GRPC_EXPERIMENTAL_ENABLE_LEAST_REQUEST" to "true".
+ LeastRequestLB = boolFromEnv("GRPC_EXPERIMENTAL_ENABLE_LEAST_REQUEST", false)
+ // ALTSMaxConcurrentHandshakes is the maximum number of concurrent ALTS
+ // handshakes that can be performed.
+ ALTSMaxConcurrentHandshakes = uint64FromEnv("GRPC_ALTS_MAX_CONCURRENT_HANDSHAKES", 100, 1, 100)
)
func boolFromEnv(envVar string, def bool) bool {
diff --git a/vendor/google.golang.org/grpc/internal/envconfig/xds.go b/vendor/google.golang.org/grpc/internal/envconfig/xds.go
index 02b4b6a1..29f234ac 100644
--- a/vendor/google.golang.org/grpc/internal/envconfig/xds.go
+++ b/vendor/google.golang.org/grpc/internal/envconfig/xds.go
@@ -50,46 +50,7 @@ var (
//
// When both bootstrap FileName and FileContent are set, FileName is used.
XDSBootstrapFileContent = os.Getenv(XDSBootstrapFileContentEnv)
- // XDSRingHash indicates whether ring hash support is enabled, which can be
- // disabled by setting the environment variable
- // "GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH" to "false".
- XDSRingHash = boolFromEnv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH", true)
- // XDSClientSideSecurity is used to control processing of security
- // configuration on the client-side.
- //
- // Note that there is no env var protection for the server-side because we
- // have a brand new API on the server-side and users explicitly need to use
- // the new API to get security integration on the server.
- XDSClientSideSecurity = boolFromEnv("GRPC_XDS_EXPERIMENTAL_SECURITY_SUPPORT", true)
- // XDSAggregateAndDNS indicates whether processing of aggregated cluster and
- // DNS cluster is enabled, which can be disabled by setting the environment
- // variable "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER"
- // to "false".
- XDSAggregateAndDNS = boolFromEnv("GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER", true)
-
- // XDSRBAC indicates whether xDS configured RBAC HTTP Filter is enabled,
- // which can be disabled by setting the environment variable
- // "GRPC_XDS_EXPERIMENTAL_RBAC" to "false".
- XDSRBAC = boolFromEnv("GRPC_XDS_EXPERIMENTAL_RBAC", true)
- // XDSOutlierDetection indicates whether outlier detection support is
- // enabled, which can be disabled by setting the environment variable
- // "GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION" to "false".
- XDSOutlierDetection = boolFromEnv("GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION", true)
- // XDSFederation indicates whether federation support is enabled, which can
- // be enabled by setting the environment variable
- // "GRPC_EXPERIMENTAL_XDS_FEDERATION" to "true".
- XDSFederation = boolFromEnv("GRPC_EXPERIMENTAL_XDS_FEDERATION", true)
-
- // XDSRLS indicates whether processing of Cluster Specifier plugins and
- // support for the RLS CLuster Specifier is enabled, which can be disabled by
- // setting the environment variable "GRPC_EXPERIMENTAL_XDS_RLS_LB" to
- // "false".
- XDSRLS = boolFromEnv("GRPC_EXPERIMENTAL_XDS_RLS_LB", true)
// C2PResolverTestOnlyTrafficDirectorURI is the TD URI for testing.
C2PResolverTestOnlyTrafficDirectorURI = os.Getenv("GRPC_TEST_ONLY_GOOGLE_C2P_RESOLVER_TRAFFIC_DIRECTOR_URI")
- // XDSCustomLBPolicy indicates whether Custom LB Policies are enabled, which
- // can be disabled by setting the environment variable
- // "GRPC_EXPERIMENTAL_XDS_CUSTOM_LB_CONFIG" to "false".
- XDSCustomLBPolicy = boolFromEnv("GRPC_EXPERIMENTAL_XDS_CUSTOM_LB_CONFIG", true)
)
diff --git a/vendor/google.golang.org/grpc/internal/experimental.go b/vendor/google.golang.org/grpc/internal/experimental.go
new file mode 100644
index 00000000..7f7044e1
--- /dev/null
+++ b/vendor/google.golang.org/grpc/internal/experimental.go
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2023 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 internal
+
+var (
+ // WithRecvBufferPool is implemented by the grpc package and returns a dial
+ // option to configure a shared buffer pool for a grpc.ClientConn.
+ WithRecvBufferPool any // func (grpc.SharedBufferPool) grpc.DialOption
+
+ // RecvBufferPool is implemented by the grpc package and returns a server
+ // option to configure a shared buffer pool for a grpc.Server.
+ RecvBufferPool any // func (grpc.SharedBufferPool) grpc.ServerOption
+)
diff --git a/vendor/google.golang.org/grpc/internal/grpclog/grpclog.go b/vendor/google.golang.org/grpc/internal/grpclog/grpclog.go
index b68e26a3..bfc45102 100644
--- a/vendor/google.golang.org/grpc/internal/grpclog/grpclog.go
+++ b/vendor/google.golang.org/grpc/internal/grpclog/grpclog.go
@@ -30,7 +30,7 @@ var Logger LoggerV2
var DepthLogger DepthLoggerV2
// InfoDepth logs to the INFO log at the specified depth.
-func InfoDepth(depth int, args ...interface{}) {
+func InfoDepth(depth int, args ...any) {
if DepthLogger != nil {
DepthLogger.InfoDepth(depth, args...)
} else {
@@ -39,7 +39,7 @@ func InfoDepth(depth int, args ...interface{}) {
}
// WarningDepth logs to the WARNING log at the specified depth.
-func WarningDepth(depth int, args ...interface{}) {
+func WarningDepth(depth int, args ...any) {
if DepthLogger != nil {
DepthLogger.WarningDepth(depth, args...)
} else {
@@ -48,7 +48,7 @@ func WarningDepth(depth int, args ...interface{}) {
}
// ErrorDepth logs to the ERROR log at the specified depth.
-func ErrorDepth(depth int, args ...interface{}) {
+func ErrorDepth(depth int, args ...any) {
if DepthLogger != nil {
DepthLogger.ErrorDepth(depth, args...)
} else {
@@ -57,7 +57,7 @@ func ErrorDepth(depth int, args ...interface{}) {
}
// FatalDepth logs to the FATAL log at the specified depth.
-func FatalDepth(depth int, args ...interface{}) {
+func FatalDepth(depth int, args ...any) {
if DepthLogger != nil {
DepthLogger.FatalDepth(depth, args...)
} else {
@@ -71,35 +71,35 @@ func FatalDepth(depth int, args ...interface{}) {
// is defined here to avoid a circular dependency.
type LoggerV2 interface {
// Info logs to INFO log. Arguments are handled in the manner of fmt.Print.
- Info(args ...interface{})
+ Info(args ...any)
// Infoln logs to INFO log. Arguments are handled in the manner of fmt.Println.
- Infoln(args ...interface{})
+ Infoln(args ...any)
// Infof logs to INFO log. Arguments are handled in the manner of fmt.Printf.
- Infof(format string, args ...interface{})
+ Infof(format string, args ...any)
// Warning logs to WARNING log. Arguments are handled in the manner of fmt.Print.
- Warning(args ...interface{})
+ Warning(args ...any)
// Warningln logs to WARNING log. Arguments are handled in the manner of fmt.Println.
- Warningln(args ...interface{})
+ Warningln(args ...any)
// Warningf logs to WARNING log. Arguments are handled in the manner of fmt.Printf.
- Warningf(format string, args ...interface{})
+ Warningf(format string, args ...any)
// Error logs to ERROR log. Arguments are handled in the manner of fmt.Print.
- Error(args ...interface{})
+ Error(args ...any)
// Errorln logs to ERROR log. Arguments are handled in the manner of fmt.Println.
- Errorln(args ...interface{})
+ Errorln(args ...any)
// Errorf logs to ERROR log. Arguments are handled in the manner of fmt.Printf.
- Errorf(format string, args ...interface{})
+ Errorf(format string, args ...any)
// Fatal logs to ERROR log. Arguments are handled in the manner of fmt.Print.
// gRPC ensures that all Fatal logs will exit with os.Exit(1).
// Implementations may also call os.Exit() with a non-zero exit code.
- Fatal(args ...interface{})
+ Fatal(args ...any)
// Fatalln logs to ERROR log. Arguments are handled in the manner of fmt.Println.
// gRPC ensures that all Fatal logs will exit with os.Exit(1).
// Implementations may also call os.Exit() with a non-zero exit code.
- Fatalln(args ...interface{})
+ Fatalln(args ...any)
// Fatalf logs to ERROR log. Arguments are handled in the manner of fmt.Printf.
// gRPC ensures that all Fatal logs will exit with os.Exit(1).
// Implementations may also call os.Exit() with a non-zero exit code.
- Fatalf(format string, args ...interface{})
+ Fatalf(format string, args ...any)
// V reports whether verbosity level l is at least the requested verbose level.
V(l int) bool
}
@@ -116,11 +116,11 @@ type LoggerV2 interface {
// later release.
type DepthLoggerV2 interface {
// InfoDepth logs to INFO log at the specified depth. Arguments are handled in the manner of fmt.Println.
- InfoDepth(depth int, args ...interface{})
+ InfoDepth(depth int, args ...any)
// WarningDepth logs to WARNING log at the specified depth. Arguments are handled in the manner of fmt.Println.
- WarningDepth(depth int, args ...interface{})
+ WarningDepth(depth int, args ...any)
// ErrorDepth logs to ERROR log at the specified depth. Arguments are handled in the manner of fmt.Println.
- ErrorDepth(depth int, args ...interface{})
+ ErrorDepth(depth int, args ...any)
// FatalDepth logs to FATAL log at the specified depth. Arguments are handled in the manner of fmt.Println.
- FatalDepth(depth int, args ...interface{})
+ FatalDepth(depth int, args ...any)
}
diff --git a/vendor/google.golang.org/grpc/internal/grpclog/prefixLogger.go b/vendor/google.golang.org/grpc/internal/grpclog/prefixLogger.go
index 02224b42..faa998de 100644
--- a/vendor/google.golang.org/grpc/internal/grpclog/prefixLogger.go
+++ b/vendor/google.golang.org/grpc/internal/grpclog/prefixLogger.go
@@ -31,7 +31,7 @@ type PrefixLogger struct {
}
// Infof does info logging.
-func (pl *PrefixLogger) Infof(format string, args ...interface{}) {
+func (pl *PrefixLogger) Infof(format string, args ...any) {
if pl != nil {
// Handle nil, so the tests can pass in a nil logger.
format = pl.prefix + format
@@ -42,7 +42,7 @@ func (pl *PrefixLogger) Infof(format string, args ...interface{}) {
}
// Warningf does warning logging.
-func (pl *PrefixLogger) Warningf(format string, args ...interface{}) {
+func (pl *PrefixLogger) Warningf(format string, args ...any) {
if pl != nil {
format = pl.prefix + format
pl.logger.WarningDepth(1, fmt.Sprintf(format, args...))
@@ -52,7 +52,7 @@ func (pl *PrefixLogger) Warningf(format string, args ...interface{}) {
}
// Errorf does error logging.
-func (pl *PrefixLogger) Errorf(format string, args ...interface{}) {
+func (pl *PrefixLogger) Errorf(format string, args ...any) {
if pl != nil {
format = pl.prefix + format
pl.logger.ErrorDepth(1, fmt.Sprintf(format, args...))
@@ -62,7 +62,7 @@ func (pl *PrefixLogger) Errorf(format string, args ...interface{}) {
}
// Debugf does info logging at verbose level 2.
-func (pl *PrefixLogger) Debugf(format string, args ...interface{}) {
+func (pl *PrefixLogger) Debugf(format string, args ...any) {
// TODO(6044): Refactor interfaces LoggerV2 and DepthLogger, and maybe
// rewrite PrefixLogger a little to ensure that we don't use the global
// `Logger` here, and instead use the `logger` field.
diff --git a/vendor/google.golang.org/grpc/internal/grpcrand/grpcrand.go b/vendor/google.golang.org/grpc/internal/grpcrand/grpcrand.go
index d08e3e90..aa97273e 100644
--- a/vendor/google.golang.org/grpc/internal/grpcrand/grpcrand.go
+++ b/vendor/google.golang.org/grpc/internal/grpcrand/grpcrand.go
@@ -80,6 +80,13 @@ func Uint32() uint32 {
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()
diff --git a/vendor/google.golang.org/grpc/internal/grpcsync/callback_serializer.go b/vendor/google.golang.org/grpc/internal/grpcsync/callback_serializer.go
index 37b8d411..f7f40a16 100644
--- a/vendor/google.golang.org/grpc/internal/grpcsync/callback_serializer.go
+++ b/vendor/google.golang.org/grpc/internal/grpcsync/callback_serializer.go
@@ -20,7 +20,6 @@ package grpcsync
import (
"context"
- "sync"
"google.golang.org/grpc/internal/buffer"
)
@@ -32,14 +31,12 @@ import (
//
// This type is safe for concurrent access.
type CallbackSerializer struct {
- // Done is closed once the serializer is shut down completely, i.e all
+ // done is closed once the serializer is shut down completely, i.e all
// scheduled callbacks are executed and the serializer has deallocated all
// its resources.
- Done chan struct{}
+ done chan struct{}
callbacks *buffer.Unbounded
- closedMu sync.Mutex
- closed bool
}
// NewCallbackSerializer returns a new CallbackSerializer instance. The provided
@@ -48,12 +45,12 @@ type CallbackSerializer struct {
// callbacks will be added once this context is canceled, and any pending un-run
// callbacks will be executed before the serializer is shut down.
func NewCallbackSerializer(ctx context.Context) *CallbackSerializer {
- t := &CallbackSerializer{
- Done: make(chan struct{}),
+ cs := &CallbackSerializer{
+ done: make(chan struct{}),
callbacks: buffer.NewUnbounded(),
}
- go t.run(ctx)
- return t
+ go cs.run(ctx)
+ return cs
}
// Schedule adds a callback to be scheduled after existing callbacks are run.
@@ -64,56 +61,40 @@ func NewCallbackSerializer(ctx context.Context) *CallbackSerializer {
// Return value indicates if the callback was successfully added to the list of
// callbacks to be executed by the serializer. It is not possible to add
// callbacks once the context passed to NewCallbackSerializer is cancelled.
-func (t *CallbackSerializer) Schedule(f func(ctx context.Context)) bool {
- t.closedMu.Lock()
- defer t.closedMu.Unlock()
-
- if t.closed {
- return false
- }
- t.callbacks.Put(f)
- return true
+func (cs *CallbackSerializer) Schedule(f func(ctx context.Context)) bool {
+ return cs.callbacks.Put(f) == nil
}
-func (t *CallbackSerializer) run(ctx context.Context) {
- var backlog []func(context.Context)
+func (cs *CallbackSerializer) run(ctx context.Context) {
+ defer close(cs.done)
- defer close(t.Done)
+ // TODO: when Go 1.21 is the oldest supported version, this loop and Close
+ // can be replaced with:
+ //
+ // context.AfterFunc(ctx, cs.callbacks.Close)
for ctx.Err() == nil {
select {
case <-ctx.Done():
// Do nothing here. Next iteration of the for loop will not happen,
// since ctx.Err() would be non-nil.
- case callback, ok := <-t.callbacks.Get():
- if !ok {
- return
- }
- t.callbacks.Load()
- callback.(func(ctx context.Context))(ctx)
+ case cb := <-cs.callbacks.Get():
+ cs.callbacks.Load()
+ cb.(func(context.Context))(ctx)
}
}
- // Fetch pending callbacks if any, and execute them before returning from
- // this method and closing t.Done.
- t.closedMu.Lock()
- t.closed = true
- backlog = t.fetchPendingCallbacks()
- t.callbacks.Close()
- t.closedMu.Unlock()
- for _, b := range backlog {
- b(ctx)
+ // Close the buffer to prevent new callbacks from being added.
+ cs.callbacks.Close()
+
+ // Run all pending callbacks.
+ for cb := range cs.callbacks.Get() {
+ cs.callbacks.Load()
+ cb.(func(context.Context))(ctx)
}
}
-func (t *CallbackSerializer) fetchPendingCallbacks() []func(context.Context) {
- var backlog []func(context.Context)
- for {
- select {
- case b := <-t.callbacks.Get():
- backlog = append(backlog, b.(func(context.Context)))
- t.callbacks.Load()
- default:
- return backlog
- }
- }
+// Done returns a channel that is closed after the context passed to
+// NewCallbackSerializer is canceled and all callbacks have been executed.
+func (cs *CallbackSerializer) Done() <-chan struct{} {
+ return cs.done
}
diff --git a/vendor/google.golang.org/grpc/internal/grpcsync/pubsub.go b/vendor/google.golang.org/grpc/internal/grpcsync/pubsub.go
new file mode 100644
index 00000000..aef8cec1
--- /dev/null
+++ b/vendor/google.golang.org/grpc/internal/grpcsync/pubsub.go
@@ -0,0 +1,121 @@
+/*
+ *
+ * Copyright 2023 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 grpcsync
+
+import (
+ "context"
+ "sync"
+)
+
+// Subscriber represents an entity that is subscribed to messages published on
+// a PubSub. It wraps the callback to be invoked by the PubSub when a new
+// message is published.
+type Subscriber interface {
+ // OnMessage is invoked when a new message is published. Implementations
+ // must not block in this method.
+ OnMessage(msg any)
+}
+
+// PubSub is a simple one-to-many publish-subscribe system that supports
+// messages of arbitrary type. It guarantees that messages are delivered in
+// the same order in which they were published.
+//
+// Publisher invokes the Publish() method to publish new messages, while
+// subscribers interested in receiving these messages register a callback
+// via the Subscribe() method.
+//
+// Once a PubSub is stopped, no more messages can be published, but any pending
+// published messages will be delivered to the subscribers. Done may be used
+// to determine when all published messages have been delivered.
+type PubSub struct {
+ cs *CallbackSerializer
+
+ // Access to the below fields are guarded by this mutex.
+ mu sync.Mutex
+ msg any
+ subscribers map[Subscriber]bool
+}
+
+// NewPubSub returns a new PubSub instance. Users should cancel the
+// provided context to shutdown the PubSub.
+func NewPubSub(ctx context.Context) *PubSub {
+ return &PubSub{
+ cs: NewCallbackSerializer(ctx),
+ subscribers: map[Subscriber]bool{},
+ }
+}
+
+// Subscribe registers the provided Subscriber to the PubSub.
+//
+// If the PubSub contains a previously published message, the Subscriber's
+// OnMessage() callback will be invoked asynchronously with the existing
+// message to begin with, and subsequently for every newly published message.
+//
+// The caller is responsible for invoking the returned cancel function to
+// unsubscribe itself from the PubSub.
+func (ps *PubSub) Subscribe(sub Subscriber) (cancel func()) {
+ ps.mu.Lock()
+ defer ps.mu.Unlock()
+
+ ps.subscribers[sub] = true
+
+ if ps.msg != nil {
+ msg := ps.msg
+ ps.cs.Schedule(func(context.Context) {
+ ps.mu.Lock()
+ defer ps.mu.Unlock()
+ if !ps.subscribers[sub] {
+ return
+ }
+ sub.OnMessage(msg)
+ })
+ }
+
+ return func() {
+ ps.mu.Lock()
+ defer ps.mu.Unlock()
+ delete(ps.subscribers, sub)
+ }
+}
+
+// Publish publishes the provided message to the PubSub, and invokes
+// callbacks registered by subscribers asynchronously.
+func (ps *PubSub) Publish(msg any) {
+ ps.mu.Lock()
+ defer ps.mu.Unlock()
+
+ ps.msg = msg
+ for sub := range ps.subscribers {
+ s := sub
+ ps.cs.Schedule(func(context.Context) {
+ ps.mu.Lock()
+ defer ps.mu.Unlock()
+ if !ps.subscribers[s] {
+ return
+ }
+ s.OnMessage(msg)
+ })
+ }
+}
+
+// Done returns a channel that is closed after the context passed to NewPubSub
+// is canceled and all updates have been sent to subscribers.
+func (ps *PubSub) Done() <-chan struct{} {
+ return ps.cs.Done()
+}
diff --git a/vendor/google.golang.org/grpc/internal/idle/idle.go b/vendor/google.golang.org/grpc/internal/idle/idle.go
new file mode 100644
index 00000000..fe49cb74
--- /dev/null
+++ b/vendor/google.golang.org/grpc/internal/idle/idle.go
@@ -0,0 +1,278 @@
+/*
+ *
+ * Copyright 2023 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 idle contains a component for managing idleness (entering and exiting)
+// based on RPC activity.
+package idle
+
+import (
+ "fmt"
+ "math"
+ "sync"
+ "sync/atomic"
+ "time"
+)
+
+// For overriding in unit tests.
+var timeAfterFunc = func(d time.Duration, f func()) *time.Timer {
+ return time.AfterFunc(d, f)
+}
+
+// Enforcer is the functionality provided by grpc.ClientConn to enter
+// and exit from idle mode.
+type Enforcer interface {
+ ExitIdleMode() error
+ EnterIdleMode()
+}
+
+// Manager implements idleness detection and calls the configured Enforcer to
+// enter/exit idle mode when appropriate. Must be created by NewManager.
+type Manager struct {
+ // State accessed atomically.
+ lastCallEndTime int64 // Unix timestamp in nanos; time when the most recent RPC completed.
+ activeCallsCount int32 // Count of active RPCs; -math.MaxInt32 means channel is idle or is trying to get there.
+ activeSinceLastTimerCheck int32 // Boolean; True if there was an RPC since the last timer callback.
+ closed int32 // Boolean; True when the manager is closed.
+
+ // Can be accessed without atomics or mutex since these are set at creation
+ // time and read-only after that.
+ enforcer Enforcer // Functionality provided by grpc.ClientConn.
+ timeout time.Duration
+
+ // idleMu is used to guarantee mutual exclusion in two scenarios:
+ // - Opposing intentions:
+ // - a: Idle timeout has fired and handleIdleTimeout() is trying to put
+ // the channel in idle mode because the channel has been inactive.
+ // - b: At the same time an RPC is made on the channel, and OnCallBegin()
+ // is trying to prevent the channel from going idle.
+ // - Competing intentions:
+ // - The channel is in idle mode and there are multiple RPCs starting at
+ // the same time, all trying to move the channel out of idle. Only one
+ // of them should succeed in doing so, while the other RPCs should
+ // piggyback on the first one and be successfully handled.
+ idleMu sync.RWMutex
+ actuallyIdle bool
+ timer *time.Timer
+}
+
+// NewManager creates a new idleness manager implementation for the
+// given idle timeout. It begins in idle mode.
+func NewManager(enforcer Enforcer, timeout time.Duration) *Manager {
+ return &Manager{
+ enforcer: enforcer,
+ timeout: timeout,
+ actuallyIdle: true,
+ activeCallsCount: -math.MaxInt32,
+ }
+}
+
+// resetIdleTimerLocked resets the idle timer to the given duration. Called
+// when exiting idle mode or when the timer fires and we need to reset it.
+func (m *Manager) resetIdleTimerLocked(d time.Duration) {
+ if m.isClosed() || m.timeout == 0 || m.actuallyIdle {
+ return
+ }
+
+ // It is safe to ignore the return value from Reset() because this method is
+ // only ever called from the timer callback or when exiting idle mode.
+ if m.timer != nil {
+ m.timer.Stop()
+ }
+ m.timer = timeAfterFunc(d, m.handleIdleTimeout)
+}
+
+func (m *Manager) resetIdleTimer(d time.Duration) {
+ m.idleMu.Lock()
+ defer m.idleMu.Unlock()
+ m.resetIdleTimerLocked(d)
+}
+
+// handleIdleTimeout is the timer callback that is invoked upon expiry of the
+// configured idle timeout. The channel is considered inactive if there are no
+// ongoing calls and no RPC activity since the last time the timer fired.
+func (m *Manager) handleIdleTimeout() {
+ if m.isClosed() {
+ return
+ }
+
+ if atomic.LoadInt32(&m.activeCallsCount) > 0 {
+ m.resetIdleTimer(m.timeout)
+ return
+ }
+
+ // There has been activity on the channel since we last got here. Reset the
+ // timer and return.
+ if atomic.LoadInt32(&m.activeSinceLastTimerCheck) == 1 {
+ // Set the timer to fire after a duration of idle timeout, calculated
+ // from the time the most recent RPC completed.
+ atomic.StoreInt32(&m.activeSinceLastTimerCheck, 0)
+ m.resetIdleTimer(time.Duration(atomic.LoadInt64(&m.lastCallEndTime)-time.Now().UnixNano()) + m.timeout)
+ return
+ }
+
+ // Now that we've checked that there has been no activity, attempt to enter
+ // idle mode, which is very likely to succeed.
+ if m.tryEnterIdleMode() {
+ // Successfully entered idle mode. No timer needed until we exit idle.
+ return
+ }
+
+ // Failed to enter idle mode due to a concurrent RPC that kept the channel
+ // active, or because of an error from the channel. Undo the attempt to
+ // enter idle, and reset the timer to try again later.
+ m.resetIdleTimer(m.timeout)
+}
+
+// tryEnterIdleMode instructs the channel to enter idle mode. But before
+// that, it performs a last minute check to ensure that no new RPC has come in,
+// making the channel active.
+//
+// Return value indicates whether or not the channel moved to idle mode.
+//
+// Holds idleMu which ensures mutual exclusion with exitIdleMode.
+func (m *Manager) tryEnterIdleMode() bool {
+ // Setting the activeCallsCount to -math.MaxInt32 indicates to OnCallBegin()
+ // that the channel is either in idle mode or is trying to get there.
+ if !atomic.CompareAndSwapInt32(&m.activeCallsCount, 0, -math.MaxInt32) {
+ // This CAS operation can fail if an RPC started after we checked for
+ // activity in the timer handler, or one was ongoing from before the
+ // last time the timer fired, or if a test is attempting to enter idle
+ // mode without checking. In all cases, abort going into idle mode.
+ return false
+ }
+ // N.B. if we fail to enter idle mode after this, we must re-add
+ // math.MaxInt32 to m.activeCallsCount.
+
+ m.idleMu.Lock()
+ defer m.idleMu.Unlock()
+
+ if atomic.LoadInt32(&m.activeCallsCount) != -math.MaxInt32 {
+ // We raced and lost to a new RPC. Very rare, but stop entering idle.
+ atomic.AddInt32(&m.activeCallsCount, math.MaxInt32)
+ return false
+ }
+ if atomic.LoadInt32(&m.activeSinceLastTimerCheck) == 1 {
+ // A very short RPC could have come in (and also finished) after we
+ // checked for calls count and activity in handleIdleTimeout(), but
+ // before the CAS operation. So, we need to check for activity again.
+ atomic.AddInt32(&m.activeCallsCount, math.MaxInt32)
+ return false
+ }
+
+ // No new RPCs have come in since we set the active calls count value to
+ // -math.MaxInt32. And since we have the lock, it is safe to enter idle mode
+ // unconditionally now.
+ m.enforcer.EnterIdleMode()
+ m.actuallyIdle = true
+ return true
+}
+
+func (m *Manager) EnterIdleModeForTesting() {
+ m.tryEnterIdleMode()
+}
+
+// OnCallBegin is invoked at the start of every RPC.
+func (m *Manager) OnCallBegin() error {
+ if m.isClosed() {
+ return nil
+ }
+
+ if atomic.AddInt32(&m.activeCallsCount, 1) > 0 {
+ // Channel is not idle now. Set the activity bit and allow the call.
+ atomic.StoreInt32(&m.activeSinceLastTimerCheck, 1)
+ return nil
+ }
+
+ // Channel is either in idle mode or is in the process of moving to idle
+ // mode. Attempt to exit idle mode to allow this RPC.
+ if err := m.ExitIdleMode(); err != nil {
+ // Undo the increment to calls count, and return an error causing the
+ // RPC to fail.
+ atomic.AddInt32(&m.activeCallsCount, -1)
+ return err
+ }
+
+ atomic.StoreInt32(&m.activeSinceLastTimerCheck, 1)
+ return nil
+}
+
+// ExitIdleMode instructs m to call the enforcer's ExitIdleMode and update m's
+// internal state.
+func (m *Manager) ExitIdleMode() error {
+ // Holds idleMu which ensures mutual exclusion with tryEnterIdleMode.
+ m.idleMu.Lock()
+ defer m.idleMu.Unlock()
+
+ if m.isClosed() || !m.actuallyIdle {
+ // This can happen in three scenarios:
+ // - handleIdleTimeout() set the calls count to -math.MaxInt32 and called
+ // tryEnterIdleMode(). But before the latter could grab the lock, an RPC
+ // came in and OnCallBegin() noticed that the calls count is negative.
+ // - Channel is in idle mode, and multiple new RPCs come in at the same
+ // time, all of them notice a negative calls count in OnCallBegin and get
+ // here. The first one to get the lock would got the channel to exit idle.
+ // - Channel is not in idle mode, and the user calls Connect which calls
+ // m.ExitIdleMode.
+ //
+ // In any case, there is nothing to do here.
+ return nil
+ }
+
+ if err := m.enforcer.ExitIdleMode(); err != nil {
+ return fmt.Errorf("failed to exit idle mode: %w", err)
+ }
+
+ // Undo the idle entry process. This also respects any new RPC attempts.
+ atomic.AddInt32(&m.activeCallsCount, math.MaxInt32)
+ m.actuallyIdle = false
+
+ // Start a new timer to fire after the configured idle timeout.
+ m.resetIdleTimerLocked(m.timeout)
+ return nil
+}
+
+// OnCallEnd is invoked at the end of every RPC.
+func (m *Manager) OnCallEnd() {
+ if m.isClosed() {
+ return
+ }
+
+ // Record the time at which the most recent call finished.
+ atomic.StoreInt64(&m.lastCallEndTime, time.Now().UnixNano())
+
+ // Decrement the active calls count. This count can temporarily go negative
+ // when the timer callback is in the process of moving the channel to idle
+ // mode, but one or more RPCs come in and complete before the timer callback
+ // can get done with the process of moving to idle mode.
+ atomic.AddInt32(&m.activeCallsCount, -1)
+}
+
+func (m *Manager) isClosed() bool {
+ return atomic.LoadInt32(&m.closed) == 1
+}
+
+func (m *Manager) Close() {
+ atomic.StoreInt32(&m.closed, 1)
+
+ m.idleMu.Lock()
+ if m.timer != nil {
+ m.timer.Stop()
+ m.timer = nil
+ }
+ m.idleMu.Unlock()
+}
diff --git a/vendor/google.golang.org/grpc/internal/internal.go b/vendor/google.golang.org/grpc/internal/internal.go
index 42ff39c8..6c7ea6a5 100644
--- a/vendor/google.golang.org/grpc/internal/internal.go
+++ b/vendor/google.golang.org/grpc/internal/internal.go
@@ -30,7 +30,7 @@ import (
var (
// WithHealthCheckFunc is set by dialoptions.go
- WithHealthCheckFunc interface{} // func (HealthChecker) DialOption
+ WithHealthCheckFunc any // func (HealthChecker) DialOption
// HealthCheckFunc is used to provide client-side LB channel health checking
HealthCheckFunc HealthChecker
// BalancerUnregister is exported by package balancer to unregister a balancer.
@@ -38,8 +38,12 @@ var (
// KeepaliveMinPingTime is the minimum ping interval. This must be 10s by
// default, but tests may wish to set it lower for convenience.
KeepaliveMinPingTime = 10 * time.Second
+ // KeepaliveMinServerPingTime is the minimum ping interval for servers.
+ // This must be 1s by default, but tests may wish to set it lower for
+ // convenience.
+ KeepaliveMinServerPingTime = time.Second
// ParseServiceConfig parses a JSON representation of the service config.
- ParseServiceConfig interface{} // func(string) *serviceconfig.ParseResult
+ ParseServiceConfig any // func(string) *serviceconfig.ParseResult
// EqualServiceConfigForTesting is for testing service config generation and
// parsing. Both a and b should be returned by ParseServiceConfig.
// This function compares the config without rawJSON stripped, in case the
@@ -49,33 +53,33 @@ var (
// given name. This is set by package certprovider for use from xDS
// bootstrap code while parsing certificate provider configs in the
// bootstrap file.
- GetCertificateProviderBuilder interface{} // func(string) certprovider.Builder
+ GetCertificateProviderBuilder any // func(string) certprovider.Builder
// GetXDSHandshakeInfoForTesting returns a pointer to the xds.HandshakeInfo
// stored in the passed in attributes. This is set by
// credentials/xds/xds.go.
- GetXDSHandshakeInfoForTesting interface{} // func (*attributes.Attributes) *xds.HandshakeInfo
+ GetXDSHandshakeInfoForTesting any // func (*attributes.Attributes) *unsafe.Pointer
// GetServerCredentials returns the transport credentials configured on a
// gRPC server. An xDS-enabled server needs to know what type of credentials
// is configured on the underlying gRPC server. This is set by server.go.
- GetServerCredentials interface{} // func (*grpc.Server) credentials.TransportCredentials
+ GetServerCredentials any // func (*grpc.Server) credentials.TransportCredentials
// CanonicalString returns the canonical string of the code defined here:
// https://github.com/grpc/grpc/blob/master/doc/statuscodes.md.
//
// This is used in the 1.0 release of gcp/observability, and thus must not be
// deleted or changed.
- CanonicalString interface{} // func (codes.Code) string
- // DrainServerTransports initiates a graceful close of existing connections
- // on a gRPC server accepted on the provided listener address. An
- // xDS-enabled server invokes this method on a grpc.Server when a particular
- // listener moves to "not-serving" mode.
- DrainServerTransports interface{} // func(*grpc.Server, string)
+ CanonicalString any // func (codes.Code) string
+ // IsRegisteredMethod returns whether the passed in method is registered as
+ // a method on the server.
+ IsRegisteredMethod any // func(*grpc.Server, string) bool
+ // ServerFromContext returns the server from the context.
+ ServerFromContext any // func(context.Context) *grpc.Server
// AddGlobalServerOptions adds an array of ServerOption that will be
// effective globally for newly created servers. The priority will be: 1.
// user-provided; 2. this method; 3. default values.
//
// This is used in the 1.0 release of gcp/observability, and thus must not be
// deleted or changed.
- AddGlobalServerOptions interface{} // func(opt ...ServerOption)
+ AddGlobalServerOptions any // func(opt ...ServerOption)
// ClearGlobalServerOptions clears the array of extra ServerOption. This
// method is useful in testing and benchmarking.
//
@@ -88,14 +92,14 @@ var (
//
// This is used in the 1.0 release of gcp/observability, and thus must not be
// deleted or changed.
- AddGlobalDialOptions interface{} // func(opt ...DialOption)
+ AddGlobalDialOptions any // func(opt ...DialOption)
// DisableGlobalDialOptions returns a DialOption that prevents the
// ClientConn from applying the global DialOptions (set via
// AddGlobalDialOptions).
//
// This is used in the 1.0 release of gcp/observability, and thus must not be
// deleted or changed.
- DisableGlobalDialOptions interface{} // func() grpc.DialOption
+ DisableGlobalDialOptions any // func() grpc.DialOption
// ClearGlobalDialOptions clears the array of extra DialOption. This
// method is useful in testing and benchmarking.
//
@@ -104,23 +108,26 @@ var (
ClearGlobalDialOptions func()
// JoinDialOptions combines the dial options passed as arguments into a
// single dial option.
- JoinDialOptions interface{} // func(...grpc.DialOption) grpc.DialOption
+ JoinDialOptions any // func(...grpc.DialOption) grpc.DialOption
// JoinServerOptions combines the server options passed as arguments into a
// single server option.
- JoinServerOptions interface{} // func(...grpc.ServerOption) grpc.ServerOption
+ JoinServerOptions any // func(...grpc.ServerOption) grpc.ServerOption
// WithBinaryLogger returns a DialOption that specifies the binary logger
// for a ClientConn.
//
// This is used in the 1.0 release of gcp/observability, and thus must not be
// deleted or changed.
- WithBinaryLogger interface{} // func(binarylog.Logger) grpc.DialOption
+ WithBinaryLogger any // func(binarylog.Logger) grpc.DialOption
// BinaryLogger returns a ServerOption that can set the binary logger for a
// server.
//
// This is used in the 1.0 release of gcp/observability, and thus must not be
// deleted or changed.
- BinaryLogger interface{} // func(binarylog.Logger) grpc.ServerOption
+ BinaryLogger any // func(binarylog.Logger) grpc.ServerOption
+
+ // SubscribeToConnectivityStateChanges adds a grpcsync.Subscriber to a provided grpc.ClientConn
+ SubscribeToConnectivityStateChanges any // func(*grpc.ClientConn, grpcsync.Subscriber)
// NewXDSResolverWithConfigForTesting creates a new xds resolver builder using
// the provided xds bootstrap config instead of the global configuration from
@@ -131,7 +138,7 @@ var (
//
// This function should ONLY be used for testing and may not work with some
// other features, including the CSDS service.
- NewXDSResolverWithConfigForTesting interface{} // func([]byte) (resolver.Builder, error)
+ NewXDSResolverWithConfigForTesting any // func([]byte) (resolver.Builder, error)
// RegisterRLSClusterSpecifierPluginForTesting registers the RLS Cluster
// Specifier Plugin for testing purposes, regardless of the XDSRLS environment
@@ -163,7 +170,32 @@ var (
UnregisterRBACHTTPFilterForTesting func()
// ORCAAllowAnyMinReportingInterval is for examples/orca use ONLY.
- ORCAAllowAnyMinReportingInterval interface{} // func(so *orca.ServiceOptions)
+ ORCAAllowAnyMinReportingInterval any // func(so *orca.ServiceOptions)
+
+ // GRPCResolverSchemeExtraMetadata determines when gRPC will add extra
+ // metadata to RPCs.
+ GRPCResolverSchemeExtraMetadata string = "xds"
+
+ // EnterIdleModeForTesting gets the ClientConn to enter IDLE mode.
+ EnterIdleModeForTesting any // func(*grpc.ClientConn)
+
+ // ExitIdleModeForTesting gets the ClientConn to exit IDLE mode.
+ ExitIdleModeForTesting any // func(*grpc.ClientConn) error
+
+ ChannelzTurnOffForTesting func()
+
+ // TriggerXDSResourceNameNotFoundForTesting triggers the resource-not-found
+ // error for a given resource type and name. This is usually triggered when
+ // the associated watch timer fires. For testing purposes, having this
+ // function makes events more predictable than relying on timer events.
+ TriggerXDSResourceNameNotFoundForTesting any // func(func(xdsresource.Type, string), string, string) error
+
+ // TriggerXDSResourceNotFoundClient invokes the testing xDS Client singleton
+ // to invoke resource not found for a resource type name and 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)
)
// HealthChecker defines the signature of the client-side LB channel health checking function.
@@ -174,7 +206,7 @@ var (
//
// The health checking protocol is defined at:
// https://github.com/grpc/grpc/blob/master/doc/health-checking.md
-type HealthChecker func(ctx context.Context, newStream func(string) (interface{}, error), setConnectivityState func(connectivity.State, error), serviceName string) error
+type HealthChecker func(ctx context.Context, newStream func(string) (any, error), setConnectivityState func(connectivity.State, error), serviceName string) error
const (
// CredsBundleModeFallback switches GoogleDefaultCreds to fallback mode.
diff --git a/vendor/google.golang.org/grpc/internal/metadata/metadata.go b/vendor/google.golang.org/grpc/internal/metadata/metadata.go
index c82e608e..900bfb71 100644
--- a/vendor/google.golang.org/grpc/internal/metadata/metadata.go
+++ b/vendor/google.golang.org/grpc/internal/metadata/metadata.go
@@ -35,7 +35,7 @@ const mdKey = mdKeyType("grpc.internal.address.metadata")
type mdValue metadata.MD
-func (m mdValue) Equal(o interface{}) bool {
+func (m mdValue) Equal(o any) bool {
om, ok := o.(mdValue)
if !ok {
return false
diff --git a/vendor/google.golang.org/grpc/internal/pretty/pretty.go b/vendor/google.golang.org/grpc/internal/pretty/pretty.go
index 0177af4b..70331913 100644
--- a/vendor/google.golang.org/grpc/internal/pretty/pretty.go
+++ b/vendor/google.golang.org/grpc/internal/pretty/pretty.go
@@ -35,7 +35,7 @@ const jsonIndent = " "
// ToJSON marshals the input into a json string.
//
// If marshal fails, it falls back to fmt.Sprintf("%+v").
-func ToJSON(e interface{}) string {
+func ToJSON(e any) string {
switch ee := e.(type) {
case protov1.Message:
mm := jsonpb.Marshaler{Indent: jsonIndent}
diff --git a/vendor/google.golang.org/grpc/internal/resolver/config_selector.go b/vendor/google.golang.org/grpc/internal/resolver/config_selector.go
index c7a18a94..f0603871 100644
--- a/vendor/google.golang.org/grpc/internal/resolver/config_selector.go
+++ b/vendor/google.golang.org/grpc/internal/resolver/config_selector.go
@@ -92,7 +92,7 @@ type ClientStream interface {
// calling RecvMsg on the same stream at the same time, but it is not safe
// to call SendMsg on the same stream in different goroutines. It is also
// not safe to call CloseSend concurrently with SendMsg.
- SendMsg(m interface{}) error
+ SendMsg(m any) error
// RecvMsg blocks until it receives a message into m or the stream is
// done. It returns io.EOF when the stream completes successfully. On
// any other error, the stream is aborted and the error contains the RPC
@@ -101,7 +101,7 @@ type ClientStream interface {
// It is safe to have a goroutine calling SendMsg and another goroutine
// calling RecvMsg on the same stream at the same time, but it is not
// safe to call RecvMsg on the same stream in different goroutines.
- RecvMsg(m interface{}) error
+ RecvMsg(m any) error
}
// ClientInterceptor is an interceptor for gRPC client streams.
diff --git a/vendor/google.golang.org/grpc/internal/resolver/dns/dns_resolver.go b/vendor/google.golang.org/grpc/internal/resolver/dns/dns_resolver.go
index 09a667f3..b66dcb21 100644
--- a/vendor/google.golang.org/grpc/internal/resolver/dns/dns_resolver.go
+++ b/vendor/google.golang.org/grpc/internal/resolver/dns/dns_resolver.go
@@ -23,7 +23,6 @@ package dns
import (
"context"
"encoding/json"
- "errors"
"fmt"
"net"
"os"
@@ -37,6 +36,7 @@ import (
"google.golang.org/grpc/internal/backoff"
"google.golang.org/grpc/internal/envconfig"
"google.golang.org/grpc/internal/grpcrand"
+ "google.golang.org/grpc/internal/resolver/dns/internal"
"google.golang.org/grpc/resolver"
"google.golang.org/grpc/serviceconfig"
)
@@ -47,53 +47,37 @@ var EnableSRVLookups = false
var logger = grpclog.Component("dns")
-// Globals to stub out in tests. TODO: Perhaps these two can be combined into a
-// single variable for testing the resolver?
-var (
- newTimer = time.NewTimer
- newTimerDNSResRate = time.NewTimer
-)
-
func init() {
resolver.Register(NewBuilder())
+ internal.TimeAfterFunc = time.After
+ internal.NewNetResolver = newNetResolver
+ internal.AddressDialer = addressDialer
}
const (
defaultPort = "443"
defaultDNSSvrPort = "53"
golang = "GO"
- // txtPrefix is the prefix string to be prepended to the host name for txt record lookup.
+ // txtPrefix is the prefix string to be prepended to the host name for txt
+ // record lookup.
txtPrefix = "_grpc_config."
// In DNS, service config is encoded in a TXT record via the mechanism
// described in RFC-1464 using the attribute name grpc_config.
txtAttribute = "grpc_config="
)
-var (
- errMissingAddr = errors.New("dns resolver: missing address")
-
- // Addresses ending with a colon that is supposed to be the separator
- // between host and port is not allowed. E.g. "::" is a valid address as
- // it is an IPv6 address (host only) and "[::]:" is invalid as it ends with
- // a colon as the host and port separator
- errEndsWithColon = errors.New("dns resolver: missing port after port-separator colon")
-)
-
-var (
- defaultResolver netResolver = net.DefaultResolver
- // To prevent excessive re-resolution, we enforce a rate limit on DNS
- // resolution requests.
- minDNSResRate = 30 * time.Second
-)
-
-var customAuthorityDialler = func(authority string) func(ctx context.Context, network, address string) (net.Conn, error) {
- return func(ctx context.Context, network, address string) (net.Conn, error) {
+var addressDialer = func(address string) func(context.Context, string, string) (net.Conn, error) {
+ return func(ctx context.Context, network, _ string) (net.Conn, error) {
var dialer net.Dialer
- return dialer.DialContext(ctx, network, authority)
+ return dialer.DialContext(ctx, network, address)
}
}
-var customAuthorityResolver = func(authority string) (netResolver, error) {
+var newNetResolver = func(authority string) (internal.NetResolver, error) {
+ if authority == "" {
+ return net.DefaultResolver, nil
+ }
+
host, port, err := parseTarget(authority, defaultDNSSvrPort)
if err != nil {
return nil, err
@@ -103,7 +87,7 @@ var customAuthorityResolver = func(authority string) (netResolver, error) {
return &net.Resolver{
PreferGo: true,
- Dial: customAuthorityDialler(authorityWithPort),
+ Dial: internal.AddressDialer(authorityWithPort),
}, nil
}
@@ -114,7 +98,8 @@ func NewBuilder() resolver.Builder {
type dnsBuilder struct{}
-// Build creates and starts a DNS resolver that watches the name resolution of the target.
+// Build creates and starts a DNS resolver that watches the name resolution of
+// the target.
func (b *dnsBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) {
host, port, err := parseTarget(target.Endpoint(), defaultPort)
if err != nil {
@@ -140,13 +125,9 @@ func (b *dnsBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts
disableServiceConfig: opts.DisableServiceConfig,
}
- if target.URL.Host == "" {
- d.resolver = defaultResolver
- } else {
- d.resolver, err = customAuthorityResolver(target.URL.Host)
- if err != nil {
- return nil, err
- }
+ d.resolver, err = internal.NewNetResolver(target.URL.Host)
+ if err != nil {
+ return nil, err
}
d.wg.Add(1)
@@ -159,12 +140,6 @@ func (b *dnsBuilder) Scheme() string {
return "dns"
}
-type netResolver interface {
- LookupHost(ctx context.Context, host string) (addrs []string, err error)
- LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*net.SRV, err error)
- LookupTXT(ctx context.Context, name string) (txts []string, err error)
-}
-
// deadResolver is a resolver that does nothing.
type deadResolver struct{}
@@ -176,23 +151,26 @@ func (deadResolver) Close() {}
type dnsResolver struct {
host string
port string
- resolver netResolver
+ resolver internal.NetResolver
ctx context.Context
cancel context.CancelFunc
cc resolver.ClientConn
- // rn channel is used by ResolveNow() to force an immediate resolution of the target.
+ // rn channel is used by ResolveNow() to force an immediate resolution of the
+ // target.
rn chan struct{}
- // wg is used to enforce Close() to return after the watcher() goroutine has finished.
- // Otherwise, data race will be possible. [Race Example] in dns_resolver_test we
- // replace the real lookup functions with mocked ones to facilitate testing.
- // If Close() doesn't wait for watcher() goroutine finishes, race detector sometimes
- // will warns lookup (READ the lookup function pointers) inside watcher() goroutine
- // has data race with replaceNetFunc (WRITE the lookup function pointers).
+ // wg is used to enforce Close() to return after the watcher() goroutine has
+ // finished. Otherwise, data race will be possible. [Race Example] in
+ // dns_resolver_test we replace the real lookup functions with mocked ones to
+ // facilitate testing. If Close() doesn't wait for watcher() goroutine
+ // finishes, race detector sometimes will warns lookup (READ the lookup
+ // function pointers) inside watcher() goroutine has data race with
+ // replaceNetFunc (WRITE the lookup function pointers).
wg sync.WaitGroup
disableServiceConfig bool
}
-// ResolveNow invoke an immediate resolution of the target that this dnsResolver watches.
+// ResolveNow invoke an immediate resolution of the target that this
+// dnsResolver watches.
func (d *dnsResolver) ResolveNow(resolver.ResolveNowOptions) {
select {
case d.rn <- struct{}{}:
@@ -218,28 +196,27 @@ func (d *dnsResolver) watcher() {
err = d.cc.UpdateState(*state)
}
- var timer *time.Timer
+ var waitTime time.Duration
if err == nil {
- // Success resolving, wait for the next ResolveNow. However, also wait 30 seconds at the very least
- // to prevent constantly re-resolving.
+ // Success resolving, wait for the next ResolveNow. However, also wait 30
+ // seconds at the very least to prevent constantly re-resolving.
backoffIndex = 1
- timer = newTimerDNSResRate(minDNSResRate)
+ waitTime = internal.MinResolutionRate
select {
case <-d.ctx.Done():
- timer.Stop()
return
case <-d.rn:
}
} else {
- // Poll on an error found in DNS Resolver or an error received from ClientConn.
- timer = newTimer(backoff.DefaultExponential.Backoff(backoffIndex))
+ // Poll on an error found in DNS Resolver or an error received from
+ // ClientConn.
+ waitTime = backoff.DefaultExponential.Backoff(backoffIndex)
backoffIndex++
}
select {
case <-d.ctx.Done():
- timer.Stop()
return
- case <-timer.C:
+ case <-internal.TimeAfterFunc(waitTime):
}
}
}
@@ -278,7 +255,8 @@ func (d *dnsResolver) lookupSRV() ([]resolver.Address, error) {
}
func handleDNSError(err error, lookupType string) error {
- if dnsErr, ok := err.(*net.DNSError); ok && !dnsErr.IsTimeout && !dnsErr.IsTemporary {
+ dnsErr, ok := err.(*net.DNSError)
+ if ok && !dnsErr.IsTimeout && !dnsErr.IsTemporary {
// Timeouts and temporary errors should be communicated to gRPC to
// attempt another DNS query (with backoff). Other errors should be
// suppressed (they may represent the absence of a TXT record).
@@ -307,10 +285,12 @@ func (d *dnsResolver) lookupTXT() *serviceconfig.ParseResult {
res += s
}
- // TXT record must have "grpc_config=" attribute in order to be used as service config.
+ // TXT record must have "grpc_config=" attribute in order to be used as
+ // service config.
if !strings.HasPrefix(res, txtAttribute) {
logger.Warningf("dns: TXT record %v missing %v attribute", res, txtAttribute)
- // This is not an error; it is the equivalent of not having a service config.
+ // This is not an error; it is the equivalent of not having a service
+ // config.
return nil
}
sc := canaryingSC(strings.TrimPrefix(res, txtAttribute))
@@ -352,9 +332,10 @@ func (d *dnsResolver) lookup() (*resolver.State, error) {
return &state, nil
}
-// formatIP returns ok = false if addr is not a valid textual representation of an IP address.
-// If addr is an IPv4 address, return the addr and ok = true.
-// If addr is an IPv6 address, return the addr enclosed in square brackets and ok = true.
+// formatIP returns ok = false if addr is not a valid textual representation of
+// an IP address. If addr is an IPv4 address, return the addr and ok = true.
+// If addr is an IPv6 address, return the addr enclosed in square brackets and
+// ok = true.
func formatIP(addr string) (addrIP string, ok bool) {
ip := net.ParseIP(addr)
if ip == nil {
@@ -366,10 +347,10 @@ func formatIP(addr string) (addrIP string, ok bool) {
return "[" + addr + "]", true
}
-// parseTarget takes the user input target string and default port, returns formatted host and port info.
-// If target doesn't specify a port, set the port to be the defaultPort.
-// If target is in IPv6 format and host-name is enclosed in square brackets, brackets
-// are stripped when setting the host.
+// parseTarget takes the user input target string and default port, returns
+// formatted host and port info. If target doesn't specify a port, set the port
+// to be the defaultPort. If target is in IPv6 format and host-name is enclosed
+// in square brackets, brackets are stripped when setting the host.
// examples:
// target: "www.google.com" defaultPort: "443" returns host: "www.google.com", port: "443"
// target: "ipv4-host:80" defaultPort: "443" returns host: "ipv4-host", port: "80"
@@ -377,7 +358,7 @@ func formatIP(addr string) (addrIP string, ok bool) {
// target: ":80" defaultPort: "443" returns host: "localhost", port: "80"
func parseTarget(target, defaultPort string) (host, port string, err error) {
if target == "" {
- return "", "", errMissingAddr
+ return "", "", internal.ErrMissingAddr
}
if ip := net.ParseIP(target); ip != nil {
// target is an IPv4 or IPv6(without brackets) address
@@ -385,12 +366,14 @@ func parseTarget(target, defaultPort string) (host, port string, err error) {
}
if host, port, err = net.SplitHostPort(target); err == nil {
if port == "" {
- // If the port field is empty (target ends with colon), e.g. "[::1]:", this is an error.
- return "", "", errEndsWithColon
+ // If the port field is empty (target ends with colon), e.g. "[::1]:",
+ // this is an error.
+ return "", "", internal.ErrEndsWithColon
}
// target has port, i.e ipv4-host:port, [ipv6-host]:port, host-name:port
if host == "" {
- // Keep consistent with net.Dial(): If the host is empty, as in ":80", the local system is assumed.
+ // Keep consistent with net.Dial(): If the host is empty, as in ":80",
+ // the local system is assumed.
host = "localhost"
}
return host, port, nil
diff --git a/vendor/google.golang.org/grpc/internal/resolver/dns/internal/internal.go b/vendor/google.golang.org/grpc/internal/resolver/dns/internal/internal.go
new file mode 100644
index 00000000..c7fc557d
--- /dev/null
+++ b/vendor/google.golang.org/grpc/internal/resolver/dns/internal/internal.go
@@ -0,0 +1,70 @@
+/*
+ *
+ * Copyright 2023 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 internal contains functionality internal to the dns resolver package.
+package internal
+
+import (
+ "context"
+ "errors"
+ "net"
+ "time"
+)
+
+// NetResolver groups the methods on net.Resolver that are used by the DNS
+// resolver implementation. This allows the default net.Resolver instance to be
+// overidden from tests.
+type NetResolver interface {
+ LookupHost(ctx context.Context, host string) (addrs []string, err error)
+ LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*net.SRV, err error)
+ LookupTXT(ctx context.Context, name string) (txts []string, err error)
+}
+
+var (
+ // ErrMissingAddr is the error returned when building a DNS resolver when
+ // the provided target name is empty.
+ ErrMissingAddr = errors.New("dns resolver: missing address")
+
+ // ErrEndsWithColon is the error returned when building a DNS resolver when
+ // the provided target name ends with a colon that is supposed to be the
+ // separator between host and port. E.g. "::" is a valid address as it is
+ // an IPv6 address (host only) and "[::]:" is invalid as it ends with a
+ // colon as the host and port separator
+ ErrEndsWithColon = errors.New("dns resolver: missing port after port-separator colon")
+)
+
+// The following vars are overridden from tests.
+var (
+ // MinResolutionRate is the minimum rate at which re-resolutions are
+ // allowed. This helps to prevent excessive re-resolution.
+ MinResolutionRate = 30 * time.Second
+
+ // 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
+ // code, this can be used to control the amount of time the resolver is
+ // blocked waiting for the duration to elapse.
+ TimeAfterFunc func(time.Duration) <-chan time.Time
+
+ // NewNetResolver returns the net.Resolver instance for the given target.
+ NewNetResolver func(string) (NetResolver, error)
+
+ // AddressDialer is the dialer used to dial the DNS server. It accepts the
+ // Host portion of the URL corresponding to the user's dial target and
+ // returns a dial function.
+ AddressDialer func(address string) func(context.Context, string, string) (net.Conn, error)
+)
diff --git a/vendor/google.golang.org/grpc/internal/resolver/unix/unix.go b/vendor/google.golang.org/grpc/internal/resolver/unix/unix.go
index 16091168..27cd81af 100644
--- a/vendor/google.golang.org/grpc/internal/resolver/unix/unix.go
+++ b/vendor/google.golang.org/grpc/internal/resolver/unix/unix.go
@@ -61,6 +61,10 @@ func (b *builder) Scheme() string {
return b.scheme
}
+func (b *builder) OverrideAuthority(resolver.Target) string {
+ return "localhost"
+}
+
type nopResolver struct {
}
diff --git a/vendor/google.golang.org/grpc/internal/status/status.go b/vendor/google.golang.org/grpc/internal/status/status.go
index b0ead4f5..03ef2fed 100644
--- a/vendor/google.golang.org/grpc/internal/status/status.go
+++ b/vendor/google.golang.org/grpc/internal/status/status.go
@@ -43,13 +43,41 @@ type Status struct {
s *spb.Status
}
+// NewWithProto returns a new status including details from statusProto. This
+// is meant to be used by the gRPC library only.
+func NewWithProto(code codes.Code, message string, statusProto []string) *Status {
+ if len(statusProto) != 1 {
+ // No grpc-status-details bin header, or multiple; just ignore.
+ return &Status{s: &spb.Status{Code: int32(code), Message: message}}
+ }
+ st := &spb.Status{}
+ if err := proto.Unmarshal([]byte(statusProto[0]), st); err != nil {
+ // Probably not a google.rpc.Status proto; do not provide details.
+ return &Status{s: &spb.Status{Code: int32(code), Message: message}}
+ }
+ if st.Code == int32(code) {
+ // The codes match between the grpc-status header and the
+ // grpc-status-details-bin header; use the full details proto.
+ return &Status{s: st}
+ }
+ return &Status{
+ s: &spb.Status{
+ Code: int32(codes.Internal),
+ Message: fmt.Sprintf(
+ "grpc-status-details-bin mismatch: grpc-status=%v, grpc-message=%q, grpc-status-details-bin=%+v",
+ code, message, st,
+ ),
+ },
+ }
+}
+
// New returns a Status representing c and msg.
func New(c codes.Code, msg string) *Status {
return &Status{s: &spb.Status{Code: int32(c), Message: msg}}
}
// Newf returns New(c, fmt.Sprintf(format, a...)).
-func Newf(c codes.Code, format string, a ...interface{}) *Status {
+func Newf(c codes.Code, format string, a ...any) *Status {
return New(c, fmt.Sprintf(format, a...))
}
@@ -64,7 +92,7 @@ func Err(c codes.Code, msg string) error {
}
// Errorf returns Error(c, fmt.Sprintf(format, a...)).
-func Errorf(c codes.Code, format string, a ...interface{}) error {
+func Errorf(c codes.Code, format string, a ...any) error {
return Err(c, fmt.Sprintf(format, a...))
}
@@ -120,11 +148,11 @@ func (s *Status) WithDetails(details ...proto.Message) (*Status, error) {
// Details returns a slice of details messages attached to the status.
// If a detail cannot be decoded, the error is returned in place of the detail.
-func (s *Status) Details() []interface{} {
+func (s *Status) Details() []any {
if s == nil || s.s == nil {
return nil
}
- details := make([]interface{}, 0, len(s.s.Details))
+ details := make([]any, 0, len(s.s.Details))
for _, any := range s.s.Details {
detail := &ptypes.DynamicAny{}
if err := ptypes.UnmarshalAny(any, detail); err != nil {
diff --git a/vendor/google.golang.org/grpc/internal/tcp_keepalive_others.go b/vendor/google.golang.org/grpc/internal/tcp_keepalive_others.go
new file mode 100644
index 00000000..4f347edd
--- /dev/null
+++ b/vendor/google.golang.org/grpc/internal/tcp_keepalive_others.go
@@ -0,0 +1,29 @@
+//go:build !unix && !windows
+
+/*
+ * Copyright 2023 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 internal
+
+import (
+ "net"
+)
+
+// NetDialerWithTCPKeepalive returns a vanilla net.Dialer on non-unix platforms.
+func NetDialerWithTCPKeepalive() *net.Dialer {
+ return &net.Dialer{}
+}
diff --git a/vendor/google.golang.org/grpc/internal/tcp_keepalive_unix.go b/vendor/google.golang.org/grpc/internal/tcp_keepalive_unix.go
new file mode 100644
index 00000000..078137b7
--- /dev/null
+++ b/vendor/google.golang.org/grpc/internal/tcp_keepalive_unix.go
@@ -0,0 +1,54 @@
+//go:build unix
+
+/*
+ * Copyright 2023 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 internal
+
+import (
+ "net"
+ "syscall"
+ "time"
+
+ "golang.org/x/sys/unix"
+)
+
+// NetDialerWithTCPKeepalive returns a net.Dialer that enables TCP keepalives on
+// the underlying connection with OS default values for keepalive parameters.
+//
+// TODO: Once https://github.com/golang/go/issues/62254 lands, and the
+// appropriate Go version becomes less than our least supported Go version, we
+// should look into using the new API to make things more straightforward.
+func NetDialerWithTCPKeepalive() *net.Dialer {
+ return &net.Dialer{
+ // Setting a negative value here prevents the Go stdlib from overriding
+ // the values of TCP keepalive time and interval. It also prevents the
+ // Go stdlib from enabling TCP keepalives by default.
+ KeepAlive: time.Duration(-1),
+ // This method is called after the underlying network socket is created,
+ // but before dialing the socket (or calling its connect() method). The
+ // combination of unconditionally enabling TCP keepalives here, and
+ // disabling the overriding of TCP keepalive parameters by setting the
+ // KeepAlive field to a negative value above, results in OS defaults for
+ // the TCP keealive interval and time parameters.
+ Control: func(_, _ string, c syscall.RawConn) error {
+ return c.Control(func(fd uintptr) {
+ unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_KEEPALIVE, 1)
+ })
+ },
+ }
+}
diff --git a/vendor/google.golang.org/grpc/internal/tcp_keepalive_windows.go b/vendor/google.golang.org/grpc/internal/tcp_keepalive_windows.go
new file mode 100644
index 00000000..fd7d43a8
--- /dev/null
+++ b/vendor/google.golang.org/grpc/internal/tcp_keepalive_windows.go
@@ -0,0 +1,54 @@
+//go:build windows
+
+/*
+ * Copyright 2023 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 internal
+
+import (
+ "net"
+ "syscall"
+ "time"
+
+ "golang.org/x/sys/windows"
+)
+
+// NetDialerWithTCPKeepalive returns a net.Dialer that enables TCP keepalives on
+// the underlying connection with OS default values for keepalive parameters.
+//
+// TODO: Once https://github.com/golang/go/issues/62254 lands, and the
+// appropriate Go version becomes less than our least supported Go version, we
+// should look into using the new API to make things more straightforward.
+func NetDialerWithTCPKeepalive() *net.Dialer {
+ return &net.Dialer{
+ // Setting a negative value here prevents the Go stdlib from overriding
+ // the values of TCP keepalive time and interval. It also prevents the
+ // Go stdlib from enabling TCP keepalives by default.
+ KeepAlive: time.Duration(-1),
+ // This method is called after the underlying network socket is created,
+ // but before dialing the socket (or calling its connect() method). The
+ // combination of unconditionally enabling TCP keepalives here, and
+ // disabling the overriding of TCP keepalive parameters by setting the
+ // KeepAlive field to a negative value above, results in OS defaults for
+ // the TCP keealive interval and time parameters.
+ Control: func(_, _ string, c syscall.RawConn) error {
+ return c.Control(func(fd uintptr) {
+ windows.SetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_KEEPALIVE, 1)
+ })
+ },
+ }
+}
diff --git a/vendor/google.golang.org/grpc/internal/transport/controlbuf.go b/vendor/google.golang.org/grpc/internal/transport/controlbuf.go
index be5a9c81..83c38298 100644
--- a/vendor/google.golang.org/grpc/internal/transport/controlbuf.go
+++ b/vendor/google.golang.org/grpc/internal/transport/controlbuf.go
@@ -40,7 +40,7 @@ var updateHeaderTblSize = func(e *hpack.Encoder, v uint32) {
}
type itemNode struct {
- it interface{}
+ it any
next *itemNode
}
@@ -49,7 +49,7 @@ type itemList struct {
tail *itemNode
}
-func (il *itemList) enqueue(i interface{}) {
+func (il *itemList) enqueue(i any) {
n := &itemNode{it: i}
if il.tail == nil {
il.head, il.tail = n, n
@@ -61,11 +61,11 @@ func (il *itemList) enqueue(i interface{}) {
// peek returns the first item in the list without removing it from the
// list.
-func (il *itemList) peek() interface{} {
+func (il *itemList) peek() any {
return il.head.it
}
-func (il *itemList) dequeue() interface{} {
+func (il *itemList) dequeue() any {
if il.head == nil {
return nil
}
@@ -336,7 +336,7 @@ func (c *controlBuffer) put(it cbItem) error {
return err
}
-func (c *controlBuffer) executeAndPut(f func(it interface{}) bool, it cbItem) (bool, error) {
+func (c *controlBuffer) executeAndPut(f func(it any) bool, it cbItem) (bool, error) {
var wakeUp bool
c.mu.Lock()
if c.err != nil {
@@ -373,7 +373,7 @@ func (c *controlBuffer) executeAndPut(f func(it interface{}) bool, it cbItem) (b
}
// Note argument f should never be nil.
-func (c *controlBuffer) execute(f func(it interface{}) bool, it interface{}) (bool, error) {
+func (c *controlBuffer) execute(f func(it any) bool, it any) (bool, error) {
c.mu.Lock()
if c.err != nil {
c.mu.Unlock()
@@ -387,7 +387,7 @@ func (c *controlBuffer) execute(f func(it interface{}) bool, it interface{}) (bo
return true, nil
}
-func (c *controlBuffer) get(block bool) (interface{}, error) {
+func (c *controlBuffer) get(block bool) (any, error) {
for {
c.mu.Lock()
if c.err != nil {
@@ -535,8 +535,8 @@ const minBatchSize = 1000
// size is too low to give stream goroutines a chance to fill it up.
//
// Upon exiting, if the error causing the exit is not an I/O error, run()
-// flushes and closes the underlying connection. Otherwise, the connection is
-// left open to allow the I/O error to be encountered by the reader instead.
+// flushes the underlying connection. The connection is always left open to
+// allow different closing behavior on the client and server.
func (l *loopyWriter) run() (err error) {
defer func() {
if l.logger.V(logLevel) {
@@ -544,7 +544,6 @@ func (l *loopyWriter) run() (err error) {
}
if !isIOError(err) {
l.framer.writer.Flush()
- l.conn.Close()
}
l.cbuf.finish()
}()
@@ -830,7 +829,7 @@ func (l *loopyWriter) goAwayHandler(g *goAway) error {
return nil
}
-func (l *loopyWriter) handle(i interface{}) error {
+func (l *loopyWriter) handle(i any) error {
switch i := i.(type) {
case *incomingWindowUpdate:
l.incomingWindowUpdateHandler(i)
diff --git a/vendor/google.golang.org/grpc/internal/transport/handler_server.go b/vendor/google.golang.org/grpc/internal/transport/handler_server.go
index 98f80e3f..a9d70e2a 100644
--- a/vendor/google.golang.org/grpc/internal/transport/handler_server.go
+++ b/vendor/google.golang.org/grpc/internal/transport/handler_server.go
@@ -75,11 +75,25 @@ func NewServerHandlerTransport(w http.ResponseWriter, r *http.Request, stats []s
return nil, errors.New(msg)
}
+ var localAddr net.Addr
+ if la := r.Context().Value(http.LocalAddrContextKey); la != nil {
+ localAddr, _ = la.(net.Addr)
+ }
+ var authInfo credentials.AuthInfo
+ if r.TLS != nil {
+ authInfo = credentials.TLSInfo{State: *r.TLS, CommonAuthInfo: credentials.CommonAuthInfo{SecurityLevel: credentials.PrivacyAndIntegrity}}
+ }
+ p := peer.Peer{
+ Addr: strAddr(r.RemoteAddr),
+ LocalAddr: localAddr,
+ AuthInfo: authInfo,
+ }
st := &serverHandlerTransport{
rw: w,
req: r,
closedCh: make(chan struct{}),
writes: make(chan func()),
+ peer: p,
contentType: contentType,
contentSubtype: contentSubtype,
stats: stats,
@@ -134,6 +148,8 @@ type serverHandlerTransport struct {
headerMD metadata.MD
+ peer peer.Peer
+
closeOnce sync.Once
closedCh chan struct{} // closed on Close
@@ -165,7 +181,13 @@ func (ht *serverHandlerTransport) Close(err error) {
})
}
-func (ht *serverHandlerTransport) RemoteAddr() net.Addr { return strAddr(ht.req.RemoteAddr) }
+func (ht *serverHandlerTransport) Peer() *peer.Peer {
+ return &peer.Peer{
+ Addr: ht.peer.Addr,
+ LocalAddr: ht.peer.LocalAddr,
+ AuthInfo: ht.peer.AuthInfo,
+ }
+}
// strAddr is a net.Addr backed by either a TCP "ip:port" string, or
// the empty string if unknown.
@@ -220,18 +242,20 @@ func (ht *serverHandlerTransport) WriteStatus(s *Stream, st *status.Status) erro
h.Set("Grpc-Message", encodeGrpcMessage(m))
}
+ s.hdrMu.Lock()
if p := st.Proto(); p != nil && len(p.Details) > 0 {
+ delete(s.trailer, grpcStatusDetailsBinHeader)
stBytes, err := proto.Marshal(p)
if err != nil {
// TODO: return error instead, when callers are able to handle it.
panic(err)
}
- h.Set("Grpc-Status-Details-Bin", encodeBinHeader(stBytes))
+ h.Set(grpcStatusDetailsBinHeader, encodeBinHeader(stBytes))
}
- if md := s.Trailer(); len(md) > 0 {
- for k, vv := range md {
+ if len(s.trailer) > 0 {
+ for k, vv := range s.trailer {
// Clients don't tolerate reading restricted headers after some non restricted ones were sent.
if isReservedHeader(k) {
continue
@@ -243,6 +267,7 @@ func (ht *serverHandlerTransport) WriteStatus(s *Stream, st *status.Status) erro
}
}
}
+ s.hdrMu.Unlock()
})
if err == nil { // transport has not been closed
@@ -287,7 +312,7 @@ func (ht *serverHandlerTransport) writeCommonHeaders(s *Stream) {
}
// writeCustomHeaders sets custom headers set on the stream via SetHeader
-// on the first write call (Write, WriteHeader, or WriteStatus).
+// on the first write call (Write, WriteHeader, or WriteStatus)
func (ht *serverHandlerTransport) writeCustomHeaders(s *Stream) {
h := ht.rw.Header()
@@ -344,10 +369,8 @@ func (ht *serverHandlerTransport) WriteHeader(s *Stream, md metadata.MD) error {
return err
}
-func (ht *serverHandlerTransport) HandleStreams(startStream func(*Stream), traceCtx func(context.Context, string) context.Context) {
+func (ht *serverHandlerTransport) HandleStreams(ctx context.Context, startStream func(*Stream)) {
// With this transport type there will be exactly 1 stream: this HTTP request.
-
- ctx := ht.req.Context()
var cancel context.CancelFunc
if ht.timeoutSet {
ctx, cancel = context.WithTimeout(ctx, ht.timeout)
@@ -367,34 +390,19 @@ func (ht *serverHandlerTransport) HandleStreams(startStream func(*Stream), trace
ht.Close(errors.New("request is done processing"))
}()
+ ctx = metadata.NewIncomingContext(ctx, ht.headerMD)
req := ht.req
-
s := &Stream{
- id: 0, // irrelevant
- requestRead: func(int) {},
- cancel: cancel,
- buf: newRecvBuffer(),
- st: ht,
- method: req.URL.Path,
- recvCompress: req.Header.Get("grpc-encoding"),
- contentSubtype: ht.contentSubtype,
- }
- pr := &peer.Peer{
- Addr: ht.RemoteAddr(),
- }
- if req.TLS != nil {
- pr.AuthInfo = credentials.TLSInfo{State: *req.TLS, CommonAuthInfo: credentials.CommonAuthInfo{SecurityLevel: credentials.PrivacyAndIntegrity}}
- }
- ctx = metadata.NewIncomingContext(ctx, ht.headerMD)
- s.ctx = peer.NewContext(ctx, pr)
- for _, sh := range ht.stats {
- s.ctx = sh.TagRPC(s.ctx, &stats.RPCTagInfo{FullMethodName: s.method})
- inHeader := &stats.InHeader{
- FullMethod: s.method,
- RemoteAddr: ht.RemoteAddr(),
- Compression: s.recvCompress,
- }
- sh.HandleRPC(s.ctx, inHeader)
+ id: 0, // irrelevant
+ ctx: ctx,
+ requestRead: func(int) {},
+ cancel: cancel,
+ buf: newRecvBuffer(),
+ st: ht,
+ method: req.URL.Path,
+ recvCompress: req.Header.Get("grpc-encoding"),
+ contentSubtype: ht.contentSubtype,
+ headerWireLength: 0, // won't have access to header wire length until golang/go#18997.
}
s.trReader = &transportReader{
reader: &recvBufferReader{ctx: s.ctx, ctxDone: s.ctx.Done(), recv: s.buf, freeBuffer: func(*bytes.Buffer) {}},
diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_client.go b/vendor/google.golang.org/grpc/internal/transport/http2_client.go
index 326bf084..eff87996 100644
--- a/vendor/google.golang.org/grpc/internal/transport/http2_client.go
+++ b/vendor/google.golang.org/grpc/internal/transport/http2_client.go
@@ -36,6 +36,7 @@ import (
"golang.org/x/net/http2/hpack"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials"
+ "google.golang.org/grpc/internal"
"google.golang.org/grpc/internal/channelz"
icredentials "google.golang.org/grpc/internal/credentials"
"google.golang.org/grpc/internal/grpclog"
@@ -43,7 +44,7 @@ import (
"google.golang.org/grpc/internal/grpcutil"
imetadata "google.golang.org/grpc/internal/metadata"
istatus "google.golang.org/grpc/internal/status"
- "google.golang.org/grpc/internal/syscall"
+ isyscall "google.golang.org/grpc/internal/syscall"
"google.golang.org/grpc/internal/transport/networktype"
"google.golang.org/grpc/keepalive"
"google.golang.org/grpc/metadata"
@@ -58,6 +59,8 @@ import (
// atomically.
var clientConnectionCounter uint64
+var metadataFromOutgoingContextRaw = internal.FromOutgoingContextRaw.(func(context.Context) (metadata.MD, [][]string, bool))
+
// http2Client implements the ClientTransport interface with HTTP2.
type http2Client struct {
lastRead int64 // Keep this field 64-bit aligned. Accessed atomically.
@@ -176,7 +179,7 @@ func dial(ctx context.Context, fn func(context.Context, string) (net.Conn, error
if networkType == "tcp" && useProxy {
return proxyDial(ctx, address, grpcUA)
}
- return (&net.Dialer{}).DialContext(ctx, networkType, address)
+ return internal.NetDialerWithTCPKeepalive().DialContext(ctx, networkType, address)
}
func isTemporary(err error) bool {
@@ -262,7 +265,7 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts
}
keepaliveEnabled := false
if kp.Time != infinity {
- if err = syscall.SetTCPUserTimeout(conn, kp.Timeout); err != nil {
+ if err = isyscall.SetTCPUserTimeout(conn, kp.Timeout); err != nil {
return nil, connectionErrorf(false, err, "transport: failed to set TCP_USER_TIMEOUT: %v", err)
}
keepaliveEnabled = true
@@ -330,7 +333,7 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts
readerDone: make(chan struct{}),
writerDone: make(chan struct{}),
goAway: make(chan struct{}),
- framer: newFramer(conn, writeBufSize, readBufSize, maxHeaderListSize),
+ framer: newFramer(conn, writeBufSize, readBufSize, opts.SharedWriteBuffer, maxHeaderListSize),
fc: &trInFlow{limit: uint32(icwz)},
scheme: scheme,
activeStreams: make(map[uint32]*Stream),
@@ -448,7 +451,13 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts
}
go func() {
t.loopy = newLoopyWriter(clientSide, t.framer, t.controlBuf, t.bdpEst, t.conn, t.logger)
- t.loopy.run()
+ if err := t.loopy.run(); !isIOError(err) {
+ // Immediately close the connection, as the loopy writer returns
+ // when there are no more active streams and we were draining (the
+ // server sent a GOAWAY). For I/O errors, the reader will hit it
+ // after draining any remaining incoming data.
+ t.conn.Close()
+ }
close(t.writerDone)
}()
return t, nil
@@ -493,8 +502,9 @@ func (t *http2Client) newStream(ctx context.Context, callHdr *CallHdr) *Stream {
func (t *http2Client) getPeer() *peer.Peer {
return &peer.Peer{
- Addr: t.remoteAddr,
- AuthInfo: t.authInfo, // Can be nil
+ Addr: t.remoteAddr,
+ AuthInfo: t.authInfo, // Can be nil
+ LocalAddr: t.localAddr,
}
}
@@ -566,7 +576,7 @@ func (t *http2Client) createHeaderFields(ctx context.Context, callHdr *CallHdr)
headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-trace-bin", Value: encodeBinHeader(b)})
}
- if md, added, ok := metadata.FromOutgoingContextRaw(ctx); ok {
+ if md, added, ok := metadataFromOutgoingContextRaw(ctx); ok {
var k string
for k, vv := range md {
// HTTP doesn't allow you to set pseudoheaders after non pseudoheaders were set.
@@ -762,7 +772,7 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (*Stream,
firstTry := true
var ch chan struct{}
transportDrainRequired := false
- checkForStreamQuota := func(it interface{}) bool {
+ checkForStreamQuota := func(it any) bool {
if t.streamQuota <= 0 { // Can go negative if server decreases it.
if firstTry {
t.waitingStreams++
@@ -800,7 +810,7 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (*Stream,
return true
}
var hdrListSizeErr error
- checkForHeaderListSize := func(it interface{}) bool {
+ checkForHeaderListSize := func(it any) bool {
if t.maxSendHeaderListSize == nil {
return true
}
@@ -815,7 +825,7 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (*Stream,
return true
}
for {
- success, err := t.controlBuf.executeAndPut(func(it interface{}) bool {
+ success, err := t.controlBuf.executeAndPut(func(it any) bool {
return checkForHeaderListSize(it) && checkForStreamQuota(it)
}, hdr)
if err != nil {
@@ -927,7 +937,7 @@ func (t *http2Client) closeStream(s *Stream, err error, rst bool, rstCode http2.
rst: rst,
rstCode: rstCode,
}
- addBackStreamQuota := func(interface{}) bool {
+ addBackStreamQuota := func(any) bool {
t.streamQuota++
if t.streamQuota > 0 && t.waitingStreams > 0 {
select {
@@ -1080,7 +1090,7 @@ func (t *http2Client) updateWindow(s *Stream, n uint32) {
// for the transport and the stream based on the current bdp
// estimation.
func (t *http2Client) updateFlowControl(n uint32) {
- updateIWS := func(interface{}) bool {
+ updateIWS := func(any) bool {
t.initialWindowSize = int32(n)
t.mu.Lock()
for _, s := range t.activeStreams {
@@ -1233,7 +1243,7 @@ func (t *http2Client) handleSettings(f *http2.SettingsFrame, isFirst bool) {
}
updateFuncs = append(updateFuncs, updateStreamQuota)
}
- t.controlBuf.executeAndPut(func(interface{}) bool {
+ t.controlBuf.executeAndPut(func(any) bool {
for _, f := range updateFuncs {
f()
}
@@ -1321,10 +1331,8 @@ func (t *http2Client) handleGoAway(f *http2.GoAwayFrame) {
for streamID, stream := range t.activeStreams {
if streamID > id && streamID <= upperLimit {
// The stream was unprocessed by the server.
- if streamID > id && streamID <= upperLimit {
- atomic.StoreUint32(&stream.unprocessed, 1)
- streamsToClose = append(streamsToClose, stream)
- }
+ atomic.StoreUint32(&stream.unprocessed, 1)
+ streamsToClose = append(streamsToClose, stream)
}
}
t.mu.Unlock()
@@ -1399,7 +1407,6 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
mdata = make(map[string][]string)
contentTypeErr = "malformed header: missing HTTP content-type"
grpcMessage string
- statusGen *status.Status
recvCompress string
httpStatusCode *int
httpStatusErr string
@@ -1434,12 +1441,6 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
rawStatusCode = codes.Code(uint32(code))
case "grpc-message":
grpcMessage = decodeGrpcMessage(hf.Value)
- case "grpc-status-details-bin":
- var err error
- statusGen, err = decodeGRPCStatusDetails(hf.Value)
- if err != nil {
- headerError = fmt.Sprintf("transport: malformed grpc-status-details-bin: %v", err)
- }
case ":status":
if hf.Value == "200" {
httpStatusErr = ""
@@ -1505,14 +1506,15 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
return
}
- isHeader := false
-
- // If headerChan hasn't been closed yet
- if atomic.CompareAndSwapUint32(&s.headerChanClosed, 0, 1) {
- s.headerValid = true
- if !endStream {
- // HEADERS frame block carries a Response-Headers.
- isHeader = true
+ // For headers, set them in s.header and close headerChan. For trailers or
+ // trailers-only, closeStream will set the trailers and close headerChan as
+ // needed.
+ if !endStream {
+ // If headerChan hasn't been closed yet (expected, given we checked it
+ // above, but something else could have potentially closed the whole
+ // stream).
+ if atomic.CompareAndSwapUint32(&s.headerChanClosed, 0, 1) {
+ s.headerValid = true
// These values can be set without any synchronization because
// stream goroutine will read it only after seeing a closed
// headerChan which we'll close after setting this.
@@ -1520,15 +1522,12 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
if len(mdata) > 0 {
s.header = mdata
}
- } else {
- // HEADERS frame block carries a Trailers-Only.
- s.noHeaders = true
+ close(s.headerChan)
}
- close(s.headerChan)
}
for _, sh := range t.statsHandlers {
- if isHeader {
+ if !endStream {
inHeader := &stats.InHeader{
Client: true,
WireLength: int(frame.Header().Length),
@@ -1550,13 +1549,12 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
return
}
- if statusGen == nil {
- statusGen = status.New(rawStatusCode, grpcMessage)
- }
+ status := istatus.NewWithProto(rawStatusCode, grpcMessage, mdata[grpcStatusDetailsBinHeader])
- // if client received END_STREAM from server while stream was still active, send RST_STREAM
- rst := s.getState() == streamActive
- t.closeStream(s, io.EOF, rst, http2.ErrCodeNo, statusGen, mdata, true)
+ // If client received END_STREAM from server while stream was still active,
+ // send RST_STREAM.
+ rstStream := s.getState() == streamActive
+ t.closeStream(s, io.EOF, rstStream, http2.ErrCodeNo, status, mdata, true)
}
// readServerPreface reads and handles the initial settings frame from the
diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_server.go b/vendor/google.golang.org/grpc/internal/transport/http2_server.go
index ec4eef21..a206e2ee 100644
--- a/vendor/google.golang.org/grpc/internal/transport/http2_server.go
+++ b/vendor/google.golang.org/grpc/internal/transport/http2_server.go
@@ -68,18 +68,15 @@ var serverConnectionCounter uint64
// http2Server implements the ServerTransport interface with HTTP2.
type http2Server struct {
- lastRead int64 // Keep this field 64-bit aligned. Accessed atomically.
- ctx context.Context
- done chan struct{}
- conn net.Conn
- loopy *loopyWriter
- readerDone chan struct{} // sync point to enable testing.
- writerDone chan struct{} // sync point to enable testing.
- remoteAddr net.Addr
- localAddr net.Addr
- authInfo credentials.AuthInfo // auth info about the connection
- inTapHandle tap.ServerInHandle
- framer *framer
+ lastRead int64 // Keep this field 64-bit aligned. Accessed atomically.
+ done chan struct{}
+ conn net.Conn
+ loopy *loopyWriter
+ readerDone chan struct{} // sync point to enable testing.
+ loopyWriterDone chan struct{}
+ peer peer.Peer
+ inTapHandle tap.ServerInHandle
+ framer *framer
// The max number of concurrent streams.
maxStreams uint32
// controlBuf delivers all the control related tasks (e.g., window
@@ -165,7 +162,7 @@ func NewServerTransport(conn net.Conn, config *ServerConfig) (_ ServerTransport,
if config.MaxHeaderListSize != nil {
maxHeaderListSize = *config.MaxHeaderListSize
}
- framer := newFramer(conn, writeBufSize, readBufSize, maxHeaderListSize)
+ framer := newFramer(conn, writeBufSize, readBufSize, config.SharedWriteBuffer, maxHeaderListSize)
// Send initial settings as connection preface to client.
isettings := []http2.Setting{{
ID: http2.SettingMaxFrameSize,
@@ -233,7 +230,7 @@ func NewServerTransport(conn net.Conn, config *ServerConfig) (_ ServerTransport,
kp.Timeout = defaultServerKeepaliveTimeout
}
if kp.Time != infinity {
- if err = syscall.SetTCPUserTimeout(conn, kp.Timeout); err != nil {
+ if err = syscall.SetTCPUserTimeout(rawConn, kp.Timeout); err != nil {
return nil, connectionErrorf(false, err, "transport: failed to set TCP_USER_TIMEOUT: %v", err)
}
}
@@ -243,16 +240,18 @@ func NewServerTransport(conn net.Conn, config *ServerConfig) (_ ServerTransport,
}
done := make(chan struct{})
+ peer := peer.Peer{
+ Addr: conn.RemoteAddr(),
+ LocalAddr: conn.LocalAddr(),
+ AuthInfo: authInfo,
+ }
t := &http2Server{
- ctx: setConnection(context.Background(), rawConn),
done: done,
conn: conn,
- remoteAddr: conn.RemoteAddr(),
- localAddr: conn.LocalAddr(),
- authInfo: authInfo,
+ peer: peer,
framer: framer,
readerDone: make(chan struct{}),
- writerDone: make(chan struct{}),
+ loopyWriterDone: make(chan struct{}),
maxStreams: config.MaxStreams,
inTapHandle: config.InTapHandle,
fc: &trInFlow{limit: uint32(icwz)},
@@ -267,8 +266,6 @@ func NewServerTransport(conn net.Conn, config *ServerConfig) (_ ServerTransport,
bufferPool: newBufferPool(),
}
t.logger = prefixLoggerForServerTransport(t)
- // Add peer information to the http2server context.
- t.ctx = peer.NewContext(t.ctx, t.getPeer())
t.controlBuf = newControlBuffer(t.done)
if dynamicWindow {
@@ -277,15 +274,7 @@ func NewServerTransport(conn net.Conn, config *ServerConfig) (_ ServerTransport,
updateFlowControl: t.updateFlowControl,
}
}
- for _, sh := range t.stats {
- t.ctx = sh.TagConn(t.ctx, &stats.ConnTagInfo{
- RemoteAddr: t.remoteAddr,
- LocalAddr: t.localAddr,
- })
- connBegin := &stats.ConnBegin{}
- sh.HandleConn(t.ctx, connBegin)
- }
- t.channelzID, err = channelz.RegisterNormalSocket(t, config.ChannelzParentID, fmt.Sprintf("%s -> %s", t.remoteAddr, t.localAddr))
+ t.channelzID, err = channelz.RegisterNormalSocket(t, config.ChannelzParentID, fmt.Sprintf("%s -> %s", t.peer.Addr, t.peer.LocalAddr))
if err != nil {
return nil, err
}
@@ -333,8 +322,24 @@ func NewServerTransport(conn net.Conn, config *ServerConfig) (_ ServerTransport,
go func() {
t.loopy = newLoopyWriter(serverSide, t.framer, t.controlBuf, t.bdpEst, t.conn, t.logger)
t.loopy.ssGoAwayHandler = t.outgoingGoAwayHandler
- t.loopy.run()
- close(t.writerDone)
+ err := t.loopy.run()
+ close(t.loopyWriterDone)
+ if !isIOError(err) {
+ // Close the connection if a non-I/O error occurs (for I/O errors
+ // the reader will also encounter the error and close). Wait 1
+ // second before closing the connection, or when the reader is done
+ // (i.e. the client already closed the connection or a connection
+ // error occurred). This avoids the potential problem where there
+ // is unread data on the receive side of the connection, which, if
+ // closed, would lead to a TCP RST instead of FIN, and the client
+ // encountering errors. For more info:
+ // https://github.com/grpc/grpc-go/issues/5358
+ select {
+ case <-t.readerDone:
+ case <-time.After(time.Second):
+ }
+ t.conn.Close()
+ }
}()
go t.keepalive()
return t, nil
@@ -342,7 +347,7 @@ func NewServerTransport(conn net.Conn, config *ServerConfig) (_ ServerTransport,
// operateHeaders takes action on the decoded headers. Returns an error if fatal
// error encountered and transport needs to close, otherwise returns nil.
-func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(*Stream), traceCtx func(context.Context, string) context.Context) error {
+func (t *http2Server) operateHeaders(ctx context.Context, frame *http2.MetaHeadersFrame, handle func(*Stream)) error {
// Acquire max stream ID lock for entire duration
t.maxStreamMu.Lock()
defer t.maxStreamMu.Unlock()
@@ -369,10 +374,11 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(
buf := newRecvBuffer()
s := &Stream{
- id: streamID,
- st: t,
- buf: buf,
- fc: &inFlow{limit: uint32(t.initialWindowSize)},
+ id: streamID,
+ st: t,
+ buf: buf,
+ fc: &inFlow{limit: uint32(t.initialWindowSize)},
+ headerWireLength: int(frame.Header().Length),
}
var (
// if false, content-type was missing or invalid
@@ -511,9 +517,9 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(
s.state = streamReadDone
}
if timeoutSet {
- s.ctx, s.cancel = context.WithTimeout(t.ctx, timeout)
+ s.ctx, s.cancel = context.WithTimeout(ctx, timeout)
} else {
- s.ctx, s.cancel = context.WithCancel(t.ctx)
+ s.ctx, s.cancel = context.WithCancel(ctx)
}
// Attach the received metadata to the context.
@@ -561,7 +567,7 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(
}
if t.inTapHandle != nil {
var err error
- if s.ctx, err = t.inTapHandle(s.ctx, &tap.Info{FullMethodName: s.method}); err != nil {
+ if s.ctx, err = t.inTapHandle(s.ctx, &tap.Info{FullMethodName: s.method, Header: mdata}); err != nil {
t.mu.Unlock()
if t.logger.V(logLevel) {
t.logger.Infof("Aborting the stream early due to InTapHandle failure: %v", err)
@@ -592,19 +598,6 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(
s.requestRead = func(n int) {
t.adjustWindow(s, uint32(n))
}
- s.ctx = traceCtx(s.ctx, s.method)
- for _, sh := range t.stats {
- s.ctx = sh.TagRPC(s.ctx, &stats.RPCTagInfo{FullMethodName: s.method})
- inHeader := &stats.InHeader{
- FullMethod: s.method,
- RemoteAddr: t.remoteAddr,
- LocalAddr: t.localAddr,
- Compression: s.recvCompress,
- WireLength: int(frame.Header().Length),
- Header: mdata.Copy(),
- }
- sh.HandleRPC(s.ctx, inHeader)
- }
s.ctxDone = s.ctx.Done()
s.wq = newWriteQuota(defaultWriteQuota, s.ctxDone)
s.trReader = &transportReader{
@@ -630,8 +623,11 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(
// HandleStreams receives incoming streams using the given handler. This is
// typically run in a separate goroutine.
// traceCtx attaches trace to ctx and returns the new context.
-func (t *http2Server) HandleStreams(handle func(*Stream), traceCtx func(context.Context, string) context.Context) {
- defer close(t.readerDone)
+func (t *http2Server) HandleStreams(ctx context.Context, handle func(*Stream)) {
+ defer func() {
+ close(t.readerDone)
+ <-t.loopyWriterDone
+ }()
for {
t.controlBuf.throttle()
frame, err := t.framer.fr.ReadFrame()
@@ -665,7 +661,7 @@ func (t *http2Server) HandleStreams(handle func(*Stream), traceCtx func(context.
}
switch frame := frame.(type) {
case *http2.MetaHeadersFrame:
- if err := t.operateHeaders(frame, handle, traceCtx); err != nil {
+ if err := t.operateHeaders(ctx, frame, handle); err != nil {
t.Close(err)
break
}
@@ -850,7 +846,7 @@ func (t *http2Server) handleSettings(f *http2.SettingsFrame) {
}
return nil
})
- t.controlBuf.executeAndPut(func(interface{}) bool {
+ t.controlBuf.executeAndPut(func(any) bool {
for _, f := range updateFuncs {
f()
}
@@ -934,7 +930,7 @@ func appendHeaderFieldsFromMD(headerFields []hpack.HeaderField, md metadata.MD)
return headerFields
}
-func (t *http2Server) checkForHeaderListSize(it interface{}) bool {
+func (t *http2Server) checkForHeaderListSize(it any) bool {
if t.maxSendHeaderListSize == nil {
return true
}
@@ -980,7 +976,12 @@ func (t *http2Server) WriteHeader(s *Stream, md metadata.MD) error {
}
}
if err := t.writeHeaderLocked(s); err != nil {
- return status.Convert(err).Err()
+ switch e := err.(type) {
+ case ConnectionError:
+ return status.Error(codes.Unavailable, e.Desc)
+ default:
+ return status.Convert(err).Err()
+ }
}
return nil
}
@@ -1053,12 +1054,15 @@ func (t *http2Server) WriteStatus(s *Stream, st *status.Status) error {
headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-message", Value: encodeGrpcMessage(st.Message())})
if p := st.Proto(); p != nil && len(p.Details) > 0 {
+ // Do not use the user's grpc-status-details-bin (if present) if we are
+ // even attempting to set our own.
+ delete(s.trailer, grpcStatusDetailsBinHeader)
stBytes, err := proto.Marshal(p)
if err != nil {
// TODO: return error instead, when callers are able to handle it.
t.logger.Errorf("Failed to marshal rpc status: %s, error: %v", pretty.ToJSON(p), err)
} else {
- headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-status-details-bin", Value: encodeBinHeader(stBytes)})
+ headerFields = append(headerFields, hpack.HeaderField{Name: grpcStatusDetailsBinHeader, Value: encodeBinHeader(stBytes)})
}
}
@@ -1240,10 +1244,6 @@ func (t *http2Server) Close(err error) {
for _, s := range streams {
s.cancel()
}
- for _, sh := range t.stats {
- connEnd := &stats.ConnEnd{}
- sh.HandleConn(t.ctx, connEnd)
- }
}
// deleteStream deletes the stream s from transport's active streams.
@@ -1309,10 +1309,6 @@ func (t *http2Server) closeStream(s *Stream, rst bool, rstCode http2.ErrCode, eo
})
}
-func (t *http2Server) RemoteAddr() net.Addr {
- return t.remoteAddr
-}
-
func (t *http2Server) Drain(debugData string) {
t.mu.Lock()
defer t.mu.Unlock()
@@ -1349,6 +1345,7 @@ func (t *http2Server) outgoingGoAwayHandler(g *goAway) (bool, error) {
if err := t.framer.fr.WriteGoAway(sid, g.code, g.debugData); err != nil {
return false, err
}
+ t.framer.writer.Flush()
if retErr != nil {
return false, retErr
}
@@ -1369,7 +1366,7 @@ func (t *http2Server) outgoingGoAwayHandler(g *goAway) (bool, error) {
return false, err
}
go func() {
- timer := time.NewTimer(time.Minute)
+ timer := time.NewTimer(5 * time.Second)
defer timer.Stop()
select {
case <-t.drainEvent.Done():
@@ -1395,11 +1392,11 @@ func (t *http2Server) ChannelzMetric() *channelz.SocketInternalMetric {
LastMessageReceivedTimestamp: time.Unix(0, atomic.LoadInt64(&t.czData.lastMsgRecvTime)),
LocalFlowControlWindow: int64(t.fc.getSize()),
SocketOptions: channelz.GetSocketOption(t.conn),
- LocalAddr: t.localAddr,
- RemoteAddr: t.remoteAddr,
+ LocalAddr: t.peer.LocalAddr,
+ RemoteAddr: t.peer.Addr,
// RemoteName :
}
- if au, ok := t.authInfo.(credentials.ChannelzSecurityInfo); ok {
+ if au, ok := t.peer.AuthInfo.(credentials.ChannelzSecurityInfo); ok {
s.Security = au.GetSecurityValue()
}
s.RemoteFlowControlWindow = t.getOutFlowWindow()
@@ -1431,10 +1428,12 @@ func (t *http2Server) getOutFlowWindow() int64 {
}
}
-func (t *http2Server) getPeer() *peer.Peer {
+// Peer returns the peer of the transport.
+func (t *http2Server) Peer() *peer.Peer {
return &peer.Peer{
- Addr: t.remoteAddr,
- AuthInfo: t.authInfo, // Can be nil
+ Addr: t.peer.Addr,
+ LocalAddr: t.peer.LocalAddr,
+ AuthInfo: t.peer.AuthInfo, // Can be nil
}
}
@@ -1459,6 +1458,6 @@ func GetConnection(ctx context.Context) net.Conn {
// SetConnection adds the connection to the context to be able to get
// information about the destination ip and port for an incoming RPC. This also
// allows any unary or streaming interceptors to see the connection.
-func setConnection(ctx context.Context, conn net.Conn) context.Context {
+func SetConnection(ctx context.Context, conn net.Conn) context.Context {
return context.WithValue(ctx, connectionKey{}, conn)
}
diff --git a/vendor/google.golang.org/grpc/internal/transport/http_util.go b/vendor/google.golang.org/grpc/internal/transport/http_util.go
index 19cbb18f..dc29d590 100644
--- a/vendor/google.golang.org/grpc/internal/transport/http_util.go
+++ b/vendor/google.golang.org/grpc/internal/transport/http_util.go
@@ -30,15 +30,13 @@ import (
"net/url"
"strconv"
"strings"
+ "sync"
"time"
"unicode/utf8"
- "github.com/golang/protobuf/proto"
"golang.org/x/net/http2"
"golang.org/x/net/http2/hpack"
- spb "google.golang.org/genproto/googleapis/rpc/status"
"google.golang.org/grpc/codes"
- "google.golang.org/grpc/status"
)
const (
@@ -87,6 +85,8 @@ var (
}
)
+var grpcStatusDetailsBinHeader = "grpc-status-details-bin"
+
// isReservedHeader checks whether hdr belongs to HTTP2 headers
// reserved by gRPC protocol. Any other headers are classified as the
// user-specified metadata.
@@ -102,7 +102,6 @@ func isReservedHeader(hdr string) bool {
"grpc-message",
"grpc-status",
"grpc-timeout",
- "grpc-status-details-bin",
// Intentionally exclude grpc-previous-rpc-attempts and
// grpc-retry-pushback-ms, which are "reserved", but their API
// intentionally works via metadata.
@@ -153,18 +152,6 @@ func decodeMetadataHeader(k, v string) (string, error) {
return v, nil
}
-func decodeGRPCStatusDetails(rawDetails string) (*status.Status, error) {
- v, err := decodeBinHeader(rawDetails)
- if err != nil {
- return nil, err
- }
- st := &spb.Status{}
- if err = proto.Unmarshal(v, st); err != nil {
- return nil, err
- }
- return status.FromProto(st), nil
-}
-
type timeoutUnit uint8
const (
@@ -309,6 +296,7 @@ func decodeGrpcMessageUnchecked(msg string) string {
}
type bufWriter struct {
+ pool *sync.Pool
buf []byte
offset int
batchSize int
@@ -316,12 +304,17 @@ type bufWriter struct {
err error
}
-func newBufWriter(conn net.Conn, batchSize int) *bufWriter {
- return &bufWriter{
- buf: make([]byte, batchSize*2),
+func newBufWriter(conn net.Conn, batchSize int, pool *sync.Pool) *bufWriter {
+ w := &bufWriter{
batchSize: batchSize,
conn: conn,
+ pool: pool,
+ }
+ // this indicates that we should use non shared buf
+ if pool == nil {
+ w.buf = make([]byte, batchSize)
}
+ return w
}
func (w *bufWriter) Write(b []byte) (n int, err error) {
@@ -332,19 +325,34 @@ func (w *bufWriter) Write(b []byte) (n int, err error) {
n, err = w.conn.Write(b)
return n, toIOError(err)
}
+ if w.buf == nil {
+ b := w.pool.Get().(*[]byte)
+ w.buf = *b
+ }
for len(b) > 0 {
nn := copy(w.buf[w.offset:], b)
b = b[nn:]
w.offset += nn
n += nn
if w.offset >= w.batchSize {
- err = w.Flush()
+ err = w.flushKeepBuffer()
}
}
return n, err
}
func (w *bufWriter) Flush() error {
+ err := w.flushKeepBuffer()
+ // Only release the buffer if we are in a "shared" mode
+ if w.buf != nil && w.pool != nil {
+ b := w.buf
+ w.pool.Put(&b)
+ w.buf = nil
+ }
+ return err
+}
+
+func (w *bufWriter) flushKeepBuffer() error {
if w.err != nil {
return w.err
}
@@ -381,7 +389,10 @@ type framer struct {
fr *http2.Framer
}
-func newFramer(conn net.Conn, writeBufferSize, readBufferSize int, maxHeaderListSize uint32) *framer {
+var writeBufferPoolMap map[int]*sync.Pool = make(map[int]*sync.Pool)
+var writeBufferMutex sync.Mutex
+
+func newFramer(conn net.Conn, writeBufferSize, readBufferSize int, sharedWriteBuffer bool, maxHeaderListSize uint32) *framer {
if writeBufferSize < 0 {
writeBufferSize = 0
}
@@ -389,7 +400,11 @@ func newFramer(conn net.Conn, writeBufferSize, readBufferSize int, maxHeaderList
if readBufferSize > 0 {
r = bufio.NewReaderSize(r, readBufferSize)
}
- w := newBufWriter(conn, writeBufferSize)
+ var pool *sync.Pool
+ if sharedWriteBuffer {
+ pool = getWriteBufferPool(writeBufferSize)
+ }
+ w := newBufWriter(conn, writeBufferSize, pool)
f := &framer{
writer: w,
fr: http2.NewFramer(w, r),
@@ -403,6 +418,24 @@ func newFramer(conn net.Conn, writeBufferSize, readBufferSize int, maxHeaderList
return f
}
+func getWriteBufferPool(writeBufferSize int) *sync.Pool {
+ writeBufferMutex.Lock()
+ defer writeBufferMutex.Unlock()
+ size := writeBufferSize * 2
+ pool, ok := writeBufferPoolMap[size]
+ if ok {
+ return pool
+ }
+ pool = &sync.Pool{
+ New: func() any {
+ b := make([]byte, size)
+ return &b
+ },
+ }
+ writeBufferPoolMap[size] = pool
+ return pool
+}
+
// parseDialTarget returns the network and address to pass to dialer.
func parseDialTarget(target string) (string, string) {
net := "tcp"
diff --git a/vendor/google.golang.org/grpc/internal/transport/proxy.go b/vendor/google.golang.org/grpc/internal/transport/proxy.go
index 41596198..24fa1032 100644
--- a/vendor/google.golang.org/grpc/internal/transport/proxy.go
+++ b/vendor/google.golang.org/grpc/internal/transport/proxy.go
@@ -28,6 +28,8 @@ import (
"net/http"
"net/http/httputil"
"net/url"
+
+ "google.golang.org/grpc/internal"
)
const proxyAuthHeaderKey = "Proxy-Authorization"
@@ -112,7 +114,7 @@ func doHTTPConnectHandshake(ctx context.Context, conn net.Conn, backendAddr stri
// proxyDial dials, connecting to a proxy first if necessary. Checks if a proxy
// is necessary, dials, does the HTTP CONNECT handshake, and returns the
// connection.
-func proxyDial(ctx context.Context, addr string, grpcUA string) (conn net.Conn, err error) {
+func proxyDial(ctx context.Context, addr string, grpcUA string) (net.Conn, error) {
newAddr := addr
proxyURL, err := mapAddress(addr)
if err != nil {
@@ -122,15 +124,15 @@ func proxyDial(ctx context.Context, addr string, grpcUA string) (conn net.Conn,
newAddr = proxyURL.Host
}
- conn, err = (&net.Dialer{}).DialContext(ctx, "tcp", newAddr)
+ conn, err := internal.NetDialerWithTCPKeepalive().DialContext(ctx, "tcp", newAddr)
if err != nil {
- return
+ return nil, err
}
- if proxyURL != nil {
+ if proxyURL == nil {
// proxy is disabled if proxyURL is nil.
- conn, err = doHTTPConnectHandshake(ctx, conn, addr, proxyURL, grpcUA)
+ return conn, err
}
- return
+ return doHTTPConnectHandshake(ctx, conn, addr, proxyURL, grpcUA)
}
func sendHTTPRequest(ctx context.Context, req *http.Request, conn net.Conn) error {
diff --git a/vendor/google.golang.org/grpc/internal/transport/transport.go b/vendor/google.golang.org/grpc/internal/transport/transport.go
index aa1c8965..b7b8fec1 100644
--- a/vendor/google.golang.org/grpc/internal/transport/transport.go
+++ b/vendor/google.golang.org/grpc/internal/transport/transport.go
@@ -37,16 +37,13 @@ import (
"google.golang.org/grpc/internal/channelz"
"google.golang.org/grpc/keepalive"
"google.golang.org/grpc/metadata"
+ "google.golang.org/grpc/peer"
"google.golang.org/grpc/resolver"
"google.golang.org/grpc/stats"
"google.golang.org/grpc/status"
"google.golang.org/grpc/tap"
)
-// ErrNoHeaders is used as a signal that a trailers only response was received,
-// and is not a real error.
-var ErrNoHeaders = errors.New("stream has no headers")
-
const logLevel = 2
type bufferPool struct {
@@ -56,7 +53,7 @@ type bufferPool struct {
func newBufferPool() *bufferPool {
return &bufferPool{
pool: sync.Pool{
- New: func() interface{} {
+ New: func() any {
return new(bytes.Buffer)
},
},
@@ -269,7 +266,8 @@ type Stream struct {
// headerValid indicates whether a valid header was received. Only
// meaningful after headerChan is closed (always call waitOnHeader() before
// reading its value). Not valid on server side.
- headerValid bool
+ headerValid bool
+ headerWireLength int // Only set on server side.
// hdrMu protects header and trailer metadata on the server-side.
hdrMu sync.Mutex
@@ -390,14 +388,10 @@ func (s *Stream) Header() (metadata.MD, error) {
}
s.waitOnHeader()
- if !s.headerValid {
+ if !s.headerValid || s.noHeaders {
return nil, s.status.Err()
}
- if s.noHeaders {
- return nil, ErrNoHeaders
- }
-
return s.header.Copy(), nil
}
@@ -433,6 +427,12 @@ func (s *Stream) Context() context.Context {
return s.ctx
}
+// SetContext sets the context of the stream. This will be deleted once the
+// stats handler callouts all move to gRPC layer.
+func (s *Stream) SetContext(ctx context.Context) {
+ s.ctx = ctx
+}
+
// Method returns the method for the stream.
func (s *Stream) Method() string {
return s.method
@@ -445,6 +445,12 @@ func (s *Stream) Status() *status.Status {
return s.status
}
+// HeaderWireLength returns the size of the headers of the stream as received
+// from the wire. Valid only on the server.
+func (s *Stream) HeaderWireLength() int {
+ return s.headerWireLength
+}
+
// SetHeader sets the header metadata. This can be called multiple times.
// Server side only.
// This should not be called in parallel to other data writes.
@@ -559,6 +565,7 @@ type ServerConfig struct {
InitialConnWindowSize int32
WriteBufferSize int
ReadBufferSize int
+ SharedWriteBuffer bool
ChannelzParentID *channelz.Identifier
MaxHeaderListSize *uint32
HeaderTableSize *uint32
@@ -592,6 +599,8 @@ type ConnectOptions struct {
WriteBufferSize int
// ReadBufferSize sets the size of read buffer, which in turn determines how much data can be read at most for one read syscall.
ReadBufferSize int
+ // SharedWriteBuffer indicates whether connections should reuse write buffer
+ SharedWriteBuffer bool
// ChannelzParentID sets the addrConn id which initiate the creation of this client transport.
ChannelzParentID *channelz.Identifier
// MaxHeaderListSize sets the max (uncompressed) size of header list that is prepared to be received.
@@ -703,7 +712,7 @@ type ClientTransport interface {
// Write methods for a given Stream will be called serially.
type ServerTransport interface {
// HandleStreams receives incoming streams using the given handler.
- HandleStreams(func(*Stream), func(context.Context, string) context.Context)
+ HandleStreams(context.Context, func(*Stream))
// WriteHeader sends the header metadata for the given stream.
// WriteHeader may not be called on all streams.
@@ -722,8 +731,8 @@ type ServerTransport interface {
// handlers will be terminated asynchronously.
Close(err error)
- // RemoteAddr returns the remote network address.
- RemoteAddr() net.Addr
+ // Peer returns the peer of the server transport.
+ Peer() *peer.Peer
// Drain notifies the client this ServerTransport stops accepting new RPCs.
Drain(debugData string)
@@ -736,7 +745,7 @@ type ServerTransport interface {
}
// connectionErrorf creates an ConnectionError with the specified error description.
-func connectionErrorf(temp bool, e error, format string, a ...interface{}) ConnectionError {
+func connectionErrorf(temp bool, e error, format string, a ...any) ConnectionError {
return ConnectionError{
Desc: fmt.Sprintf(format, a...),
temp: temp,
diff --git a/vendor/google.golang.org/grpc/metadata/metadata.go b/vendor/google.golang.org/grpc/metadata/metadata.go
index a2cdcaf1..1e9485fd 100644
--- a/vendor/google.golang.org/grpc/metadata/metadata.go
+++ b/vendor/google.golang.org/grpc/metadata/metadata.go
@@ -25,8 +25,14 @@ import (
"context"
"fmt"
"strings"
+
+ "google.golang.org/grpc/internal"
)
+func init() {
+ internal.FromOutgoingContextRaw = fromOutgoingContextRaw
+}
+
// DecodeKeyValue returns k, v, nil.
//
// Deprecated: use k and v directly instead.
@@ -153,14 +159,16 @@ func Join(mds ...MD) MD {
type mdIncomingKey struct{}
type mdOutgoingKey struct{}
-// NewIncomingContext creates a new context with incoming md attached.
+// NewIncomingContext creates a new context with incoming md attached. md must
+// not be modified after calling this function.
func NewIncomingContext(ctx context.Context, md MD) context.Context {
return context.WithValue(ctx, mdIncomingKey{}, md)
}
// NewOutgoingContext creates a new context with outgoing md attached. If used
// in conjunction with AppendToOutgoingContext, NewOutgoingContext will
-// overwrite any previously-appended metadata.
+// overwrite any previously-appended metadata. md must not be modified after
+// calling this function.
func NewOutgoingContext(ctx context.Context, md MD) context.Context {
return context.WithValue(ctx, mdOutgoingKey{}, rawMD{md: md})
}
@@ -203,7 +211,8 @@ func FromIncomingContext(ctx context.Context) (MD, bool) {
}
// ValueFromIncomingContext returns the metadata value corresponding to the metadata
-// key from the incoming metadata if it exists. Key must be lower-case.
+// key from the incoming metadata if it exists. Keys are matched in a case insensitive
+// manner.
//
// # Experimental
//
@@ -219,33 +228,29 @@ func ValueFromIncomingContext(ctx context.Context, key string) []string {
return copyOf(v)
}
for k, v := range md {
- // We need to manually convert all keys to lower case, because MD is a
- // map, and there's no guarantee that the MD attached to the context is
- // created using our helper functions.
- if strings.ToLower(k) == key {
+ // Case insenitive comparison: MD is a map, and there's no guarantee
+ // that the MD attached to the context is created using our helper
+ // functions.
+ if strings.EqualFold(k, key) {
return copyOf(v)
}
}
return nil
}
-// the returned slice must not be modified in place
func copyOf(v []string) []string {
vals := make([]string, len(v))
copy(vals, v)
return vals
}
-// FromOutgoingContextRaw returns the un-merged, intermediary contents of rawMD.
+// fromOutgoingContextRaw returns the un-merged, intermediary contents of rawMD.
//
// Remember to perform strings.ToLower on the keys, for both the returned MD (MD
// is a map, there's no guarantee it's created using our helper functions) and
// the extra kv pairs (AppendToOutgoingContext doesn't turn them into
// lowercase).
-//
-// This is intended for gRPC-internal use ONLY. Users should use
-// FromOutgoingContext instead.
-func FromOutgoingContextRaw(ctx context.Context) (MD, [][]string, bool) {
+func fromOutgoingContextRaw(ctx context.Context) (MD, [][]string, bool) {
raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD)
if !ok {
return nil, nil, false
diff --git a/vendor/google.golang.org/grpc/peer/peer.go b/vendor/google.golang.org/grpc/peer/peer.go
index e01d219f..a821ff9b 100644
--- a/vendor/google.golang.org/grpc/peer/peer.go
+++ b/vendor/google.golang.org/grpc/peer/peer.go
@@ -32,6 +32,8 @@ import (
type Peer struct {
// Addr is the peer address.
Addr net.Addr
+ // LocalAddr is the local address.
+ LocalAddr net.Addr
// AuthInfo is the authentication information of the transport.
// It is nil if there is no transport security being used.
AuthInfo credentials.AuthInfo
diff --git a/vendor/google.golang.org/grpc/picker_wrapper.go b/vendor/google.golang.org/grpc/picker_wrapper.go
index 02f97595..bf56faa7 100644
--- a/vendor/google.golang.org/grpc/picker_wrapper.go
+++ b/vendor/google.golang.org/grpc/picker_wrapper.go
@@ -28,31 +28,31 @@ import (
"google.golang.org/grpc/internal/channelz"
istatus "google.golang.org/grpc/internal/status"
"google.golang.org/grpc/internal/transport"
+ "google.golang.org/grpc/stats"
"google.golang.org/grpc/status"
)
// pickerWrapper is a wrapper of balancer.Picker. It blocks on certain pick
// actions and unblock when there's a picker update.
type pickerWrapper struct {
- mu sync.Mutex
- done bool
- idle bool
- blockingCh chan struct{}
- picker balancer.Picker
+ mu sync.Mutex
+ done bool
+ blockingCh chan struct{}
+ picker balancer.Picker
+ statsHandlers []stats.Handler // to record blocking picker calls
}
-func newPickerWrapper() *pickerWrapper {
- return &pickerWrapper{blockingCh: make(chan struct{})}
+func newPickerWrapper(statsHandlers []stats.Handler) *pickerWrapper {
+ return &pickerWrapper{
+ blockingCh: make(chan struct{}),
+ statsHandlers: statsHandlers,
+ }
}
// updatePicker is called by UpdateBalancerState. It unblocks all blocked pick.
func (pw *pickerWrapper) updatePicker(p balancer.Picker) {
pw.mu.Lock()
- if pw.done || pw.idle {
- // There is a small window where a picker update from the LB policy can
- // race with the channel going to idle mode. If the picker is idle here,
- // it is because the channel asked it to do so, and therefore it is sage
- // to ignore the update from the LB policy.
+ if pw.done {
pw.mu.Unlock()
return
}
@@ -95,6 +95,7 @@ func (pw *pickerWrapper) pick(ctx context.Context, failfast bool, info balancer.
var ch chan struct{}
var lastPickErr error
+
for {
pw.mu.Lock()
if pw.done {
@@ -129,6 +130,20 @@ func (pw *pickerWrapper) pick(ctx context.Context, failfast bool, info balancer.
continue
}
+ // If the channel is set, it means that the pick call had to wait for a
+ // new picker at some point. Either it's the first iteration and this
+ // function received the first picker, or a picker errored with
+ // ErrNoSubConnAvailable or errored with failfast set to false, which
+ // will trigger a continue to the next iteration. In the first case this
+ // conditional will hit if this call had to block (the channel is set).
+ // In the second case, the only way it will get to this conditional is
+ // if there is a new picker.
+ if ch != nil {
+ for _, sh := range pw.statsHandlers {
+ sh.HandleRPC(ctx, &stats.PickerUpdated{})
+ }
+ }
+
ch = pw.blockingCh
p := pw.picker
pw.mu.Unlock()
@@ -190,23 +205,15 @@ func (pw *pickerWrapper) close() {
close(pw.blockingCh)
}
-func (pw *pickerWrapper) enterIdleMode() {
- pw.mu.Lock()
- defer pw.mu.Unlock()
- if pw.done {
- return
- }
- pw.idle = true
-}
-
-func (pw *pickerWrapper) exitIdleMode() {
+// reset clears the pickerWrapper and prepares it for being used again when idle
+// mode is exited.
+func (pw *pickerWrapper) reset() {
pw.mu.Lock()
defer pw.mu.Unlock()
if pw.done {
return
}
pw.blockingCh = make(chan struct{})
- pw.idle = false
}
// dropError is a wrapper error that indicates the LB policy wishes to drop the
diff --git a/vendor/google.golang.org/grpc/pickfirst.go b/vendor/google.golang.org/grpc/pickfirst.go
index abe266b0..5128f936 100644
--- a/vendor/google.golang.org/grpc/pickfirst.go
+++ b/vendor/google.golang.org/grpc/pickfirst.go
@@ -25,13 +25,18 @@ import (
"google.golang.org/grpc/balancer"
"google.golang.org/grpc/connectivity"
- "google.golang.org/grpc/internal/envconfig"
+ internalgrpclog "google.golang.org/grpc/internal/grpclog"
"google.golang.org/grpc/internal/grpcrand"
+ "google.golang.org/grpc/internal/pretty"
+ "google.golang.org/grpc/resolver"
"google.golang.org/grpc/serviceconfig"
)
-// PickFirstBalancerName is the name of the pick_first balancer.
-const PickFirstBalancerName = "pick_first"
+const (
+ // PickFirstBalancerName is the name of the pick_first balancer.
+ PickFirstBalancerName = "pick_first"
+ logPrefix = "[pick-first-lb %p] "
+)
func newPickfirstBuilder() balancer.Builder {
return &pickfirstBuilder{}
@@ -40,7 +45,9 @@ func newPickfirstBuilder() balancer.Builder {
type pickfirstBuilder struct{}
func (*pickfirstBuilder) Build(cc balancer.ClientConn, opt balancer.BuildOptions) balancer.Balancer {
- return &pickfirstBalancer{cc: cc}
+ b := &pickfirstBalancer{cc: cc}
+ b.logger = internalgrpclog.NewPrefixLogger(logger, fmt.Sprintf(logPrefix, b))
+ return b
}
func (*pickfirstBuilder) Name() string {
@@ -57,23 +64,23 @@ type pfConfig struct {
}
func (*pickfirstBuilder) ParseConfig(js json.RawMessage) (serviceconfig.LoadBalancingConfig, error) {
- cfg := &pfConfig{}
- if err := json.Unmarshal(js, cfg); err != nil {
+ var cfg pfConfig
+ if err := json.Unmarshal(js, &cfg); err != nil {
return nil, fmt.Errorf("pickfirst: unable to unmarshal LB policy config: %s, error: %v", string(js), err)
}
return cfg, nil
}
type pickfirstBalancer struct {
+ logger *internalgrpclog.PrefixLogger
state connectivity.State
cc balancer.ClientConn
subConn balancer.SubConn
- cfg *pfConfig
}
func (b *pickfirstBalancer) ResolverError(err error) {
- if logger.V(2) {
- logger.Infof("pickfirstBalancer: ResolverError called with error: %v", err)
+ if b.logger.V(2) {
+ b.logger.Infof("Received error from the name resolver: %v", err)
}
if b.subConn == nil {
b.state = connectivity.TransientFailure
@@ -96,35 +103,44 @@ func (b *pickfirstBalancer) UpdateClientConnState(state balancer.ClientConnState
// The resolver reported an empty address list. Treat it like an error by
// calling b.ResolverError.
if b.subConn != nil {
- // Remove the old subConn. All addresses were removed, so it is no longer
- // valid.
- b.cc.RemoveSubConn(b.subConn)
+ // Shut down the old subConn. All addresses were removed, so it is
+ // no longer valid.
+ b.subConn.Shutdown()
b.subConn = nil
}
b.ResolverError(errors.New("produced zero addresses"))
return balancer.ErrBadResolverState
}
- if state.BalancerConfig != nil {
- cfg, ok := state.BalancerConfig.(*pfConfig)
- if !ok {
- return fmt.Errorf("pickfirstBalancer: received nil or illegal BalancerConfig (type %T): %v", state.BalancerConfig, state.BalancerConfig)
- }
- b.cfg = cfg
+ // We don't have to guard this block with the env var because ParseConfig
+ // already does so.
+ cfg, ok := state.BalancerConfig.(pfConfig)
+ if state.BalancerConfig != nil && !ok {
+ return fmt.Errorf("pickfirst: received illegal BalancerConfig (type %T): %v", state.BalancerConfig, state.BalancerConfig)
}
-
- if envconfig.PickFirstLBConfig && b.cfg != nil && b.cfg.ShuffleAddressList {
+ if cfg.ShuffleAddressList {
+ addrs = append([]resolver.Address{}, addrs...)
grpcrand.Shuffle(len(addrs), func(i, j int) { addrs[i], addrs[j] = addrs[j], addrs[i] })
}
+
+ if b.logger.V(2) {
+ b.logger.Infof("Received new config %s, resolver state %s", pretty.ToJSON(cfg), pretty.ToJSON(state.ResolverState))
+ }
+
if b.subConn != nil {
b.cc.UpdateAddresses(b.subConn, addrs)
return nil
}
- subConn, err := b.cc.NewSubConn(addrs, balancer.NewSubConnOptions{})
+ var subConn balancer.SubConn
+ subConn, err := b.cc.NewSubConn(addrs, balancer.NewSubConnOptions{
+ StateListener: func(state balancer.SubConnState) {
+ b.updateSubConnState(subConn, state)
+ },
+ })
if err != nil {
- if logger.V(2) {
- logger.Errorf("pickfirstBalancer: failed to NewSubConn: %v", err)
+ if b.logger.V(2) {
+ b.logger.Infof("Failed to create new SubConn: %v", err)
}
b.state = connectivity.TransientFailure
b.cc.UpdateState(balancer.State{
@@ -143,13 +159,19 @@ func (b *pickfirstBalancer) UpdateClientConnState(state balancer.ClientConnState
return nil
}
+// UpdateSubConnState is unused as a StateListener is always registered when
+// creating SubConns.
func (b *pickfirstBalancer) UpdateSubConnState(subConn balancer.SubConn, state balancer.SubConnState) {
- if logger.V(2) {
- logger.Infof("pickfirstBalancer: UpdateSubConnState: %p, %v", subConn, state)
+ b.logger.Errorf("UpdateSubConnState(%v, %+v) called unexpectedly", subConn, state)
+}
+
+func (b *pickfirstBalancer) updateSubConnState(subConn balancer.SubConn, state balancer.SubConnState) {
+ if b.logger.V(2) {
+ b.logger.Infof("Received SubConn state update: %p, %+v", subConn, state)
}
if b.subConn != subConn {
- if logger.V(2) {
- logger.Infof("pickfirstBalancer: ignored state change because subConn is not recognized")
+ if b.logger.V(2) {
+ b.logger.Infof("Ignored state change because subConn is not recognized")
}
return
}
diff --git a/vendor/google.golang.org/grpc/preloader.go b/vendor/google.golang.org/grpc/preloader.go
index cd455478..73bd6336 100644
--- a/vendor/google.golang.org/grpc/preloader.go
+++ b/vendor/google.golang.org/grpc/preloader.go
@@ -37,7 +37,7 @@ type PreparedMsg struct {
}
// Encode marshalls and compresses the message using the codec and compressor for the stream.
-func (p *PreparedMsg) Encode(s Stream, msg interface{}) error {
+func (p *PreparedMsg) Encode(s Stream, msg any) error {
ctx := s.Context()
rpcInfo, ok := rpcInfoFromContext(ctx)
if !ok {
diff --git a/vendor/google.golang.org/grpc/resolver/dns/dns_resolver.go b/vendor/google.golang.org/grpc/resolver/dns/dns_resolver.go
new file mode 100644
index 00000000..14aa6f20
--- /dev/null
+++ b/vendor/google.golang.org/grpc/resolver/dns/dns_resolver.go
@@ -0,0 +1,36 @@
+/*
+ *
+ * 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 dns implements a dns resolver to be installed as the default resolver
+// in grpc.
+//
+// Deprecated: this package is imported by grpc and should not need to be
+// imported directly by users.
+package dns
+
+import (
+ "google.golang.org/grpc/internal/resolver/dns"
+ "google.golang.org/grpc/resolver"
+)
+
+// NewBuilder creates a dnsBuilder which is used to factory DNS resolvers.
+//
+// Deprecated: import grpc and use resolver.Get("dns") instead.
+func NewBuilder() resolver.Builder {
+ return dns.NewBuilder()
+}
diff --git a/vendor/google.golang.org/grpc/resolver/map.go b/vendor/google.golang.org/grpc/resolver/map.go
index efcb7f3e..ada5b9bb 100644
--- a/vendor/google.golang.org/grpc/resolver/map.go
+++ b/vendor/google.golang.org/grpc/resolver/map.go
@@ -20,7 +20,7 @@ package resolver
type addressMapEntry struct {
addr Address
- value interface{}
+ value any
}
// AddressMap is a map of addresses to arbitrary values taking into account
@@ -69,7 +69,7 @@ func (l addressMapEntryList) find(addr Address) int {
}
// Get returns the value for the address in the map, if present.
-func (a *AddressMap) Get(addr Address) (value interface{}, ok bool) {
+func (a *AddressMap) Get(addr Address) (value any, ok bool) {
addrKey := toMapKey(&addr)
entryList := a.m[addrKey]
if entry := entryList.find(addr); entry != -1 {
@@ -79,7 +79,7 @@ func (a *AddressMap) Get(addr Address) (value interface{}, ok bool) {
}
// Set updates or adds the value to the address in the map.
-func (a *AddressMap) Set(addr Address, value interface{}) {
+func (a *AddressMap) Set(addr Address, value any) {
addrKey := toMapKey(&addr)
entryList := a.m[addrKey]
if entry := entryList.find(addr); entry != -1 {
@@ -127,8 +127,8 @@ func (a *AddressMap) Keys() []Address {
}
// Values returns a slice of all current map values.
-func (a *AddressMap) Values() []interface{} {
- ret := make([]interface{}, 0, a.Len())
+func (a *AddressMap) Values() []any {
+ ret := make([]any, 0, a.Len())
for _, entryList := range a.m {
for _, entry := range entryList {
ret = append(ret, entry.value)
@@ -136,3 +136,116 @@ func (a *AddressMap) Values() []interface{} {
}
return ret
}
+
+type endpointNode struct {
+ addrs map[string]struct{}
+}
+
+// Equal returns whether the unordered set of addrs are the same between the
+// endpoint nodes.
+func (en *endpointNode) Equal(en2 *endpointNode) bool {
+ if len(en.addrs) != len(en2.addrs) {
+ return false
+ }
+ for addr := range en.addrs {
+ if _, ok := en2.addrs[addr]; !ok {
+ return false
+ }
+ }
+ return true
+}
+
+func toEndpointNode(endpoint Endpoint) endpointNode {
+ en := make(map[string]struct{})
+ for _, addr := range endpoint.Addresses {
+ en[addr.Addr] = struct{}{}
+ }
+ return endpointNode{
+ addrs: en,
+ }
+}
+
+// EndpointMap is a map of endpoints to arbitrary values keyed on only the
+// unordered set of address strings within an endpoint. This map is not thread
+// safe, thus it is unsafe to access concurrently. Must be created via
+// NewEndpointMap; do not construct directly.
+type EndpointMap struct {
+ endpoints map[*endpointNode]any
+}
+
+// NewEndpointMap creates a new EndpointMap.
+func NewEndpointMap() *EndpointMap {
+ return &EndpointMap{
+ endpoints: make(map[*endpointNode]any),
+ }
+}
+
+// Get returns the value for the address in the map, if present.
+func (em *EndpointMap) Get(e Endpoint) (value any, ok bool) {
+ en := toEndpointNode(e)
+ if endpoint := em.find(en); endpoint != nil {
+ return em.endpoints[endpoint], true
+ }
+ return nil, false
+}
+
+// Set updates or adds the value to the address in the map.
+func (em *EndpointMap) Set(e Endpoint, value any) {
+ en := toEndpointNode(e)
+ if endpoint := em.find(en); endpoint != nil {
+ em.endpoints[endpoint] = value
+ return
+ }
+ em.endpoints[&en] = value
+}
+
+// Len returns the number of entries in the map.
+func (em *EndpointMap) Len() int {
+ return len(em.endpoints)
+}
+
+// Keys returns a slice of all current map keys, as endpoints specifying the
+// addresses present in the endpoint keys, 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) Keys() []Endpoint {
+ ret := make([]Endpoint, 0, len(em.endpoints))
+ for en := range em.endpoints {
+ var endpoint Endpoint
+ for addr := range en.addrs {
+ endpoint.Addresses = append(endpoint.Addresses, Address{Addr: addr})
+ }
+ ret = append(ret, endpoint)
+ }
+ return ret
+}
+
+// Values returns a slice of all current map values.
+func (em *EndpointMap) Values() []any {
+ ret := make([]any, 0, len(em.endpoints))
+ for _, val := range em.endpoints {
+ ret = append(ret, val)
+ }
+ return ret
+}
+
+// find returns a pointer to the endpoint node in em if the endpoint node is
+// already present. If not found, nil is returned. The comparisons are done on
+// the unordered set of addresses within an endpoint.
+func (em EndpointMap) find(e endpointNode) *endpointNode {
+ for endpoint := range em.endpoints {
+ if e.Equal(endpoint) {
+ return endpoint
+ }
+ }
+ return nil
+}
+
+// Delete removes the specified endpoint from the map.
+func (em *EndpointMap) Delete(e Endpoint) {
+ en := toEndpointNode(e)
+ if entry := em.find(en); entry != nil {
+ delete(em.endpoints, entry)
+ }
+}
diff --git a/vendor/google.golang.org/grpc/resolver/resolver.go b/vendor/google.golang.org/grpc/resolver/resolver.go
index 353c10b6..adf89dd9 100644
--- a/vendor/google.golang.org/grpc/resolver/resolver.go
+++ b/vendor/google.golang.org/grpc/resolver/resolver.go
@@ -77,25 +77,6 @@ func GetDefaultScheme() string {
return defaultScheme
}
-// AddressType indicates the address type returned by name resolution.
-//
-// Deprecated: use Attributes in Address instead.
-type AddressType uint8
-
-const (
- // Backend indicates the address is for a backend server.
- //
- // Deprecated: use Attributes in Address instead.
- Backend AddressType = iota
- // GRPCLB indicates the address is for a grpclb load balancer.
- //
- // Deprecated: to select the GRPCLB load balancing policy, use a service
- // config with a corresponding loadBalancingConfig. To supply balancer
- // addresses to the GRPCLB load balancing policy, set State.Attributes
- // using balancer/grpclb/state.Set.
- GRPCLB
-)
-
// Address represents a server the client connects to.
//
// # Experimental
@@ -111,9 +92,6 @@ type Address struct {
// the address, instead of the hostname from the Dial target string. In most cases,
// this should not be set.
//
- // If Type is GRPCLB, ServerName should be the name of the remote load
- // balancer, not the name of the backend.
- //
// WARNING: ServerName must only be populated with trusted values. It
// is insecure to populate it with data from untrusted inputs since untrusted
// values could be used to bypass the authority checks performed by TLS.
@@ -126,27 +104,29 @@ type Address struct {
// BalancerAttributes contains arbitrary data about this address intended
// for consumption by the LB policy. These attributes do not affect SubConn
// creation, connection establishment, handshaking, etc.
- BalancerAttributes *attributes.Attributes
-
- // Type is the type of this address.
//
- // Deprecated: use Attributes instead.
- Type AddressType
+ // Deprecated: when an Address is inside an Endpoint, this field should not
+ // be used, and it will eventually be removed entirely.
+ BalancerAttributes *attributes.Attributes
// Metadata is the information associated with Addr, which may be used
// to make load balancing decision.
//
// Deprecated: use Attributes instead.
- Metadata interface{}
+ Metadata any
}
// Equal returns whether a and o are identical. Metadata is compared directly,
// not with any recursive introspection.
+//
+// This method compares all fields of the address. When used to tell apart
+// addresses during subchannel creation or connection establishment, it might be
+// more appropriate for the caller to implement custom equality logic.
func (a Address) Equal(o Address) bool {
return a.Addr == o.Addr && a.ServerName == o.ServerName &&
a.Attributes.Equal(o.Attributes) &&
a.BalancerAttributes.Equal(o.BalancerAttributes) &&
- a.Type == o.Type && a.Metadata == o.Metadata
+ a.Metadata == o.Metadata
}
// String returns JSON formatted string representation of the address.
@@ -190,11 +170,37 @@ type BuildOptions struct {
Dialer func(context.Context, string) (net.Conn, error)
}
+// An Endpoint is one network endpoint, or server, which may have multiple
+// addresses with which it can be accessed.
+type Endpoint struct {
+ // Addresses contains a list of addresses used to access this endpoint.
+ Addresses []Address
+
+ // Attributes contains arbitrary data about this endpoint intended for
+ // consumption by the LB policy.
+ Attributes *attributes.Attributes
+}
+
// State contains the current Resolver state relevant to the ClientConn.
type State struct {
// Addresses is the latest set of resolved addresses for the target.
+ //
+ // If a resolver sets Addresses but does not set Endpoints, one Endpoint
+ // will be created for each Address before the State is passed to the LB
+ // policy. The BalancerAttributes of each entry in Addresses will be set
+ // in Endpoints.Attributes, and be cleared in the Endpoint's Address's
+ // BalancerAttributes.
+ //
+ // Soon, Addresses will be deprecated and replaced fully by Endpoints.
Addresses []Address
+ // Endpoints is the latest set of resolved endpoints for the target.
+ //
+ // If a resolver produces a State containing Endpoints but not Addresses,
+ // it must take care to ensure the LB policies it selects will support
+ // Endpoints.
+ Endpoints []Endpoint
+
// ServiceConfig contains the result from parsing the latest service
// config. If it is nil, it indicates no service config is present or the
// resolver does not provide service configs.
@@ -234,11 +240,6 @@ type ClientConn interface {
//
// Deprecated: Use UpdateState instead.
NewAddress(addresses []Address)
- // NewServiceConfig is called by resolver to notify ClientConn a new
- // service config. The service config should be provided as a json string.
- //
- // Deprecated: Use UpdateState instead.
- NewServiceConfig(serviceConfig string)
// ParseServiceConfig parses the provided service config and returns an
// object that provides the parsed config.
ParseServiceConfig(serviceConfigJSON string) *serviceconfig.ParseResult
@@ -254,20 +255,7 @@ type ClientConn interface {
// target does not contain a scheme or if the parsed scheme is not registered
// (i.e. no corresponding resolver available to resolve the endpoint), we will
// apply the default scheme, and will attempt to reparse it.
-//
-// Examples:
-//
-// - "dns://some_authority/foo.bar"
-// Target{Scheme: "dns", Authority: "some_authority", Endpoint: "foo.bar"}
-// - "foo.bar"
-// Target{Scheme: resolver.GetDefaultScheme(), Endpoint: "foo.bar"}
-// - "unknown_scheme://authority/endpoint"
-// Target{Scheme: resolver.GetDefaultScheme(), Endpoint: "unknown_scheme://authority/endpoint"}
type Target struct {
- // Deprecated: use URL.Scheme instead.
- Scheme string
- // Deprecated: use URL.Host instead.
- Authority string
// URL contains the parsed dial target with an optional default scheme added
// to it if the original dial target contained no scheme or contained an
// unregistered scheme. Any query params specified in the original dial
@@ -293,6 +281,11 @@ func (t Target) Endpoint() string {
return strings.TrimPrefix(endpoint, "/")
}
+// String returns a string representation of Target.
+func (t Target) String() string {
+ return t.URL.String()
+}
+
// Builder creates a resolver that will be used to watch name resolution updates.
type Builder interface {
// Build creates a new resolver for the given target.
@@ -322,9 +315,12 @@ type Resolver interface {
Close()
}
-// UnregisterForTesting removes the resolver builder with the given scheme from the
-// resolver map.
-// This function is for testing only.
-func UnregisterForTesting(scheme string) {
- delete(m, scheme)
+// AuthorityOverrider is implemented by Builders that wish to override the
+// default authority for the ClientConn.
+// By default, the authority used is target.Endpoint().
+type AuthorityOverrider interface {
+ // OverrideAuthority returns the authority to use for a ClientConn with the
+ // given target. The implementation must generate it without blocking,
+ // typically in line, and must keep it unchanged.
+ OverrideAuthority(Target) string
}
diff --git a/vendor/google.golang.org/grpc/resolver_conn_wrapper.go b/vendor/google.golang.org/grpc/resolver_conn_wrapper.go
deleted file mode 100644
index b408b368..00000000
--- a/vendor/google.golang.org/grpc/resolver_conn_wrapper.go
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- *
- * Copyright 2017 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 grpc
-
-import (
- "context"
- "strings"
- "sync"
-
- "google.golang.org/grpc/balancer"
- "google.golang.org/grpc/internal/channelz"
- "google.golang.org/grpc/internal/grpcsync"
- "google.golang.org/grpc/internal/pretty"
- "google.golang.org/grpc/resolver"
- "google.golang.org/grpc/serviceconfig"
-)
-
-// resolverStateUpdater wraps the single method used by ccResolverWrapper to
-// report a state update from the actual resolver implementation.
-type resolverStateUpdater interface {
- updateResolverState(s resolver.State, err error) error
-}
-
-// ccResolverWrapper is a wrapper on top of cc for resolvers.
-// It implements resolver.ClientConn interface.
-type ccResolverWrapper struct {
- // The following fields are initialized when the wrapper is created and are
- // read-only afterwards, and therefore can be accessed without a mutex.
- cc resolverStateUpdater
- channelzID *channelz.Identifier
- ignoreServiceConfig bool
- opts ccResolverWrapperOpts
- serializer *grpcsync.CallbackSerializer // To serialize all incoming calls.
- serializerCancel context.CancelFunc // To close the serializer, accessed only from close().
-
- // All incoming (resolver --> gRPC) calls are guaranteed to execute in a
- // mutually exclusive manner as they are scheduled on the serializer.
- // Fields accessed *only* in these serializer callbacks, can therefore be
- // accessed without a mutex.
- curState resolver.State
-
- // mu guards access to the below fields.
- mu sync.Mutex
- closed bool
- resolver resolver.Resolver // Accessed only from outgoing calls.
-}
-
-// ccResolverWrapperOpts wraps the arguments to be passed when creating a new
-// ccResolverWrapper.
-type ccResolverWrapperOpts struct {
- target resolver.Target // User specified dial target to resolve.
- builder resolver.Builder // Resolver builder to use.
- bOpts resolver.BuildOptions // Resolver build options to use.
- channelzID *channelz.Identifier // Channelz identifier for the channel.
-}
-
-// newCCResolverWrapper uses the resolver.Builder to build a Resolver and
-// returns a ccResolverWrapper object which wraps the newly built resolver.
-func newCCResolverWrapper(cc resolverStateUpdater, opts ccResolverWrapperOpts) (*ccResolverWrapper, error) {
- ctx, cancel := context.WithCancel(context.Background())
- ccr := &ccResolverWrapper{
- cc: cc,
- channelzID: opts.channelzID,
- ignoreServiceConfig: opts.bOpts.DisableServiceConfig,
- opts: opts,
- serializer: grpcsync.NewCallbackSerializer(ctx),
- serializerCancel: cancel,
- }
-
- // Cannot hold the lock at build time because the resolver can send an
- // update or error inline and these incoming calls grab the lock to schedule
- // a callback in the serializer.
- r, err := opts.builder.Build(opts.target, ccr, opts.bOpts)
- if err != nil {
- cancel()
- return nil, err
- }
-
- // Any error reported by the resolver at build time that leads to a
- // re-resolution request from the balancer is dropped by grpc until we
- // return from this function. So, we don't have to handle pending resolveNow
- // requests here.
- ccr.mu.Lock()
- ccr.resolver = r
- ccr.mu.Unlock()
-
- return ccr, nil
-}
-
-func (ccr *ccResolverWrapper) resolveNow(o resolver.ResolveNowOptions) {
- ccr.mu.Lock()
- defer ccr.mu.Unlock()
-
- // ccr.resolver field is set only after the call to Build() returns. But in
- // the process of building, the resolver may send an error update which when
- // propagated to the balancer may result in a re-resolution request.
- if ccr.closed || ccr.resolver == nil {
- return
- }
- ccr.resolver.ResolveNow(o)
-}
-
-func (ccr *ccResolverWrapper) close() {
- ccr.mu.Lock()
- if ccr.closed {
- ccr.mu.Unlock()
- return
- }
-
- channelz.Info(logger, ccr.channelzID, "Closing the name resolver")
-
- // Close the serializer to ensure that no more calls from the resolver are
- // handled, before actually closing the resolver.
- ccr.serializerCancel()
- ccr.closed = true
- r := ccr.resolver
- ccr.mu.Unlock()
-
- // Give enqueued callbacks a chance to finish.
- <-ccr.serializer.Done
-
- // Spawn a goroutine to close the resolver (since it may block trying to
- // cleanup all allocated resources) and return early.
- go r.Close()
-}
-
-// serializerScheduleLocked is a convenience method to schedule a function to be
-// run on the serializer while holding ccr.mu.
-func (ccr *ccResolverWrapper) serializerScheduleLocked(f func(context.Context)) {
- ccr.mu.Lock()
- ccr.serializer.Schedule(f)
- ccr.mu.Unlock()
-}
-
-// UpdateState is called by resolver implementations to report new state to gRPC
-// which includes addresses and service config.
-func (ccr *ccResolverWrapper) UpdateState(s resolver.State) error {
- errCh := make(chan error, 1)
- ok := ccr.serializer.Schedule(func(context.Context) {
- ccr.addChannelzTraceEvent(s)
- ccr.curState = s
- if err := ccr.cc.updateResolverState(ccr.curState, nil); err == balancer.ErrBadResolverState {
- errCh <- balancer.ErrBadResolverState
- return
- }
- errCh <- nil
- })
- if !ok {
- // The only time when Schedule() fail to add the callback to the
- // serializer is when the serializer is closed, and this happens only
- // when the resolver wrapper is closed.
- return nil
- }
- return <-errCh
-}
-
-// ReportError is called by resolver implementations to report errors
-// encountered during name resolution to gRPC.
-func (ccr *ccResolverWrapper) ReportError(err error) {
- ccr.serializerScheduleLocked(func(_ context.Context) {
- channelz.Warningf(logger, ccr.channelzID, "ccResolverWrapper: reporting error to cc: %v", err)
- ccr.cc.updateResolverState(resolver.State{}, err)
- })
-}
-
-// NewAddress is called by the resolver implementation to send addresses to
-// gRPC.
-func (ccr *ccResolverWrapper) NewAddress(addrs []resolver.Address) {
- ccr.serializerScheduleLocked(func(_ context.Context) {
- ccr.addChannelzTraceEvent(resolver.State{Addresses: addrs, ServiceConfig: ccr.curState.ServiceConfig})
- ccr.curState.Addresses = addrs
- ccr.cc.updateResolverState(ccr.curState, nil)
- })
-}
-
-// NewServiceConfig is called by the resolver implementation to send service
-// configs to gRPC.
-func (ccr *ccResolverWrapper) NewServiceConfig(sc string) {
- ccr.serializerScheduleLocked(func(_ context.Context) {
- channelz.Infof(logger, ccr.channelzID, "ccResolverWrapper: got new service config: %s", sc)
- if ccr.ignoreServiceConfig {
- channelz.Info(logger, ccr.channelzID, "Service config lookups disabled; ignoring config")
- return
- }
- scpr := parseServiceConfig(sc)
- if scpr.Err != nil {
- channelz.Warningf(logger, ccr.channelzID, "ccResolverWrapper: error parsing service config: %v", scpr.Err)
- return
- }
- ccr.addChannelzTraceEvent(resolver.State{Addresses: ccr.curState.Addresses, ServiceConfig: scpr})
- ccr.curState.ServiceConfig = scpr
- ccr.cc.updateResolverState(ccr.curState, nil)
- })
-}
-
-// ParseServiceConfig is called by resolver implementations to parse a JSON
-// representation of the service config.
-func (ccr *ccResolverWrapper) ParseServiceConfig(scJSON string) *serviceconfig.ParseResult {
- return parseServiceConfig(scJSON)
-}
-
-// addChannelzTraceEvent adds a channelz trace event containing the new
-// state received from resolver implementations.
-func (ccr *ccResolverWrapper) addChannelzTraceEvent(s resolver.State) {
- var updates []string
- var oldSC, newSC *ServiceConfig
- var oldOK, newOK bool
- if ccr.curState.ServiceConfig != nil {
- oldSC, oldOK = ccr.curState.ServiceConfig.Config.(*ServiceConfig)
- }
- if s.ServiceConfig != nil {
- newSC, newOK = s.ServiceConfig.Config.(*ServiceConfig)
- }
- if oldOK != newOK || (oldOK && newOK && oldSC.rawJSONString != newSC.rawJSONString) {
- updates = append(updates, "service config updated")
- }
- if len(ccr.curState.Addresses) > 0 && len(s.Addresses) == 0 {
- updates = append(updates, "resolver returned an empty address list")
- } else if len(ccr.curState.Addresses) == 0 && len(s.Addresses) > 0 {
- updates = append(updates, "resolver returned new addresses")
- }
- channelz.Infof(logger, ccr.channelzID, "Resolver state updated: %s (%v)", pretty.ToJSON(s), strings.Join(updates, "; "))
-}
diff --git a/vendor/google.golang.org/grpc/resolver_wrapper.go b/vendor/google.golang.org/grpc/resolver_wrapper.go
new file mode 100644
index 00000000..c79bab12
--- /dev/null
+++ b/vendor/google.golang.org/grpc/resolver_wrapper.go
@@ -0,0 +1,197 @@
+/*
+ *
+ * Copyright 2017 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 grpc
+
+import (
+ "context"
+ "strings"
+ "sync"
+
+ "google.golang.org/grpc/internal/channelz"
+ "google.golang.org/grpc/internal/grpcsync"
+ "google.golang.org/grpc/internal/pretty"
+ "google.golang.org/grpc/resolver"
+ "google.golang.org/grpc/serviceconfig"
+)
+
+// ccResolverWrapper is a wrapper on top of cc for resolvers.
+// It implements resolver.ClientConn interface.
+type ccResolverWrapper struct {
+ // The following fields are initialized when the wrapper is created and are
+ // read-only afterwards, and therefore can be accessed without a mutex.
+ cc *ClientConn
+ ignoreServiceConfig bool
+ serializer *grpcsync.CallbackSerializer
+ serializerCancel context.CancelFunc
+
+ resolver resolver.Resolver // only accessed within the serializer
+
+ // The following fields are protected by mu. Caller must take cc.mu before
+ // taking mu.
+ mu sync.Mutex
+ curState resolver.State
+ closed bool
+}
+
+// newCCResolverWrapper initializes the ccResolverWrapper. It can only be used
+// after calling start, which builds the resolver.
+func newCCResolverWrapper(cc *ClientConn) *ccResolverWrapper {
+ ctx, cancel := context.WithCancel(cc.ctx)
+ return &ccResolverWrapper{
+ cc: cc,
+ ignoreServiceConfig: cc.dopts.disableServiceConfig,
+ serializer: grpcsync.NewCallbackSerializer(ctx),
+ serializerCancel: cancel,
+ }
+}
+
+// start builds the name resolver using the resolver.Builder in cc and returns
+// any error encountered. It must always be the first operation performed on
+// any newly created ccResolverWrapper, except that close may be called instead.
+func (ccr *ccResolverWrapper) start() error {
+ errCh := make(chan error)
+ ccr.serializer.Schedule(func(ctx context.Context) {
+ if ctx.Err() != nil {
+ return
+ }
+ opts := resolver.BuildOptions{
+ DisableServiceConfig: ccr.cc.dopts.disableServiceConfig,
+ DialCreds: ccr.cc.dopts.copts.TransportCredentials,
+ CredsBundle: ccr.cc.dopts.copts.CredsBundle,
+ Dialer: ccr.cc.dopts.copts.Dialer,
+ }
+ var err error
+ ccr.resolver, err = ccr.cc.resolverBuilder.Build(ccr.cc.parsedTarget, ccr, opts)
+ errCh <- err
+ })
+ return <-errCh
+}
+
+func (ccr *ccResolverWrapper) resolveNow(o resolver.ResolveNowOptions) {
+ ccr.serializer.Schedule(func(ctx context.Context) {
+ if ctx.Err() != nil || ccr.resolver == nil {
+ return
+ }
+ ccr.resolver.ResolveNow(o)
+ })
+}
+
+// close initiates async shutdown of the wrapper. To determine the wrapper has
+// finished shutting down, the channel should block on ccr.serializer.Done()
+// without cc.mu held.
+func (ccr *ccResolverWrapper) close() {
+ channelz.Info(logger, ccr.cc.channelzID, "Closing the name resolver")
+ ccr.mu.Lock()
+ ccr.closed = true
+ ccr.mu.Unlock()
+
+ ccr.serializer.Schedule(func(context.Context) {
+ if ccr.resolver == nil {
+ return
+ }
+ ccr.resolver.Close()
+ ccr.resolver = nil
+ })
+ ccr.serializerCancel()
+}
+
+// UpdateState is called by resolver implementations to report new state to gRPC
+// which includes addresses and service config.
+func (ccr *ccResolverWrapper) UpdateState(s resolver.State) error {
+ ccr.cc.mu.Lock()
+ ccr.mu.Lock()
+ if ccr.closed {
+ ccr.mu.Unlock()
+ ccr.cc.mu.Unlock()
+ return nil
+ }
+ if s.Endpoints == nil {
+ s.Endpoints = make([]resolver.Endpoint, 0, len(s.Addresses))
+ for _, a := range s.Addresses {
+ ep := resolver.Endpoint{Addresses: []resolver.Address{a}, Attributes: a.BalancerAttributes}
+ ep.Addresses[0].BalancerAttributes = nil
+ s.Endpoints = append(s.Endpoints, ep)
+ }
+ }
+ ccr.addChannelzTraceEvent(s)
+ ccr.curState = s
+ ccr.mu.Unlock()
+ return ccr.cc.updateResolverStateAndUnlock(s, nil)
+}
+
+// ReportError is called by resolver implementations to report errors
+// encountered during name resolution to gRPC.
+func (ccr *ccResolverWrapper) ReportError(err error) {
+ ccr.cc.mu.Lock()
+ ccr.mu.Lock()
+ if ccr.closed {
+ ccr.mu.Unlock()
+ ccr.cc.mu.Unlock()
+ return
+ }
+ ccr.mu.Unlock()
+ channelz.Warningf(logger, ccr.cc.channelzID, "ccResolverWrapper: reporting error to cc: %v", err)
+ ccr.cc.updateResolverStateAndUnlock(resolver.State{}, err)
+}
+
+// NewAddress is called by the resolver implementation to send addresses to
+// gRPC.
+func (ccr *ccResolverWrapper) NewAddress(addrs []resolver.Address) {
+ ccr.cc.mu.Lock()
+ ccr.mu.Lock()
+ if ccr.closed {
+ ccr.mu.Unlock()
+ ccr.cc.mu.Unlock()
+ return
+ }
+ s := resolver.State{Addresses: addrs, ServiceConfig: ccr.curState.ServiceConfig}
+ ccr.addChannelzTraceEvent(s)
+ ccr.curState = s
+ ccr.mu.Unlock()
+ ccr.cc.updateResolverStateAndUnlock(s, nil)
+}
+
+// ParseServiceConfig is called by resolver implementations to parse a JSON
+// representation of the service config.
+func (ccr *ccResolverWrapper) ParseServiceConfig(scJSON string) *serviceconfig.ParseResult {
+ return parseServiceConfig(scJSON)
+}
+
+// addChannelzTraceEvent adds a channelz trace event containing the new
+// state received from resolver implementations.
+func (ccr *ccResolverWrapper) addChannelzTraceEvent(s resolver.State) {
+ var updates []string
+ var oldSC, newSC *ServiceConfig
+ var oldOK, newOK bool
+ if ccr.curState.ServiceConfig != nil {
+ oldSC, oldOK = ccr.curState.ServiceConfig.Config.(*ServiceConfig)
+ }
+ if s.ServiceConfig != nil {
+ newSC, newOK = s.ServiceConfig.Config.(*ServiceConfig)
+ }
+ if oldOK != newOK || (oldOK && newOK && oldSC.rawJSONString != newSC.rawJSONString) {
+ updates = append(updates, "service config updated")
+ }
+ if len(ccr.curState.Addresses) > 0 && len(s.Addresses) == 0 {
+ updates = append(updates, "resolver returned an empty address list")
+ } else if len(ccr.curState.Addresses) == 0 && len(s.Addresses) > 0 {
+ updates = append(updates, "resolver returned new addresses")
+ }
+ channelz.Infof(logger, ccr.cc.channelzID, "Resolver state updated: %s (%v)", pretty.ToJSON(s), strings.Join(updates, "; "))
+}
diff --git a/vendor/google.golang.org/grpc/rpc_util.go b/vendor/google.golang.org/grpc/rpc_util.go
index 2030736a..a4b6bc68 100644
--- a/vendor/google.golang.org/grpc/rpc_util.go
+++ b/vendor/google.golang.org/grpc/rpc_util.go
@@ -75,7 +75,7 @@ func NewGZIPCompressorWithLevel(level int) (Compressor, error) {
}
return &gzipCompressor{
pool: sync.Pool{
- New: func() interface{} {
+ New: func() any {
w, err := gzip.NewWriterLevel(io.Discard, level)
if err != nil {
panic(err)
@@ -577,6 +577,9 @@ type parser struct {
// The header of a gRPC message. Find more detail at
// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md
header [5]byte
+
+ // recvBufferPool is the pool of shared receive buffers.
+ recvBufferPool SharedBufferPool
}
// recvMsg reads a complete gRPC message from the stream.
@@ -610,9 +613,7 @@ func (p *parser) recvMsg(maxReceiveMessageSize int) (pf payloadFormat, msg []byt
if int(length) > maxReceiveMessageSize {
return 0, nil, status.Errorf(codes.ResourceExhausted, "grpc: received message larger than max (%d vs. %d)", length, maxReceiveMessageSize)
}
- // TODO(bradfitz,zhaoq): garbage. reuse buffer after proto decoding instead
- // of making it for each message:
- msg = make([]byte, int(length))
+ msg = p.recvBufferPool.Get(int(length))
if _, err := p.r.Read(msg); err != nil {
if err == io.EOF {
err = io.ErrUnexpectedEOF
@@ -625,7 +626,7 @@ func (p *parser) recvMsg(maxReceiveMessageSize int) (pf payloadFormat, msg []byt
// encode serializes msg and returns a buffer containing the message, or an
// error if it is too large to be transmitted by grpc. If msg is nil, it
// generates an empty message.
-func encode(c baseCodec, msg interface{}) ([]byte, error) {
+func encode(c baseCodec, msg any) ([]byte, error) {
if msg == nil { // NOTE: typed nils will not be caught by this check
return nil, nil
}
@@ -639,14 +640,18 @@ func encode(c baseCodec, msg interface{}) ([]byte, error) {
return b, nil
}
-// compress returns the input bytes compressed by compressor or cp. If both
-// compressors are nil, returns nil.
+// compress returns the input bytes compressed by compressor or cp.
+// If both compressors are nil, or if the message has zero length, returns nil,
+// indicating no compression was done.
//
// TODO(dfawley): eliminate cp parameter by wrapping Compressor in an encoding.Compressor.
func compress(in []byte, cp Compressor, compressor encoding.Compressor) ([]byte, error) {
if compressor == nil && cp == nil {
return nil, nil
}
+ if len(in) == 0 {
+ return nil, nil
+ }
wrapErr := func(err error) error {
return status.Errorf(codes.Internal, "grpc: error while compressing: %v", err.Error())
}
@@ -692,7 +697,7 @@ func msgHeader(data, compData []byte) (hdr []byte, payload []byte) {
return hdr, data
}
-func outPayload(client bool, msg interface{}, data, payload []byte, t time.Time) *stats.OutPayload {
+func outPayload(client bool, msg any, data, payload []byte, t time.Time) *stats.OutPayload {
return &stats.OutPayload{
Client: client,
Payload: msg,
@@ -726,12 +731,12 @@ type payloadInfo struct {
}
func recvAndDecompress(p *parser, s *transport.Stream, dc Decompressor, maxReceiveMessageSize int, payInfo *payloadInfo, compressor encoding.Compressor) ([]byte, error) {
- pf, d, err := p.recvMsg(maxReceiveMessageSize)
+ pf, buf, err := p.recvMsg(maxReceiveMessageSize)
if err != nil {
return nil, err
}
if payInfo != nil {
- payInfo.compressedLength = len(d)
+ payInfo.compressedLength = len(buf)
}
if st := checkRecvPayload(pf, s.RecvCompress(), compressor != nil || dc != nil); st != nil {
@@ -743,10 +748,10 @@ func recvAndDecompress(p *parser, s *transport.Stream, dc Decompressor, maxRecei
// To match legacy behavior, if the decompressor is set by WithDecompressor or RPCDecompressor,
// use this decompressor as the default.
if dc != nil {
- d, err = dc.Do(bytes.NewReader(d))
- size = len(d)
+ buf, err = dc.Do(bytes.NewReader(buf))
+ size = len(buf)
} else {
- d, size, err = decompress(compressor, d, maxReceiveMessageSize)
+ buf, size, err = decompress(compressor, buf, maxReceiveMessageSize)
}
if err != nil {
return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the received message: %v", err)
@@ -757,7 +762,7 @@ func recvAndDecompress(p *parser, s *transport.Stream, dc Decompressor, maxRecei
return nil, status.Errorf(codes.ResourceExhausted, "grpc: received message after decompression larger than max (%d vs. %d)", size, maxReceiveMessageSize)
}
}
- return d, nil
+ return buf, nil
}
// Using compressor, decompress d, returning data and size.
@@ -791,16 +796,18 @@ func decompress(compressor encoding.Compressor, d []byte, maxReceiveMessageSize
// For the two compressor parameters, both should not be set, but if they are,
// dc takes precedence over compressor.
// TODO(dfawley): wrap the old compressor/decompressor using the new API?
-func recv(p *parser, c baseCodec, s *transport.Stream, dc Decompressor, m interface{}, maxReceiveMessageSize int, payInfo *payloadInfo, compressor encoding.Compressor) error {
- d, err := recvAndDecompress(p, s, dc, maxReceiveMessageSize, payInfo, compressor)
+func recv(p *parser, c baseCodec, s *transport.Stream, dc Decompressor, m any, maxReceiveMessageSize int, payInfo *payloadInfo, compressor encoding.Compressor) error {
+ buf, err := recvAndDecompress(p, s, dc, maxReceiveMessageSize, payInfo, compressor)
if err != nil {
return err
}
- if err := c.Unmarshal(d, m); err != nil {
+ if err := c.Unmarshal(buf, m); err != nil {
return status.Errorf(codes.Internal, "grpc: failed to unmarshal the received message: %v", err)
}
if payInfo != nil {
- payInfo.uncompressedBytes = d
+ payInfo.uncompressedBytes = buf
+ } else {
+ p.recvBufferPool.Put(&buf)
}
return nil
}
@@ -860,19 +867,22 @@ func ErrorDesc(err error) string {
// Errorf returns nil if c is OK.
//
// Deprecated: use status.Errorf instead.
-func Errorf(c codes.Code, format string, a ...interface{}) error {
+func Errorf(c codes.Code, format string, a ...any) error {
return status.Errorf(c, format, a...)
}
+var errContextCanceled = status.Error(codes.Canceled, context.Canceled.Error())
+var errContextDeadline = status.Error(codes.DeadlineExceeded, context.DeadlineExceeded.Error())
+
// toRPCErr converts an error into an error from the status package.
func toRPCErr(err error) error {
switch err {
case nil, io.EOF:
return err
case context.DeadlineExceeded:
- return status.Error(codes.DeadlineExceeded, err.Error())
+ return errContextDeadline
case context.Canceled:
- return status.Error(codes.Canceled, err.Error())
+ return errContextCanceled
case io.ErrUnexpectedEOF:
return status.Error(codes.Internal, err.Error())
}
diff --git a/vendor/google.golang.org/grpc/server.go b/vendor/google.golang.org/grpc/server.go
index 8869cc90..e89c5ac6 100644
--- a/vendor/google.golang.org/grpc/server.go
+++ b/vendor/google.golang.org/grpc/server.go
@@ -70,9 +70,10 @@ func init() {
internal.GetServerCredentials = func(srv *Server) credentials.TransportCredentials {
return srv.opts.creds
}
- internal.DrainServerTransports = func(srv *Server, addr string) {
- srv.drainServerTransports(addr)
+ internal.IsRegisteredMethod = func(srv *Server, method string) bool {
+ return srv.isRegisteredMethod(method)
}
+ internal.ServerFromContext = serverFromContext
internal.AddGlobalServerOptions = func(opt ...ServerOption) {
globalServerOptions = append(globalServerOptions, opt...)
}
@@ -81,12 +82,13 @@ func init() {
}
internal.BinaryLogger = binaryLogger
internal.JoinServerOptions = newJoinServerOption
+ internal.RecvBufferPool = recvBufferPool
}
var statusOK = status.New(codes.OK, "")
var logger = grpclog.Component("core")
-type methodHandler func(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor UnaryServerInterceptor) (interface{}, error)
+type methodHandler func(srv any, ctx context.Context, dec func(any) error, interceptor UnaryServerInterceptor) (any, error)
// MethodDesc represents an RPC service's method specification.
type MethodDesc struct {
@@ -99,20 +101,20 @@ type ServiceDesc struct {
ServiceName string
// The pointer to the service interface. Used to check whether the user
// provided implementation satisfies the interface requirements.
- HandlerType interface{}
+ HandlerType any
Methods []MethodDesc
Streams []StreamDesc
- Metadata interface{}
+ Metadata any
}
// serviceInfo wraps information about a service. It is very similar to
// ServiceDesc and is constructed from it for internal purposes.
type serviceInfo struct {
// Contains the implementation for the methods in this service.
- serviceImpl interface{}
+ serviceImpl any
methods map[string]*MethodDesc
streams map[string]*StreamDesc
- mdata interface{}
+ mdata any
}
// Server is a gRPC server to serve RPC requests.
@@ -134,12 +136,14 @@ type Server struct {
quit *grpcsync.Event
done *grpcsync.Event
channelzRemoveOnce sync.Once
- serveWG sync.WaitGroup // counts active Serve goroutines for GracefulStop
+ serveWG sync.WaitGroup // counts active Serve goroutines for Stop/GracefulStop
+ handlersWG sync.WaitGroup // counts active method handler goroutines
channelzID *channelz.Identifier
czData *channelzData
- serverWorkerChannel chan func()
+ serverWorkerChannel chan func()
+ serverWorkerChannelClose func()
}
type serverOptions struct {
@@ -164,10 +168,13 @@ type serverOptions struct {
initialConnWindowSize int32
writeBufferSize int
readBufferSize int
+ sharedWriteBuffer bool
connectionTimeout time.Duration
maxHeaderListSize *uint32
headerTableSize *uint32
numServerWorkers uint32
+ recvBufferPool SharedBufferPool
+ waitForHandlers bool
}
var defaultServerOptions = serverOptions{
@@ -177,6 +184,7 @@ var defaultServerOptions = serverOptions{
connectionTimeout: 120 * time.Second,
writeBufferSize: defaultWriteBufSize,
readBufferSize: defaultReadBufSize,
+ recvBufferPool: nopBufferPool{},
}
var globalServerOptions []ServerOption
@@ -228,6 +236,20 @@ func newJoinServerOption(opts ...ServerOption) ServerOption {
return &joinServerOption{opts: opts}
}
+// SharedWriteBuffer allows reusing per-connection transport write buffer.
+// If this option is set to true every connection will release the buffer after
+// flushing the data on the wire.
+//
+// # Experimental
+//
+// Notice: This API is EXPERIMENTAL and may be changed or removed in a
+// later release.
+func SharedWriteBuffer(val bool) ServerOption {
+ return newFuncServerOption(func(o *serverOptions) {
+ o.sharedWriteBuffer = val
+ })
+}
+
// WriteBufferSize determines how much data can be batched before doing a write
// on the wire. The corresponding memory allocation for this buffer will be
// twice the size to keep syscalls low. The default value for this buffer is
@@ -268,9 +290,9 @@ func InitialConnWindowSize(s int32) ServerOption {
// KeepaliveParams returns a ServerOption that sets keepalive and max-age parameters for the server.
func KeepaliveParams(kp keepalive.ServerParameters) ServerOption {
- if kp.Time > 0 && kp.Time < time.Second {
+ if kp.Time > 0 && kp.Time < internal.KeepaliveMinServerPingTime {
logger.Warning("Adjusting keepalive ping interval to minimum period of 1s")
- kp.Time = time.Second
+ kp.Time = internal.KeepaliveMinServerPingTime
}
return newFuncServerOption(func(o *serverOptions) {
@@ -550,6 +572,44 @@ func NumStreamWorkers(numServerWorkers uint32) ServerOption {
})
}
+// WaitForHandlers cause Stop to wait until all outstanding method handlers have
+// exited before returning. If false, Stop will return as soon as all
+// connections have closed, but method handlers may still be running. By
+// default, Stop does not wait for method handlers to return.
+//
+// # Experimental
+//
+// Notice: This API is EXPERIMENTAL and may be changed or removed in a
+// later release.
+func WaitForHandlers(w bool) ServerOption {
+ return newFuncServerOption(func(o *serverOptions) {
+ o.waitForHandlers = w
+ })
+}
+
+// RecvBufferPool returns a ServerOption that configures the server
+// to use the provided shared buffer pool for parsing incoming messages. Depending
+// on the application's workload, this could result in reduced memory allocation.
+//
+// If you are unsure about how to implement a memory pool but want to utilize one,
+// begin with grpc.NewSharedBufferPool.
+//
+// Note: The shared buffer pool feature will not be active if any of the following
+// options are used: StatsHandler, EnableTracing, or binary logging. In such
+// cases, the shared buffer pool will be ignored.
+//
+// Deprecated: use experimental.WithRecvBufferPool instead. Will be deleted in
+// v1.60.0 or later.
+func RecvBufferPool(bufferPool SharedBufferPool) ServerOption {
+ return recvBufferPool(bufferPool)
+}
+
+func recvBufferPool(bufferPool SharedBufferPool) ServerOption {
+ return newFuncServerOption(func(o *serverOptions) {
+ o.recvBufferPool = bufferPool
+ })
+}
+
// serverWorkerResetThreshold defines how often the stack must be reset. Every
// N requests, by spawning a new goroutine in its place, a worker can reset its
// stack so that large stacks don't live in memory forever. 2^16 should allow
@@ -578,15 +638,14 @@ func (s *Server) serverWorker() {
// connections to reduce the time spent overall on runtime.morestack.
func (s *Server) initServerWorkers() {
s.serverWorkerChannel = make(chan func())
+ s.serverWorkerChannelClose = grpcsync.OnceFunc(func() {
+ close(s.serverWorkerChannel)
+ })
for i := uint32(0); i < s.opts.numServerWorkers; i++ {
go s.serverWorker()
}
}
-func (s *Server) stopServerWorkers() {
- close(s.serverWorkerChannel)
-}
-
// NewServer creates a gRPC server which has no service registered and has not
// started to accept requests yet.
func NewServer(opt ...ServerOption) *Server {
@@ -625,7 +684,7 @@ func NewServer(opt ...ServerOption) *Server {
// printf records an event in s's event log, unless s has been stopped.
// REQUIRES s.mu is held.
-func (s *Server) printf(format string, a ...interface{}) {
+func (s *Server) printf(format string, a ...any) {
if s.events != nil {
s.events.Printf(format, a...)
}
@@ -633,7 +692,7 @@ func (s *Server) printf(format string, a ...interface{}) {
// errorf records an error in s's event log, unless s has been stopped.
// REQUIRES s.mu is held.
-func (s *Server) errorf(format string, a ...interface{}) {
+func (s *Server) errorf(format string, a ...any) {
if s.events != nil {
s.events.Errorf(format, a...)
}
@@ -648,14 +707,14 @@ type ServiceRegistrar interface {
// once the server has started serving.
// desc describes the service and its methods and handlers. impl is the
// service implementation which is passed to the method handlers.
- RegisterService(desc *ServiceDesc, impl interface{})
+ RegisterService(desc *ServiceDesc, impl any)
}
// RegisterService registers a service and its implementation to the gRPC
// server. It is called from the IDL generated code. This must be called before
// invoking Serve. If ss is non-nil (for legacy code), its type is checked to
// ensure it implements sd.HandlerType.
-func (s *Server) RegisterService(sd *ServiceDesc, ss interface{}) {
+func (s *Server) RegisterService(sd *ServiceDesc, ss any) {
if ss != nil {
ht := reflect.TypeOf(sd.HandlerType).Elem()
st := reflect.TypeOf(ss)
@@ -666,7 +725,7 @@ func (s *Server) RegisterService(sd *ServiceDesc, ss interface{}) {
s.register(sd, ss)
}
-func (s *Server) register(sd *ServiceDesc, ss interface{}) {
+func (s *Server) register(sd *ServiceDesc, ss any) {
s.mu.Lock()
defer s.mu.Unlock()
s.printf("RegisterService(%q)", sd.ServiceName)
@@ -707,7 +766,7 @@ type MethodInfo struct {
type ServiceInfo struct {
Methods []MethodInfo
// Metadata is the metadata specified in ServiceDesc when registering service.
- Metadata interface{}
+ Metadata any
}
// GetServiceInfo returns a map from service names to ServiceInfo.
@@ -768,6 +827,18 @@ func (l *listenSocket) Close() error {
// Serve returns when lis.Accept fails with fatal errors. lis will be closed when
// this method returns.
// Serve will return a non-nil error unless Stop or GracefulStop is called.
+//
+// Note: All supported releases of Go (as of December 2023) override the OS
+// defaults for TCP keepalive time and interval to 15s. To enable TCP keepalive
+// with OS defaults for keepalive time and interval, callers need to do the
+// following two things:
+// - pass a net.Listener created by calling the Listen method on a
+// net.ListenConfig with the `KeepAlive` field set to a negative value. This
+// will result in the Go standard library not overriding OS defaults for TCP
+// keepalive interval and time. But this will also result in the Go standard
+// library not enabling TCP keepalives by default.
+// - override the Accept method on the passed in net.Listener and set the
+// SO_KEEPALIVE socket option to enable TCP keepalives, with OS defaults.
func (s *Server) Serve(lis net.Listener) error {
s.mu.Lock()
s.printf("serving")
@@ -875,24 +946,21 @@ func (s *Server) handleRawConn(lisAddr string, rawConn net.Conn) {
return
}
+ if cc, ok := rawConn.(interface {
+ PassServerTransport(transport.ServerTransport)
+ }); ok {
+ cc.PassServerTransport(st)
+ }
+
if !s.addConn(lisAddr, st) {
return
}
go func() {
- s.serveStreams(st)
+ s.serveStreams(context.Background(), st, rawConn)
s.removeConn(lisAddr, st)
}()
}
-func (s *Server) drainServerTransports(addr string) {
- s.mu.Lock()
- conns := s.conns[addr]
- for st := range conns {
- st.Drain("")
- }
- s.mu.Unlock()
-}
-
// newHTTP2Transport sets up a http/2 transport (using the
// gRPC http2 server transport in transport/http2_server.go).
func (s *Server) newHTTP2Transport(c net.Conn) transport.ServerTransport {
@@ -908,6 +976,7 @@ func (s *Server) newHTTP2Transport(c net.Conn) transport.ServerTransport {
InitialConnWindowSize: s.opts.initialConnWindowSize,
WriteBufferSize: s.opts.writeBufferSize,
ReadBufferSize: s.opts.readBufferSize,
+ SharedWriteBuffer: s.opts.sharedWriteBuffer,
ChannelzParentID: s.channelzID,
MaxHeaderListSize: s.opts.maxHeaderListSize,
HeaderTableSize: s.opts.headerTableSize,
@@ -932,19 +1001,32 @@ func (s *Server) newHTTP2Transport(c net.Conn) transport.ServerTransport {
return st
}
-func (s *Server) serveStreams(st transport.ServerTransport) {
- defer st.Close(errors.New("finished serving streams for the server transport"))
- var wg sync.WaitGroup
+func (s *Server) serveStreams(ctx context.Context, st transport.ServerTransport, rawConn net.Conn) {
+ ctx = transport.SetConnection(ctx, rawConn)
+ ctx = peer.NewContext(ctx, st.Peer())
+ for _, sh := range s.opts.statsHandlers {
+ ctx = sh.TagConn(ctx, &stats.ConnTagInfo{
+ RemoteAddr: st.Peer().Addr,
+ LocalAddr: st.Peer().LocalAddr,
+ })
+ sh.HandleConn(ctx, &stats.ConnBegin{})
+ }
- streamQuota := newHandlerQuota(s.opts.maxConcurrentStreams)
- st.HandleStreams(func(stream *transport.Stream) {
- wg.Add(1)
+ defer func() {
+ st.Close(errors.New("finished serving streams for the server transport"))
+ for _, sh := range s.opts.statsHandlers {
+ sh.HandleConn(ctx, &stats.ConnEnd{})
+ }
+ }()
+ streamQuota := newHandlerQuota(s.opts.maxConcurrentStreams)
+ st.HandleStreams(ctx, func(stream *transport.Stream) {
+ s.handlersWG.Add(1)
streamQuota.acquire()
f := func() {
defer streamQuota.release()
- defer wg.Done()
- s.handleStream(st, stream, s.traceInfo(st, stream))
+ defer s.handlersWG.Done()
+ s.handleStream(st, stream)
}
if s.opts.numServerWorkers > 0 {
@@ -956,14 +1038,7 @@ func (s *Server) serveStreams(st transport.ServerTransport) {
}
}
go f()
- }, func(ctx context.Context, method string) context.Context {
- if !EnableTracing {
- return ctx
- }
- tr := trace.New("grpc.Recv."+methodFamily(method), method)
- return trace.NewContext(ctx, tr)
})
- wg.Wait()
}
var _ http.Handler = (*Server)(nil)
@@ -1007,31 +1082,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
defer s.removeConn(listenerAddressForServeHTTP, st)
- s.serveStreams(st)
-}
-
-// traceInfo returns a traceInfo and associates it with stream, if tracing is enabled.
-// If tracing is not enabled, it returns nil.
-func (s *Server) traceInfo(st transport.ServerTransport, stream *transport.Stream) (trInfo *traceInfo) {
- if !EnableTracing {
- return nil
- }
- tr, ok := trace.FromContext(stream.Context())
- if !ok {
- return nil
- }
-
- trInfo = &traceInfo{
- tr: tr,
- firstLine: firstLine{
- client: false,
- remoteAddr: st.RemoteAddr(),
- },
- }
- if dl, ok := stream.Context().Deadline(); ok {
- trInfo.firstLine.deadline = time.Until(dl)
- }
- return trInfo
+ s.serveStreams(r.Context(), st, nil)
}
func (s *Server) addConn(addr string, st transport.ServerTransport) bool {
@@ -1094,7 +1145,7 @@ func (s *Server) incrCallsFailed() {
atomic.AddInt64(&s.czData.callsFailed, 1)
}
-func (s *Server) sendResponse(t transport.ServerTransport, stream *transport.Stream, msg interface{}, cp Compressor, opts *transport.Options, comp encoding.Compressor) error {
+func (s *Server) sendResponse(ctx context.Context, t transport.ServerTransport, stream *transport.Stream, msg any, cp Compressor, opts *transport.Options, comp encoding.Compressor) error {
data, err := encode(s.getCodec(stream.ContentSubtype()), msg)
if err != nil {
channelz.Error(logger, s.channelzID, "grpc: server failed to encode response: ", err)
@@ -1113,7 +1164,7 @@ func (s *Server) sendResponse(t transport.ServerTransport, stream *transport.Str
err = t.Write(stream, hdr, payload, opts)
if err == nil {
for _, sh := range s.opts.statsHandlers {
- sh.HandleRPC(stream.Context(), outPayload(false, msg, data, payload, time.Now()))
+ sh.HandleRPC(ctx, outPayload(false, msg, data, payload, time.Now()))
}
}
return err
@@ -1141,7 +1192,7 @@ func chainUnaryServerInterceptors(s *Server) {
}
func chainUnaryInterceptors(interceptors []UnaryServerInterceptor) UnaryServerInterceptor {
- return func(ctx context.Context, req interface{}, info *UnaryServerInfo, handler UnaryHandler) (interface{}, error) {
+ return func(ctx context.Context, req any, info *UnaryServerInfo, handler UnaryHandler) (any, error) {
return interceptors[0](ctx, req, info, getChainUnaryHandler(interceptors, 0, info, handler))
}
}
@@ -1150,12 +1201,12 @@ func getChainUnaryHandler(interceptors []UnaryServerInterceptor, curr int, info
if curr == len(interceptors)-1 {
return finalHandler
}
- return func(ctx context.Context, req interface{}) (interface{}, error) {
+ return func(ctx context.Context, req any) (any, error) {
return interceptors[curr+1](ctx, req, info, getChainUnaryHandler(interceptors, curr+1, info, finalHandler))
}
}
-func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.Stream, info *serviceInfo, md *MethodDesc, trInfo *traceInfo) (err error) {
+func (s *Server) processUnaryRPC(ctx context.Context, t transport.ServerTransport, stream *transport.Stream, info *serviceInfo, md *MethodDesc, trInfo *traceInfo) (err error) {
shs := s.opts.statsHandlers
if len(shs) != 0 || trInfo != nil || channelz.IsOn() {
if channelz.IsOn() {
@@ -1169,7 +1220,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
IsClientStream: false,
IsServerStream: false,
}
- sh.HandleRPC(stream.Context(), statsBegin)
+ sh.HandleRPC(ctx, statsBegin)
}
if trInfo != nil {
trInfo.tr.LazyLog(&trInfo.firstLine, false)
@@ -1187,7 +1238,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
defer func() {
if trInfo != nil {
if err != nil && err != io.EOF {
- trInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true)
+ trInfo.tr.LazyLog(&fmtStringer{"%v", []any{err}}, true)
trInfo.tr.SetError()
}
trInfo.tr.Finish()
@@ -1201,7 +1252,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
if err != nil && err != io.EOF {
end.Error = toRPCErr(err)
}
- sh.HandleRPC(stream.Context(), end)
+ sh.HandleRPC(ctx, end)
}
if channelz.IsOn() {
@@ -1223,7 +1274,6 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
}
}
if len(binlogs) != 0 {
- ctx := stream.Context()
md, _ := metadata.FromIncomingContext(ctx)
logEntry := &binarylog.ClientHeader{
Header: md,
@@ -1294,7 +1344,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
if len(shs) != 0 || len(binlogs) != 0 {
payInfo = &payloadInfo{}
}
- d, err := recvAndDecompress(&parser{r: stream}, stream, dc, s.opts.maxReceiveMessageSize, payInfo, decomp)
+ d, err := recvAndDecompress(&parser{r: stream, recvBufferPool: s.opts.recvBufferPool}, stream, dc, s.opts.maxReceiveMessageSize, payInfo, decomp)
if err != nil {
if e := t.WriteStatus(stream, status.Convert(err)); e != nil {
channelz.Warningf(logger, s.channelzID, "grpc: Server.processUnaryRPC failed to write status: %v", e)
@@ -1304,12 +1354,12 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
if channelz.IsOn() {
t.IncrMsgRecv()
}
- df := func(v interface{}) error {
+ df := func(v any) error {
if err := s.getCodec(stream.ContentSubtype()).Unmarshal(d, v); err != nil {
return status.Errorf(codes.Internal, "grpc: error unmarshalling request: %v", err)
}
for _, sh := range shs {
- sh.HandleRPC(stream.Context(), &stats.InPayload{
+ sh.HandleRPC(ctx, &stats.InPayload{
RecvTime: time.Now(),
Payload: v,
Length: len(d),
@@ -1323,7 +1373,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
Message: d,
}
for _, binlog := range binlogs {
- binlog.Log(stream.Context(), cm)
+ binlog.Log(ctx, cm)
}
}
if trInfo != nil {
@@ -1331,7 +1381,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
}
return nil
}
- ctx := NewContextWithServerTransportStream(stream.Context(), stream)
+ ctx = NewContextWithServerTransportStream(ctx, stream)
reply, appErr := md.Handler(info.serviceImpl, ctx, df, s.opts.unaryInt)
if appErr != nil {
appStatus, ok := status.FromError(appErr)
@@ -1356,7 +1406,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
Header: h,
}
for _, binlog := range binlogs {
- binlog.Log(stream.Context(), sh)
+ binlog.Log(ctx, sh)
}
}
st := &binarylog.ServerTrailer{
@@ -1364,7 +1414,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
Err: appErr,
}
for _, binlog := range binlogs {
- binlog.Log(stream.Context(), st)
+ binlog.Log(ctx, st)
}
}
return appErr
@@ -1379,7 +1429,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
if stream.SendCompress() != sendCompressorName {
comp = encoding.GetCompressor(stream.SendCompress())
}
- if err := s.sendResponse(t, stream, reply, cp, opts, comp); err != nil {
+ if err := s.sendResponse(ctx, t, stream, reply, cp, opts, comp); err != nil {
if err == io.EOF {
// The entire stream is done (for unary RPC only).
return err
@@ -1406,8 +1456,8 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
Err: appErr,
}
for _, binlog := range binlogs {
- binlog.Log(stream.Context(), sh)
- binlog.Log(stream.Context(), st)
+ binlog.Log(ctx, sh)
+ binlog.Log(ctx, st)
}
}
return err
@@ -1421,8 +1471,8 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
Message: reply,
}
for _, binlog := range binlogs {
- binlog.Log(stream.Context(), sh)
- binlog.Log(stream.Context(), sm)
+ binlog.Log(ctx, sh)
+ binlog.Log(ctx, sm)
}
}
if channelz.IsOn() {
@@ -1440,7 +1490,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
Err: appErr,
}
for _, binlog := range binlogs {
- binlog.Log(stream.Context(), st)
+ binlog.Log(ctx, st)
}
}
return t.WriteStatus(stream, statusOK)
@@ -1468,7 +1518,7 @@ func chainStreamServerInterceptors(s *Server) {
}
func chainStreamInterceptors(interceptors []StreamServerInterceptor) StreamServerInterceptor {
- return func(srv interface{}, ss ServerStream, info *StreamServerInfo, handler StreamHandler) error {
+ return func(srv any, ss ServerStream, info *StreamServerInfo, handler StreamHandler) error {
return interceptors[0](srv, ss, info, getChainStreamHandler(interceptors, 0, info, handler))
}
}
@@ -1477,12 +1527,12 @@ func getChainStreamHandler(interceptors []StreamServerInterceptor, curr int, inf
if curr == len(interceptors)-1 {
return finalHandler
}
- return func(srv interface{}, stream ServerStream) error {
+ return func(srv any, stream ServerStream) error {
return interceptors[curr+1](srv, stream, info, getChainStreamHandler(interceptors, curr+1, info, finalHandler))
}
}
-func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transport.Stream, info *serviceInfo, sd *StreamDesc, trInfo *traceInfo) (err error) {
+func (s *Server) processStreamingRPC(ctx context.Context, t transport.ServerTransport, stream *transport.Stream, info *serviceInfo, sd *StreamDesc, trInfo *traceInfo) (err error) {
if channelz.IsOn() {
s.incrCallsStarted()
}
@@ -1496,15 +1546,15 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp
IsServerStream: sd.ServerStreams,
}
for _, sh := range shs {
- sh.HandleRPC(stream.Context(), statsBegin)
+ sh.HandleRPC(ctx, statsBegin)
}
}
- ctx := NewContextWithServerTransportStream(stream.Context(), stream)
+ ctx = NewContextWithServerTransportStream(ctx, stream)
ss := &serverStream{
ctx: ctx,
t: t,
s: stream,
- p: &parser{r: stream},
+ p: &parser{r: stream, recvBufferPool: s.opts.recvBufferPool},
codec: s.getCodec(stream.ContentSubtype()),
maxReceiveMessageSize: s.opts.maxReceiveMessageSize,
maxSendMessageSize: s.opts.maxSendMessageSize,
@@ -1518,7 +1568,7 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp
if trInfo != nil {
ss.mu.Lock()
if err != nil && err != io.EOF {
- ss.trInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true)
+ ss.trInfo.tr.LazyLog(&fmtStringer{"%v", []any{err}}, true)
ss.trInfo.tr.SetError()
}
ss.trInfo.tr.Finish()
@@ -1535,7 +1585,7 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp
end.Error = toRPCErr(err)
}
for _, sh := range shs {
- sh.HandleRPC(stream.Context(), end)
+ sh.HandleRPC(ctx, end)
}
}
@@ -1577,7 +1627,7 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp
logEntry.PeerAddr = peer.Addr
}
for _, binlog := range ss.binlogs {
- binlog.Log(stream.Context(), logEntry)
+ binlog.Log(ctx, logEntry)
}
}
@@ -1621,7 +1671,7 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp
trInfo.tr.LazyLog(&trInfo.firstLine, false)
}
var appErr error
- var server interface{}
+ var server any
if info != nil {
server = info.serviceImpl
}
@@ -1655,7 +1705,7 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp
Err: appErr,
}
for _, binlog := range ss.binlogs {
- binlog.Log(stream.Context(), st)
+ binlog.Log(ctx, st)
}
}
t.WriteStatus(ss.s, appStatus)
@@ -1673,53 +1723,87 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp
Err: appErr,
}
for _, binlog := range ss.binlogs {
- binlog.Log(stream.Context(), st)
+ binlog.Log(ctx, st)
}
}
return t.WriteStatus(ss.s, statusOK)
}
-func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Stream, trInfo *traceInfo) {
+func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Stream) {
+ ctx := stream.Context()
+ ctx = contextWithServer(ctx, s)
+ var ti *traceInfo
+ if EnableTracing {
+ tr := trace.New("grpc.Recv."+methodFamily(stream.Method()), stream.Method())
+ ctx = trace.NewContext(ctx, tr)
+ ti = &traceInfo{
+ tr: tr,
+ firstLine: firstLine{
+ client: false,
+ remoteAddr: t.Peer().Addr,
+ },
+ }
+ if dl, ok := ctx.Deadline(); ok {
+ ti.firstLine.deadline = time.Until(dl)
+ }
+ }
+
sm := stream.Method()
if sm != "" && sm[0] == '/' {
sm = sm[1:]
}
pos := strings.LastIndex(sm, "/")
if pos == -1 {
- if trInfo != nil {
- trInfo.tr.LazyLog(&fmtStringer{"Malformed method name %q", []interface{}{sm}}, true)
- trInfo.tr.SetError()
+ if ti != nil {
+ ti.tr.LazyLog(&fmtStringer{"Malformed method name %q", []any{sm}}, true)
+ ti.tr.SetError()
}
errDesc := fmt.Sprintf("malformed method name: %q", stream.Method())
if err := t.WriteStatus(stream, status.New(codes.Unimplemented, errDesc)); err != nil {
- if trInfo != nil {
- trInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true)
- trInfo.tr.SetError()
+ if ti != nil {
+ ti.tr.LazyLog(&fmtStringer{"%v", []any{err}}, true)
+ ti.tr.SetError()
}
channelz.Warningf(logger, s.channelzID, "grpc: Server.handleStream failed to write status: %v", err)
}
- if trInfo != nil {
- trInfo.tr.Finish()
+ if ti != nil {
+ ti.tr.Finish()
}
return
}
service := sm[:pos]
method := sm[pos+1:]
+ md, _ := metadata.FromIncomingContext(ctx)
+ for _, sh := range s.opts.statsHandlers {
+ ctx = sh.TagRPC(ctx, &stats.RPCTagInfo{FullMethodName: stream.Method()})
+ sh.HandleRPC(ctx, &stats.InHeader{
+ FullMethod: stream.Method(),
+ RemoteAddr: t.Peer().Addr,
+ LocalAddr: t.Peer().LocalAddr,
+ Compression: stream.RecvCompress(),
+ WireLength: stream.HeaderWireLength(),
+ Header: md,
+ })
+ }
+ // To have calls in stream callouts work. Will delete once all stats handler
+ // calls come from the gRPC layer.
+ stream.SetContext(ctx)
+
srv, knownService := s.services[service]
if knownService {
if md, ok := srv.methods[method]; ok {
- s.processUnaryRPC(t, stream, srv, md, trInfo)
+ s.processUnaryRPC(ctx, t, stream, srv, md, ti)
return
}
if sd, ok := srv.streams[method]; ok {
- s.processStreamingRPC(t, stream, srv, sd, trInfo)
+ s.processStreamingRPC(ctx, t, stream, srv, sd, ti)
return
}
}
// Unknown service, or known server unknown method.
if unknownDesc := s.opts.unknownStreamDesc; unknownDesc != nil {
- s.processStreamingRPC(t, stream, nil, unknownDesc, trInfo)
+ s.processStreamingRPC(ctx, t, stream, nil, unknownDesc, ti)
return
}
var errDesc string
@@ -1728,19 +1812,19 @@ func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Str
} else {
errDesc = fmt.Sprintf("unknown method %v for service %v", method, service)
}
- if trInfo != nil {
- trInfo.tr.LazyPrintf("%s", errDesc)
- trInfo.tr.SetError()
+ if ti != nil {
+ ti.tr.LazyPrintf("%s", errDesc)
+ ti.tr.SetError()
}
if err := t.WriteStatus(stream, status.New(codes.Unimplemented, errDesc)); err != nil {
- if trInfo != nil {
- trInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true)
- trInfo.tr.SetError()
+ if ti != nil {
+ ti.tr.LazyLog(&fmtStringer{"%v", []any{err}}, true)
+ ti.tr.SetError()
}
channelz.Warningf(logger, s.channelzID, "grpc: Server.handleStream failed to write status: %v", err)
}
- if trInfo != nil {
- trInfo.tr.Finish()
+ if ti != nil {
+ ti.tr.Finish()
}
}
@@ -1795,62 +1879,72 @@ func ServerTransportStreamFromContext(ctx context.Context) ServerTransportStream
// pending RPCs on the client side will get notified by connection
// errors.
func (s *Server) Stop() {
- s.quit.Fire()
+ s.stop(false)
+}
- defer func() {
- s.serveWG.Wait()
- s.done.Fire()
- }()
+// GracefulStop stops the gRPC server gracefully. It stops the server from
+// accepting new connections and RPCs and blocks until all the pending RPCs are
+// finished.
+func (s *Server) GracefulStop() {
+ s.stop(true)
+}
+
+func (s *Server) stop(graceful bool) {
+ s.quit.Fire()
+ defer s.done.Fire()
s.channelzRemoveOnce.Do(func() { channelz.RemoveEntry(s.channelzID) })
s.mu.Lock()
- listeners := s.lis
- s.lis = nil
- conns := s.conns
- s.conns = nil
- // interrupt GracefulStop if Stop and GracefulStop are called concurrently.
- s.cv.Broadcast()
+ s.closeListenersLocked()
+ // Wait for serving threads to be ready to exit. Only then can we be sure no
+ // new conns will be created.
s.mu.Unlock()
+ s.serveWG.Wait()
- for lis := range listeners {
- lis.Close()
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
+ if graceful {
+ s.drainAllServerTransportsLocked()
+ } else {
+ s.closeServerTransportsLocked()
}
- for _, cs := range conns {
- for st := range cs {
- st.Close(errors.New("Server.Stop called"))
- }
+
+ for len(s.conns) != 0 {
+ s.cv.Wait()
}
+ s.conns = nil
+
if s.opts.numServerWorkers > 0 {
- s.stopServerWorkers()
+ // Closing the channel (only once, via grpcsync.OnceFunc) after all the
+ // connections have been closed above ensures that there are no
+ // goroutines executing the callback passed to st.HandleStreams (where
+ // the channel is written to).
+ s.serverWorkerChannelClose()
+ }
+
+ if graceful || s.opts.waitForHandlers {
+ s.handlersWG.Wait()
}
- s.mu.Lock()
if s.events != nil {
s.events.Finish()
s.events = nil
}
- s.mu.Unlock()
}
-// GracefulStop stops the gRPC server gracefully. It stops the server from
-// accepting new connections and RPCs and blocks until all the pending RPCs are
-// finished.
-func (s *Server) GracefulStop() {
- s.quit.Fire()
- defer s.done.Fire()
-
- s.channelzRemoveOnce.Do(func() { channelz.RemoveEntry(s.channelzID) })
- s.mu.Lock()
- if s.conns == nil {
- s.mu.Unlock()
- return
+// s.mu must be held by the caller.
+func (s *Server) closeServerTransportsLocked() {
+ for _, conns := range s.conns {
+ for st := range conns {
+ st.Close(errors.New("Server.Stop called"))
+ }
}
+}
- for lis := range s.lis {
- lis.Close()
- }
- s.lis = nil
+// s.mu must be held by the caller.
+func (s *Server) drainAllServerTransportsLocked() {
if !s.drain {
for _, conns := range s.conns {
for st := range conns {
@@ -1859,22 +1953,14 @@ func (s *Server) GracefulStop() {
}
s.drain = true
}
+}
- // Wait for serving threads to be ready to exit. Only then can we be sure no
- // new conns will be created.
- s.mu.Unlock()
- s.serveWG.Wait()
- s.mu.Lock()
-
- for len(s.conns) != 0 {
- s.cv.Wait()
- }
- s.conns = nil
- if s.events != nil {
- s.events.Finish()
- s.events = nil
+// s.mu must be held by the caller.
+func (s *Server) closeListenersLocked() {
+ for lis := range s.lis {
+ lis.Close()
}
- s.mu.Unlock()
+ s.lis = nil
}
// contentSubtype must be lowercase
@@ -1888,11 +1974,50 @@ func (s *Server) getCodec(contentSubtype string) baseCodec {
}
codec := encoding.GetCodec(contentSubtype)
if codec == nil {
+ logger.Warningf("Unsupported codec %q. Defaulting to %q for now. This will start to fail in future releases.", contentSubtype, proto.Name)
return encoding.GetCodec(proto.Name)
}
return codec
}
+type serverKey struct{}
+
+// serverFromContext gets the Server from the context.
+func serverFromContext(ctx context.Context) *Server {
+ s, _ := ctx.Value(serverKey{}).(*Server)
+ return s
+}
+
+// contextWithServer sets the Server in the context.
+func contextWithServer(ctx context.Context, server *Server) context.Context {
+ return context.WithValue(ctx, serverKey{}, server)
+}
+
+// isRegisteredMethod returns whether the passed in method is registered as a
+// method on the server. /service/method and service/method will match if the
+// service and method are registered on the server.
+func (s *Server) isRegisteredMethod(serviceMethod string) bool {
+ if serviceMethod != "" && serviceMethod[0] == '/' {
+ serviceMethod = serviceMethod[1:]
+ }
+ pos := strings.LastIndex(serviceMethod, "/")
+ if pos == -1 { // Invalid method name syntax.
+ return false
+ }
+ service := serviceMethod[:pos]
+ method := serviceMethod[pos+1:]
+ srv, knownService := s.services[service]
+ if knownService {
+ if _, ok := srv.methods[method]; ok {
+ return true
+ }
+ if _, ok := srv.streams[method]; ok {
+ return true
+ }
+ }
+ return false
+}
+
// SetHeader sets the header metadata to be sent from the server to the client.
// The context provided must be the context passed to the server's handler.
//
@@ -2054,12 +2179,12 @@ func validateSendCompressor(name, clientCompressors string) error {
// atomicSemaphore implements a blocking, counting semaphore. acquire should be
// called synchronously; release may be called asynchronously.
type atomicSemaphore struct {
- n int64
+ n atomic.Int64
wait chan struct{}
}
func (q *atomicSemaphore) acquire() {
- if atomic.AddInt64(&q.n, -1) < 0 {
+ if q.n.Add(-1) < 0 {
// We ran out of quota. Block until a release happens.
<-q.wait
}
@@ -2070,12 +2195,14 @@ func (q *atomicSemaphore) release() {
// concurrent calls to acquire, but also note that with synchronous calls to
// acquire, as our system does, n will never be less than -1. There are
// fairness issues (queuing) to consider if this was to be generalized.
- if atomic.AddInt64(&q.n, 1) <= 0 {
+ if q.n.Add(1) <= 0 {
// An acquire was waiting on us. Unblock it.
q.wait <- struct{}{}
}
}
func newHandlerQuota(n uint32) *atomicSemaphore {
- return &atomicSemaphore{n: int64(n), wait: make(chan struct{}, 1)}
+ a := &atomicSemaphore{wait: make(chan struct{}, 1)}
+ a.n.Store(int64(n))
+ return a
}
diff --git a/vendor/google.golang.org/grpc/shared_buffer_pool.go b/vendor/google.golang.org/grpc/shared_buffer_pool.go
new file mode 100644
index 00000000..48a64cfe
--- /dev/null
+++ b/vendor/google.golang.org/grpc/shared_buffer_pool.go
@@ -0,0 +1,154 @@
+/*
+ *
+ * Copyright 2023 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 grpc
+
+import "sync"
+
+// SharedBufferPool is a pool of buffers that can be shared, resulting in
+// decreased memory allocation. Currently, in gRPC-go, it is only utilized
+// for parsing incoming messages.
+//
+// # Experimental
+//
+// Notice: This API is EXPERIMENTAL and may be changed or removed in a
+// later release.
+type SharedBufferPool interface {
+ // Get returns a buffer with specified length from the pool.
+ //
+ // The returned byte slice may be not zero initialized.
+ Get(length int) []byte
+
+ // Put returns a buffer to the pool.
+ Put(*[]byte)
+}
+
+// NewSharedBufferPool creates a simple SharedBufferPool with buckets
+// of different sizes to optimize memory usage. This prevents the pool from
+// wasting large amounts of memory, even when handling messages of varying sizes.
+//
+// # Experimental
+//
+// Notice: This API is EXPERIMENTAL and may be changed or removed in a
+// later release.
+func NewSharedBufferPool() SharedBufferPool {
+ return &simpleSharedBufferPool{
+ pools: [poolArraySize]simpleSharedBufferChildPool{
+ newBytesPool(level0PoolMaxSize),
+ newBytesPool(level1PoolMaxSize),
+ newBytesPool(level2PoolMaxSize),
+ newBytesPool(level3PoolMaxSize),
+ newBytesPool(level4PoolMaxSize),
+ newBytesPool(0),
+ },
+ }
+}
+
+// simpleSharedBufferPool is a simple implementation of SharedBufferPool.
+type simpleSharedBufferPool struct {
+ pools [poolArraySize]simpleSharedBufferChildPool
+}
+
+func (p *simpleSharedBufferPool) Get(size int) []byte {
+ return p.pools[p.poolIdx(size)].Get(size)
+}
+
+func (p *simpleSharedBufferPool) Put(bs *[]byte) {
+ p.pools[p.poolIdx(cap(*bs))].Put(bs)
+}
+
+func (p *simpleSharedBufferPool) poolIdx(size int) int {
+ switch {
+ case size <= level0PoolMaxSize:
+ return level0PoolIdx
+ case size <= level1PoolMaxSize:
+ return level1PoolIdx
+ case size <= level2PoolMaxSize:
+ return level2PoolIdx
+ case size <= level3PoolMaxSize:
+ return level3PoolIdx
+ case size <= level4PoolMaxSize:
+ return level4PoolIdx
+ default:
+ return levelMaxPoolIdx
+ }
+}
+
+const (
+ level0PoolMaxSize = 16 // 16 B
+ level1PoolMaxSize = level0PoolMaxSize * 16 // 256 B
+ level2PoolMaxSize = level1PoolMaxSize * 16 // 4 KB
+ level3PoolMaxSize = level2PoolMaxSize * 16 // 64 KB
+ level4PoolMaxSize = level3PoolMaxSize * 16 // 1 MB
+)
+
+const (
+ level0PoolIdx = iota
+ level1PoolIdx
+ level2PoolIdx
+ level3PoolIdx
+ level4PoolIdx
+ levelMaxPoolIdx
+ poolArraySize
+)
+
+type simpleSharedBufferChildPool interface {
+ Get(size int) []byte
+ Put(any)
+}
+
+type bufferPool struct {
+ sync.Pool
+
+ defaultSize int
+}
+
+func (p *bufferPool) Get(size int) []byte {
+ bs := p.Pool.Get().(*[]byte)
+
+ if cap(*bs) < size {
+ p.Pool.Put(bs)
+
+ return make([]byte, size)
+ }
+
+ return (*bs)[:size]
+}
+
+func newBytesPool(size int) simpleSharedBufferChildPool {
+ return &bufferPool{
+ Pool: sync.Pool{
+ New: func() any {
+ bs := make([]byte, size)
+ return &bs
+ },
+ },
+ defaultSize: size,
+ }
+}
+
+// nopBufferPool is a buffer pool just makes new buffer without pooling.
+type nopBufferPool struct {
+}
+
+func (nopBufferPool) Get(length int) []byte {
+ return make([]byte, length)
+}
+
+func (nopBufferPool) Put(*[]byte) {
+}
diff --git a/vendor/google.golang.org/grpc/stats/stats.go b/vendor/google.golang.org/grpc/stats/stats.go
index 7a552a9b..4ab70e2d 100644
--- a/vendor/google.golang.org/grpc/stats/stats.go
+++ b/vendor/google.golang.org/grpc/stats/stats.go
@@ -59,12 +59,22 @@ func (s *Begin) IsClient() bool { return s.Client }
func (s *Begin) isRPCStats() {}
+// PickerUpdated indicates that the LB policy provided a new picker while the
+// RPC was waiting for one.
+type PickerUpdated struct{}
+
+// IsClient indicates if the stats information is from client side. Only Client
+// Side interfaces with a Picker, thus always returns true.
+func (*PickerUpdated) IsClient() bool { return true }
+
+func (*PickerUpdated) isRPCStats() {}
+
// InPayload contains the information for an incoming payload.
type InPayload struct {
// Client is true if this InPayload is from client side.
Client bool
// Payload is the payload with original type.
- Payload interface{}
+ Payload any
// Data is the serialized message payload.
Data []byte
@@ -134,7 +144,7 @@ type OutPayload struct {
// Client is true if this OutPayload is from client side.
Client bool
// Payload is the payload with original type.
- Payload interface{}
+ Payload any
// Data is the serialized message payload.
Data []byte
// Length is the size of the uncompressed payload data. Does not include any
diff --git a/vendor/google.golang.org/grpc/status/status.go b/vendor/google.golang.org/grpc/status/status.go
index bcf2e4d8..a93360ef 100644
--- a/vendor/google.golang.org/grpc/status/status.go
+++ b/vendor/google.golang.org/grpc/status/status.go
@@ -50,7 +50,7 @@ func New(c codes.Code, msg string) *Status {
}
// Newf returns New(c, fmt.Sprintf(format, a...)).
-func Newf(c codes.Code, format string, a ...interface{}) *Status {
+func Newf(c codes.Code, format string, a ...any) *Status {
return New(c, fmt.Sprintf(format, a...))
}
@@ -60,7 +60,7 @@ func Error(c codes.Code, msg string) error {
}
// Errorf returns Error(c, fmt.Sprintf(format, a...)).
-func Errorf(c codes.Code, format string, a ...interface{}) error {
+func Errorf(c codes.Code, format string, a ...any) error {
return Error(c, fmt.Sprintf(format, a...))
}
@@ -99,25 +99,27 @@ func FromError(err error) (s *Status, ok bool) {
}
type grpcstatus interface{ GRPCStatus() *Status }
if gs, ok := err.(grpcstatus); ok {
- if gs.GRPCStatus() == nil {
+ grpcStatus := gs.GRPCStatus()
+ if grpcStatus == nil {
// Error has status nil, which maps to codes.OK. There
// is no sensible behavior for this, so we turn it into
// an error with codes.Unknown and discard the existing
// status.
return New(codes.Unknown, err.Error()), false
}
- return gs.GRPCStatus(), true
+ return grpcStatus, true
}
var gs grpcstatus
if errors.As(err, &gs) {
- if gs.GRPCStatus() == nil {
+ grpcStatus := gs.GRPCStatus()
+ if grpcStatus == nil {
// Error wraps an error that has status nil, which maps
// to codes.OK. There is no sensible behavior for this,
// so we turn it into an error with codes.Unknown and
// discard the existing status.
return New(codes.Unknown, err.Error()), false
}
- p := gs.GRPCStatus().Proto()
+ p := grpcStatus.Proto()
p.Message = err.Error()
return status.FromProto(p), true
}
diff --git a/vendor/google.golang.org/grpc/stream.go b/vendor/google.golang.org/grpc/stream.go
index 10092685..d621f52b 100644
--- a/vendor/google.golang.org/grpc/stream.go
+++ b/vendor/google.golang.org/grpc/stream.go
@@ -31,6 +31,7 @@ import (
"google.golang.org/grpc/balancer"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/encoding"
+ "google.golang.org/grpc/internal"
"google.golang.org/grpc/internal/balancerload"
"google.golang.org/grpc/internal/binarylog"
"google.golang.org/grpc/internal/channelz"
@@ -47,6 +48,8 @@ import (
"google.golang.org/grpc/status"
)
+var metadataFromOutgoingContextRaw = internal.FromOutgoingContextRaw.(func(context.Context) (metadata.MD, [][]string, bool))
+
// StreamHandler defines the handler called by gRPC server to complete the
// execution of a streaming RPC.
//
@@ -54,7 +57,7 @@ import (
// status package, or be one of the context errors. Otherwise, gRPC will use
// codes.Unknown as the status code and err.Error() as the status message of the
// RPC.
-type StreamHandler func(srv interface{}, stream ServerStream) error
+type StreamHandler func(srv any, stream ServerStream) error
// StreamDesc represents a streaming RPC service's method specification. Used
// on the server when registering services and on the client when initiating
@@ -79,9 +82,9 @@ type Stream interface {
// Deprecated: See ClientStream and ServerStream documentation instead.
Context() context.Context
// Deprecated: See ClientStream and ServerStream documentation instead.
- SendMsg(m interface{}) error
+ SendMsg(m any) error
// Deprecated: See ClientStream and ServerStream documentation instead.
- RecvMsg(m interface{}) error
+ RecvMsg(m any) error
}
// ClientStream defines the client-side behavior of a streaming RPC.
@@ -90,7 +93,9 @@ type Stream interface {
// status package.
type ClientStream interface {
// Header returns the header metadata received from the server if there
- // is any. It blocks if the metadata is not ready to read.
+ // is any. It blocks if the metadata is not ready to read. If the metadata
+ // is nil and the error is also nil, then the stream was terminated without
+ // headers, and the status can be discovered by calling RecvMsg.
Header() (metadata.MD, error)
// Trailer returns the trailer metadata from the server, if there is any.
// It must only be called after stream.CloseAndRecv has returned, or
@@ -126,7 +131,7 @@ type ClientStream interface {
//
// It is not safe to modify the message after calling SendMsg. Tracing
// libraries and stats handlers may use the message lazily.
- SendMsg(m interface{}) error
+ SendMsg(m any) error
// RecvMsg blocks until it receives a message into m or the stream is
// done. It returns io.EOF when the stream completes successfully. On
// any other error, the stream is aborted and the error contains the RPC
@@ -135,7 +140,7 @@ type ClientStream interface {
// It is safe to have a goroutine calling SendMsg and another goroutine
// calling RecvMsg on the same stream at the same time, but it is not
// safe to call RecvMsg on the same stream in different goroutines.
- RecvMsg(m interface{}) error
+ RecvMsg(m any) error
}
// NewStream creates a new Stream for the client side. This is typically
@@ -155,11 +160,6 @@ type ClientStream interface {
// If none of the above happen, a goroutine and a context will be leaked, and grpc
// will not call the optionally-configured stats handler with a stats.End message.
func (cc *ClientConn) NewStream(ctx context.Context, desc *StreamDesc, method string, opts ...CallOption) (ClientStream, error) {
- if err := cc.idlenessMgr.onCallBegin(); err != nil {
- return nil, err
- }
- defer cc.idlenessMgr.onCallEnd()
-
// allow interceptor to see all applicable call options, which means those
// configured as defaults from dial option as well as per-call options
opts = combine(cc.dopts.callOptions, opts)
@@ -176,7 +176,17 @@ func NewClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth
}
func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, opts ...CallOption) (_ ClientStream, err error) {
- if md, added, ok := metadata.FromOutgoingContextRaw(ctx); ok {
+ // Start tracking the RPC for idleness purposes. This is where a stream is
+ // created for both streaming and unary RPCs, and hence is a good place to
+ // track active RPC count.
+ if err := cc.idlenessMgr.OnCallBegin(); err != nil {
+ return nil, err
+ }
+ // Add a calloption, to decrement the active call count, that gets executed
+ // when the RPC completes.
+ opts = append([]CallOption{OnFinish(func(error) { cc.idlenessMgr.OnCallEnd() })}, opts...)
+
+ if md, added, ok := metadataFromOutgoingContextRaw(ctx); ok {
// validate md
if err := imetadata.Validate(md); err != nil {
return nil, status.Error(codes.Internal, err.Error())
@@ -433,7 +443,7 @@ func (cs *clientStream) newAttemptLocked(isTransparent bool) (*csAttempt, error)
ctx = trace.NewContext(ctx, trInfo.tr)
}
- if cs.cc.parsedTarget.URL.Scheme == "xds" {
+ if cs.cc.parsedTarget.URL.Scheme == internal.GRPCResolverSchemeExtraMetadata {
// Add extra metadata (metadata that will be added by transport) to context
// so the balancer can see them.
ctx = grpcutil.WithExtraMetadata(ctx, metadata.Pairs(
@@ -507,7 +517,7 @@ func (a *csAttempt) newStream() error {
return toRPCErr(nse.Err)
}
a.s = s
- a.p = &parser{r: s}
+ a.p = &parser{r: s, recvBufferPool: a.cs.cc.dopts.recvBufferPool}
return nil
}
@@ -788,23 +798,24 @@ func (cs *clientStream) withRetry(op func(a *csAttempt) error, onSuccess func())
func (cs *clientStream) Header() (metadata.MD, error) {
var m metadata.MD
- noHeader := false
err := cs.withRetry(func(a *csAttempt) error {
var err error
m, err = a.s.Header()
- if err == transport.ErrNoHeaders {
- noHeader = true
- return nil
- }
return toRPCErr(err)
}, cs.commitAttemptLocked)
+ if m == nil && err == nil {
+ // The stream ended with success. Finish the clientStream.
+ err = io.EOF
+ }
+
if err != nil {
cs.finish(err)
- return nil, err
+ // Do not return the error. The user should get it by calling Recv().
+ return nil, nil
}
- if len(cs.binlogs) != 0 && !cs.serverHeaderBinlogged && !noHeader {
+ if len(cs.binlogs) != 0 && !cs.serverHeaderBinlogged && m != nil {
// Only log if binary log is on and header has not been logged, and
// there is actually headers to log.
logEntry := &binarylog.ServerHeader{
@@ -820,6 +831,7 @@ func (cs *clientStream) Header() (metadata.MD, error) {
binlog.Log(cs.ctx, logEntry)
}
}
+
return m, nil
}
@@ -860,7 +872,7 @@ func (cs *clientStream) bufferForRetryLocked(sz int, op func(a *csAttempt) error
cs.buffer = append(cs.buffer, op)
}
-func (cs *clientStream) SendMsg(m interface{}) (err error) {
+func (cs *clientStream) SendMsg(m any) (err error) {
defer func() {
if err != nil && err != io.EOF {
// Call finish on the client stream for errors generated by this SendMsg
@@ -904,7 +916,7 @@ func (cs *clientStream) SendMsg(m interface{}) (err error) {
return err
}
-func (cs *clientStream) RecvMsg(m interface{}) error {
+func (cs *clientStream) RecvMsg(m any) error {
if len(cs.binlogs) != 0 && !cs.serverHeaderBinlogged {
// Call Header() to binary log header if it's not already logged.
cs.Header()
@@ -928,24 +940,6 @@ func (cs *clientStream) RecvMsg(m interface{}) error {
if err != nil || !cs.desc.ServerStreams {
// err != nil or non-server-streaming indicates end of stream.
cs.finish(err)
-
- if len(cs.binlogs) != 0 {
- // finish will not log Trailer. Log Trailer here.
- logEntry := &binarylog.ServerTrailer{
- OnClientSide: true,
- Trailer: cs.Trailer(),
- Err: err,
- }
- if logEntry.Err == io.EOF {
- logEntry.Err = nil
- }
- if peer, ok := peer.FromContext(cs.Context()); ok {
- logEntry.PeerAddr = peer.Addr
- }
- for _, binlog := range cs.binlogs {
- binlog.Log(cs.ctx, logEntry)
- }
- }
}
return err
}
@@ -1001,18 +995,30 @@ func (cs *clientStream) finish(err error) {
}
}
}
+
cs.mu.Unlock()
- // For binary logging. only log cancel in finish (could be caused by RPC ctx
- // canceled or ClientConn closed). Trailer will be logged in RecvMsg.
- //
- // Only one of cancel or trailer needs to be logged. In the cases where
- // users don't call RecvMsg, users must have already canceled the RPC.
- if len(cs.binlogs) != 0 && status.Code(err) == codes.Canceled {
- c := &binarylog.Cancel{
- OnClientSide: true,
- }
- for _, binlog := range cs.binlogs {
- binlog.Log(cs.ctx, c)
+ // Only one of cancel or trailer needs to be logged.
+ if len(cs.binlogs) != 0 {
+ switch err {
+ case errContextCanceled, errContextDeadline, ErrClientConnClosing:
+ c := &binarylog.Cancel{
+ OnClientSide: true,
+ }
+ for _, binlog := range cs.binlogs {
+ binlog.Log(cs.ctx, c)
+ }
+ default:
+ logEntry := &binarylog.ServerTrailer{
+ OnClientSide: true,
+ Trailer: cs.Trailer(),
+ Err: err,
+ }
+ if peer, ok := peer.FromContext(cs.Context()); ok {
+ logEntry.PeerAddr = peer.Addr
+ }
+ for _, binlog := range cs.binlogs {
+ binlog.Log(cs.ctx, logEntry)
+ }
}
}
if err == nil {
@@ -1028,7 +1034,7 @@ func (cs *clientStream) finish(err error) {
cs.cancel()
}
-func (a *csAttempt) sendMsg(m interface{}, hdr, payld, data []byte) error {
+func (a *csAttempt) sendMsg(m any, hdr, payld, data []byte) error {
cs := a.cs
if a.trInfo != nil {
a.mu.Lock()
@@ -1055,7 +1061,7 @@ func (a *csAttempt) sendMsg(m interface{}, hdr, payld, data []byte) error {
return nil
}
-func (a *csAttempt) recvMsg(m interface{}, payInfo *payloadInfo) (err error) {
+func (a *csAttempt) recvMsg(m any, payInfo *payloadInfo) (err error) {
cs := a.cs
if len(a.statsHandlers) != 0 && payInfo == nil {
payInfo = &payloadInfo{}
@@ -1270,7 +1276,7 @@ func newNonRetryClientStream(ctx context.Context, desc *StreamDesc, method strin
return nil, err
}
as.s = s
- as.p = &parser{r: s}
+ as.p = &parser{r: s, recvBufferPool: ac.dopts.recvBufferPool}
ac.incrCallsStarted()
if desc != unaryStreamDesc {
// Listen on stream context to cleanup when the stream context is
@@ -1348,7 +1354,7 @@ func (as *addrConnStream) Context() context.Context {
return as.s.Context()
}
-func (as *addrConnStream) SendMsg(m interface{}) (err error) {
+func (as *addrConnStream) SendMsg(m any) (err error) {
defer func() {
if err != nil && err != io.EOF {
// Call finish on the client stream for errors generated by this SendMsg
@@ -1393,7 +1399,7 @@ func (as *addrConnStream) SendMsg(m interface{}) (err error) {
return nil
}
-func (as *addrConnStream) RecvMsg(m interface{}) (err error) {
+func (as *addrConnStream) RecvMsg(m any) (err error) {
defer func() {
if err != nil || !as.desc.ServerStreams {
// err != nil or non-server-streaming indicates end of stream.
@@ -1512,7 +1518,7 @@ type ServerStream interface {
//
// It is not safe to modify the message after calling SendMsg. Tracing
// libraries and stats handlers may use the message lazily.
- SendMsg(m interface{}) error
+ SendMsg(m any) error
// RecvMsg blocks until it receives a message into m or the stream is
// done. It returns io.EOF when the client has performed a CloseSend. On
// any non-EOF error, the stream is aborted and the error contains the
@@ -1521,7 +1527,7 @@ type ServerStream interface {
// It is safe to have a goroutine calling SendMsg and another goroutine
// calling RecvMsg on the same stream at the same time, but it is not
// safe to call RecvMsg on the same stream in different goroutines.
- RecvMsg(m interface{}) error
+ RecvMsg(m any) error
}
// serverStream implements a server side Stream.
@@ -1602,7 +1608,7 @@ func (ss *serverStream) SetTrailer(md metadata.MD) {
ss.s.SetTrailer(md)
}
-func (ss *serverStream) SendMsg(m interface{}) (err error) {
+func (ss *serverStream) SendMsg(m any) (err error) {
defer func() {
if ss.trInfo != nil {
ss.mu.Lock()
@@ -1610,7 +1616,7 @@ func (ss *serverStream) SendMsg(m interface{}) (err error) {
if err == nil {
ss.trInfo.tr.LazyLog(&payload{sent: true, msg: m}, true)
} else {
- ss.trInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true)
+ ss.trInfo.tr.LazyLog(&fmtStringer{"%v", []any{err}}, true)
ss.trInfo.tr.SetError()
}
}
@@ -1677,7 +1683,7 @@ func (ss *serverStream) SendMsg(m interface{}) (err error) {
return nil
}
-func (ss *serverStream) RecvMsg(m interface{}) (err error) {
+func (ss *serverStream) RecvMsg(m any) (err error) {
defer func() {
if ss.trInfo != nil {
ss.mu.Lock()
@@ -1685,7 +1691,7 @@ func (ss *serverStream) RecvMsg(m interface{}) (err error) {
if err == nil {
ss.trInfo.tr.LazyLog(&payload{sent: false, msg: m}, true)
} else if err != io.EOF {
- ss.trInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true)
+ ss.trInfo.tr.LazyLog(&fmtStringer{"%v", []any{err}}, true)
ss.trInfo.tr.SetError()
}
}
@@ -1757,7 +1763,7 @@ func MethodFromServerStream(stream ServerStream) (string, bool) {
// prepareMsg returns the hdr, payload and data
// using the compressors passed or using the
// passed preparedmsg
-func prepareMsg(m interface{}, codec baseCodec, cp Compressor, comp encoding.Compressor) (hdr, payload, data []byte, err error) {
+func prepareMsg(m any, codec baseCodec, cp Compressor, comp encoding.Compressor) (hdr, payload, data []byte, err error) {
if preparedMsg, ok := m.(*PreparedMsg); ok {
return preparedMsg.hdr, preparedMsg.payload, preparedMsg.encodedData, nil
}
diff --git a/vendor/google.golang.org/grpc/tap/tap.go b/vendor/google.golang.org/grpc/tap/tap.go
index bfa5dfa4..07f01257 100644
--- a/vendor/google.golang.org/grpc/tap/tap.go
+++ b/vendor/google.golang.org/grpc/tap/tap.go
@@ -27,6 +27,8 @@ package tap
import (
"context"
+
+ "google.golang.org/grpc/metadata"
)
// Info defines the relevant information needed by the handles.
@@ -34,6 +36,10 @@ type Info struct {
// FullMethodName is the string of grpc method (in the format of
// /package.service/method).
FullMethodName string
+
+ // Header contains the header metadata received.
+ Header metadata.MD
+
// TODO: More to be added.
}
diff --git a/vendor/google.golang.org/grpc/trace.go b/vendor/google.golang.org/grpc/trace.go
index 07a2d26b..9ded7932 100644
--- a/vendor/google.golang.org/grpc/trace.go
+++ b/vendor/google.golang.org/grpc/trace.go
@@ -97,8 +97,8 @@ func truncate(x string, l int) string {
// payload represents an RPC request or response payload.
type payload struct {
- sent bool // whether this is an outgoing payload
- msg interface{} // e.g. a proto.Message
+ sent bool // whether this is an outgoing payload
+ msg any // e.g. a proto.Message
// TODO(dsymonds): add stringifying info to codec, and limit how much we hold here?
}
@@ -111,7 +111,7 @@ func (p payload) String() string {
type fmtStringer struct {
format string
- a []interface{}
+ a []any
}
func (f *fmtStringer) String() string {
diff --git a/vendor/google.golang.org/grpc/version.go b/vendor/google.golang.org/grpc/version.go
index 3cc75406..f1aec4c0 100644
--- a/vendor/google.golang.org/grpc/version.go
+++ b/vendor/google.golang.org/grpc/version.go
@@ -19,4 +19,4 @@
package grpc
// Version is the current grpc version.
-const Version = "1.56.3"
+const Version = "1.61.1"
diff --git a/vendor/google.golang.org/grpc/vet.sh b/vendor/google.golang.org/grpc/vet.sh
index a8e4732b..5da38a40 100644
--- a/vendor/google.golang.org/grpc/vet.sh
+++ b/vendor/google.golang.org/grpc/vet.sh
@@ -35,7 +35,6 @@ if [[ "$1" = "-install" ]]; then
# Install the pinned versions as defined in module tools.
pushd ./test/tools
go install \
- golang.org/x/lint/golint \
golang.org/x/tools/cmd/goimports \
honnef.co/go/tools/cmd/staticcheck \
github.com/client9/misspell/cmd/misspell
@@ -77,12 +76,19 @@ fi
not grep 'func Test[^(]' *_test.go
not grep 'func Test[^(]' test/*.go
+# - Check for typos in test function names
+git grep 'func (s) ' -- "*_test.go" | not grep -v 'func (s) Test'
+git grep 'func [A-Z]' -- "*_test.go" | not grep -v 'func Test\|Benchmark\|Example'
+
# - Do not import x/net/context.
not git grep -l 'x/net/context' -- "*.go"
# - Do not import math/rand for real library code. Use internal/grpcrand for
# thread safety.
-git grep -l '"math/rand"' -- "*.go" 2>&1 | not grep -v '^examples\|^stress\|grpcrand\|^benchmark\|wrr_test'
+git grep -l '"math/rand"' -- "*.go" 2>&1 | not grep -v '^examples\|^interop/stress\|grpcrand\|^benchmark\|wrr_test'
+
+# - Do not use "interface{}"; use "any" instead.
+git grep -l 'interface{}' -- "*.go" 2>&1 | not grep -v '\.pb\.go\|protoc-gen-go-grpc\|grpc_testing_not_regenerate'
# - Do not call grpclog directly. Use grpclog.Component instead.
git grep -l -e 'grpclog.I' --or -e 'grpclog.W' --or -e 'grpclog.E' --or -e 'grpclog.F' --or -e 'grpclog.V' -- "*.go" | not grep -v '^grpclog/component.go\|^internal/grpctest/tlogger_test.go'
@@ -90,13 +96,15 @@ git grep -l -e 'grpclog.I' --or -e 'grpclog.W' --or -e 'grpclog.E' --or -e 'grpc
# - Ensure all ptypes proto packages are renamed when importing.
not git grep "\(import \|^\s*\)\"github.com/golang/protobuf/ptypes/" -- "*.go"
+# - Ensure all usages of grpc_testing package are renamed when importing.
+not git grep "\(import \|^\s*\)\"google.golang.org/grpc/interop/grpc_testing" -- "*.go"
+
# - Ensure all xds proto imports are renamed to *pb or *grpc.
git grep '"github.com/envoyproxy/go-control-plane/envoy' -- '*.go' ':(exclude)*.pb.go' | not grep -v 'pb "\|grpc "'
misspell -error .
-# - gofmt, goimports, golint (with exceptions for generated code), go vet,
-# go mod tidy.
+# - gofmt, goimports, go vet, go mod tidy.
# Perform these checks on each module inside gRPC.
for MOD_FILE in $(find . -name 'go.mod'); do
MOD_DIR=$(dirname ${MOD_FILE})
@@ -104,105 +112,79 @@ for MOD_FILE in $(find . -name 'go.mod'); do
go vet -all ./... | fail_on_output
gofmt -s -d -l . 2>&1 | fail_on_output
goimports -l . 2>&1 | not grep -vE "\.pb\.go"
- golint ./... 2>&1 | not grep -vE "/grpc_testing_not_regenerate/.*\.pb\.go:"
- go mod tidy -compat=1.17
+ go mod tidy -compat=1.19
git status --porcelain 2>&1 | fail_on_output || \
(git status; git --no-pager diff; exit 1)
popd
done
# - Collection of static analysis checks
-#
-# TODO(dfawley): don't use deprecated functions in examples or first-party
-# plugins.
-# TODO(dfawley): enable ST1019 (duplicate imports) but allow for protobufs.
SC_OUT="$(mktemp)"
-staticcheck -go 1.19 -checks 'inherit,-ST1015,-ST1019,-SA1019' ./... > "${SC_OUT}" || true
-# Error if anything other than deprecation warnings are printed.
-not grep -v "is deprecated:.*SA1019" "${SC_OUT}"
-# Only ignore the following deprecated types/fields/functions.
-not grep -Fv '.CredsBundle
-.HeaderMap
-.Metadata is deprecated: use Attributes
-.NewAddress
-.NewServiceConfig
-.Type is deprecated: use Attributes
-BuildVersion is deprecated
-balancer.ErrTransientFailure
-balancer.Picker
-extDesc.Filename is deprecated
-github.com/golang/protobuf/jsonpb is deprecated
-grpc.CallCustomCodec
-grpc.Code
-grpc.Compressor
-grpc.CustomCodec
-grpc.Decompressor
-grpc.MaxMsgSize
-grpc.MethodConfig
-grpc.NewGZIPCompressor
-grpc.NewGZIPDecompressor
-grpc.RPCCompressor
-grpc.RPCDecompressor
-grpc.ServiceConfig
-grpc.WithCompressor
-grpc.WithDecompressor
-grpc.WithDialer
-grpc.WithMaxMsgSize
-grpc.WithServiceConfig
-grpc.WithTimeout
-http.CloseNotifier
-info.SecurityVersion
-proto is deprecated
-proto.InternalMessageInfo is deprecated
-proto.EnumName is deprecated
-proto.ErrInternalBadWireType is deprecated
-proto.FileDescriptor is deprecated
-proto.Marshaler is deprecated
-proto.MessageType is deprecated
-proto.RegisterEnum is deprecated
-proto.RegisterFile is deprecated
-proto.RegisterType is deprecated
-proto.RegisterExtension is deprecated
-proto.RegisteredExtension is deprecated
-proto.RegisteredExtensions is deprecated
-proto.RegisterMapType is deprecated
-proto.Unmarshaler is deprecated
-resolver.Backend
-resolver.GRPCLB
+staticcheck -go 1.19 -checks 'all' ./... > "${SC_OUT}" || true
+
+# Error for anything other than checks that need exclusions.
+grep -v "(ST1000)" "${SC_OUT}" | grep -v "(SA1019)" | grep -v "(ST1003)" | not grep -v "(ST1019)\|\(other import of\)"
+
+# Exclude underscore checks for generated code.
+grep "(ST1003)" "${SC_OUT}" | not grep -v '\(.pb.go:\)\|\(code_string_test.go:\)\|\(grpc_testing_not_regenerate\)'
+
+# Error for duplicate imports not including grpc protos.
+grep "(ST1019)\|\(other import of\)" "${SC_OUT}" | not grep -Fv 'XXXXX PleaseIgnoreUnused
+channelz/grpc_channelz_v1"
+go-control-plane/envoy
+grpclb/grpc_lb_v1"
+health/grpc_health_v1"
+interop/grpc_testing"
+orca/v3"
+proto/grpc_gcp"
+proto/grpc_lookup_v1"
+reflection/grpc_reflection_v1"
+reflection/grpc_reflection_v1alpha"
+XXXXX PleaseIgnoreUnused'
+
+# Error for any package comments not in generated code.
+grep "(ST1000)" "${SC_OUT}" | not grep -v "\.pb\.go:"
+
+# Only ignore the following deprecated types/fields/functions and exclude
+# generated code.
+grep "(SA1019)" "${SC_OUT}" | not grep -Fv 'XXXXX PleaseIgnoreUnused
+XXXXX Protobuf related deprecation errors:
+"github.com/golang/protobuf
+.pb.go:
+grpc_testing_not_regenerate
+: ptypes.
+proto.RegisterType
+XXXXX gRPC internal usage deprecation errors:
+"google.golang.org/grpc
+: grpc.
+: v1alpha.
+: v1alphareflectionpb.
+BalancerAttributes is deprecated:
+CredsBundle is deprecated:
+Metadata is deprecated: use Attributes instead.
+NewSubConn is deprecated:
+OverrideServerName is deprecated:
+RemoveSubConn is deprecated:
+SecurityVersion is deprecated:
Target is deprecated: Use the Target field in the BuildOptions instead.
-xxx_messageInfo_
-' "${SC_OUT}"
-
-# - special golint on package comments.
-lint_package_comment_per_package() {
- # Number of files in this go package.
- fileCount=$(go list -f '{{len .GoFiles}}' $1)
- if [ ${fileCount} -eq 0 ]; then
- return 0
- fi
- # Number of package errors generated by golint.
- lintPackageCommentErrorsCount=$(golint --min_confidence 0 $1 | grep -c "should have a package comment")
- # golint complains about every file that's missing the package comment. If the
- # number of files for this package is greater than the number of errors, there's
- # at least one file with package comment, good. Otherwise, fail.
- if [ ${fileCount} -le ${lintPackageCommentErrorsCount} ]; then
- echo "Package $1 (with ${fileCount} files) is missing package comment"
- return 1
- fi
-}
-lint_package_comment() {
- set +ex
-
- count=0
- for i in $(go list ./...); do
- lint_package_comment_per_package "$i"
- ((count += $?))
- done
-
- set -ex
- return $count
-}
-lint_package_comment
+UpdateAddresses is deprecated:
+UpdateSubConnState is deprecated:
+balancer.ErrTransientFailure is deprecated:
+grpc/reflection/v1alpha/reflection.proto
+XXXXX xDS deprecated fields we support
+.ExactMatch
+.PrefixMatch
+.SafeRegexMatch
+.SuffixMatch
+GetContainsMatch
+GetExactMatch
+GetMatchSubjectAltNames
+GetPrefixMatch
+GetSafeRegexMatch
+GetSuffixMatch
+GetTlsCertificateCertificateProviderInstance
+GetValidationContextCertificateProviderInstance
+XXXXX PleaseIgnoreUnused'
echo SUCCESS
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 96c6a0cb..462ce061 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -62,9 +62,10 @@ github.com/cyphar/filepath-securejoin
# github.com/davecgh/go-spew v1.1.1
## explicit
github.com/davecgh/go-spew/spew
-# github.com/devtron-labs/common-lib v0.0.16-0.20240318063710-69cb957d019a
+# github.com/devtron-labs/common-lib v0.0.16-0.20240418060324-b414ea7c74a3
## explicit; go 1.20
github.com/devtron-labs/common-lib/constants
+github.com/devtron-labs/common-lib/middlewares
github.com/devtron-labs/common-lib/monitoring
github.com/devtron-labs/common-lib/monitoring/pprof
github.com/devtron-labs/common-lib/monitoring/statsViz
@@ -184,8 +185,10 @@ github.com/gorilla/mux
# github.com/gorilla/websocket v1.5.0
## explicit; go 1.12
github.com/gorilla/websocket
-# github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1
+# github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0
## explicit; go 1.19
+github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors
+github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging
github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/recovery
# github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
## explicit
@@ -252,7 +255,7 @@ github.com/prometheus/common/model
github.com/prometheus/procfs
github.com/prometheus/procfs/internal/fs
github.com/prometheus/procfs/internal/util
-# github.com/robfig/cron/v3 v3.0.0
+# github.com/robfig/cron/v3 v3.0.1
## explicit; go 1.12
github.com/robfig/cron/v3
# github.com/sergi/go-diff v1.1.0
@@ -294,7 +297,7 @@ go.uber.org/zap/internal/bufferpool
go.uber.org/zap/internal/color
go.uber.org/zap/internal/exit
go.uber.org/zap/zapcore
-# golang.org/x/crypto v0.17.0
+# golang.org/x/crypto v0.19.0
## explicit; go 1.18
golang.org/x/crypto/argon2
golang.org/x/crypto/blake2b
@@ -316,10 +319,14 @@ golang.org/x/crypto/ssh
golang.org/x/crypto/ssh/agent
golang.org/x/crypto/ssh/internal/bcrypt_pbkdf
golang.org/x/crypto/ssh/knownhosts
-# golang.org/x/mod v0.12.0
-## explicit; go 1.17
+# golang.org/x/exp v0.0.0-20240222234643-814bf88cf225
+## explicit; go 1.20
+golang.org/x/exp/constraints
+golang.org/x/exp/slices
+# golang.org/x/mod v0.15.0
+## explicit; go 1.18
golang.org/x/mod/semver
-# golang.org/x/net v0.19.0
+# golang.org/x/net v0.21.0
## explicit; go 1.18
golang.org/x/net/context
golang.org/x/net/http/httpguts
@@ -330,7 +337,7 @@ golang.org/x/net/internal/socks
golang.org/x/net/internal/timeseries
golang.org/x/net/proxy
golang.org/x/net/trace
-# golang.org/x/sys v0.15.0
+# golang.org/x/sys v0.17.0
## explicit; go 1.18
golang.org/x/sys/cpu
golang.org/x/sys/execabs
@@ -342,7 +349,7 @@ golang.org/x/text/secure/bidirule
golang.org/x/text/transform
golang.org/x/text/unicode/bidi
golang.org/x/text/unicode/norm
-# golang.org/x/tools v0.13.0
+# golang.org/x/tools v0.18.0
## explicit; go 1.18
golang.org/x/tools/cmd/stringer
golang.org/x/tools/go/gcexportdata
@@ -361,11 +368,12 @@ golang.org/x/tools/internal/pkgbits
golang.org/x/tools/internal/tokeninternal
golang.org/x/tools/internal/typeparams
golang.org/x/tools/internal/typesinternal
-# google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19
+golang.org/x/tools/internal/versions
+# google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9
## explicit; go 1.19
google.golang.org/genproto/googleapis/rpc/status
-# google.golang.org/grpc v1.56.3
-## explicit; go 1.17
+# google.golang.org/grpc v1.61.1
+## explicit; go 1.19
google.golang.org/grpc
google.golang.org/grpc/attributes
google.golang.org/grpc/backoff
@@ -395,10 +403,12 @@ google.golang.org/grpc/internal/grpclog
google.golang.org/grpc/internal/grpcrand
google.golang.org/grpc/internal/grpcsync
google.golang.org/grpc/internal/grpcutil
+google.golang.org/grpc/internal/idle
google.golang.org/grpc/internal/metadata
google.golang.org/grpc/internal/pretty
google.golang.org/grpc/internal/resolver
google.golang.org/grpc/internal/resolver/dns
+google.golang.org/grpc/internal/resolver/dns/internal
google.golang.org/grpc/internal/resolver/passthrough
google.golang.org/grpc/internal/resolver/unix
google.golang.org/grpc/internal/serviceconfig
@@ -410,6 +420,7 @@ google.golang.org/grpc/keepalive
google.golang.org/grpc/metadata
google.golang.org/grpc/peer
google.golang.org/grpc/resolver
+google.golang.org/grpc/resolver/dns
google.golang.org/grpc/serviceconfig
google.golang.org/grpc/stats
google.golang.org/grpc/status
diff --git a/wire_gen.go b/wire_gen.go
index c7b7edf5..c50f59b8 100644
--- a/wire_gen.go
+++ b/wire_gen.go
@@ -59,6 +59,9 @@ func InitializeApp() (*app.App, error) {
monitoringRouter := monitoring.NewMonitoringRouter(sugaredLogger)
muxRouter := api.NewMuxRouter(sugaredLogger, restHandlerImpl, monitoringRouter)
grpcHandlerImpl := api.NewGrpcHandlerImpl(repoManagerImpl, sugaredLogger)
- appApp := app.NewApp(muxRouter, sugaredLogger, gitWatcherImpl, db, pubSubClientServiceImpl, grpcHandlerImpl)
+ appApp, err := app.NewApp(muxRouter, sugaredLogger, gitWatcherImpl, db, pubSubClientServiceImpl, grpcHandlerImpl)
+ if err != nil {
+ return nil, err
+ }
return appApp, nil
}