mirror of https://github.com/knative/caching.git
upgrade (#506)
This commit is contained in:
parent
6947bb32bc
commit
4e553d2275
2
go.mod
2
go.mod
|
@ -19,5 +19,5 @@ require (
|
|||
k8s.io/code-generator v0.20.7
|
||||
k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd
|
||||
knative.dev/hack v0.0.0-20210622141627-e28525d8d260
|
||||
knative.dev/pkg v0.0.0-20210731072840-64ab22bbaab9
|
||||
knative.dev/pkg v0.0.0-20210803160015-21eb4c167cc5
|
||||
)
|
||||
|
|
37
go.sum
37
go.sum
|
@ -113,6 +113,7 @@ github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4
|
|||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
|
@ -155,7 +156,7 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
|
|||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
|
||||
github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses=
|
||||
|
@ -289,8 +290,8 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4
|
|||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I=
|
||||
|
@ -309,8 +310,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf
|
|||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.14.8 h1:hXClj+iFpmLM8i3lkO6i4Psli4P2qObQuQReiII26U8=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.14.8/go.mod h1:NZE8t6vs6TnwLL/ITkaK8W3ecMLGAbh2jXTclvpiwYo=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
|
@ -599,12 +600,13 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
|||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.8.0 h1:CUhrE4N1rqSE6FM9ecihEjRkLQu8cDfgDyoOs83mEY4=
|
||||
go.uber.org/atomic v1.8.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q=
|
||||
go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
|
||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
|
@ -710,8 +712,8 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY
|
|||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 h1:4CSI6oo7cOjJKajidEljs9h+uP0rRZBPPPhcCbj5mw8=
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -870,8 +872,8 @@ golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4f
|
|||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.4 h1:cVngSRcfgyZCzys3KYOpCFa+4dqX/Oub9tAq00ttGVs=
|
||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
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=
|
||||
|
@ -969,10 +971,12 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji
|
|||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.39.0 h1:Klz8I9kdtkIN6EpHHUOMLCYhTn/2WAe5a0s1hcBkdTI=
|
||||
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
@ -984,8 +988,9 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
|
|||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
@ -1057,8 +1062,8 @@ k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g
|
|||
k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
knative.dev/hack v0.0.0-20210622141627-e28525d8d260 h1:f2eMtOubAOc/Q7JlvFPDKXiPlJVK+VpX2Cot8hRzCgQ=
|
||||
knative.dev/hack v0.0.0-20210622141627-e28525d8d260/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
|
||||
knative.dev/pkg v0.0.0-20210731072840-64ab22bbaab9 h1:eeRutJPRJ6tR7LVkeaD7H2BaKeKwadHaR66+Z1QRVcs=
|
||||
knative.dev/pkg v0.0.0-20210731072840-64ab22bbaab9/go.mod h1:NYZRIPU+Pv39VfbZV1BtMIe4kCavNle1udsPrvOLm+Y=
|
||||
knative.dev/pkg v0.0.0-20210803160015-21eb4c167cc5 h1:jpOTmAXg1oLS8u5HPBrFP1XsOSFCQIvlTRxP8TDGg2E=
|
||||
knative.dev/pkg v0.0.0-20210803160015-21eb4c167cc5/go.mod h1:RPk5txNA3apR9X40D4MpUOP9/VqOG8CrtABWfOwGVS4=
|
||||
pgregory.net/rapid v0.3.3/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
// Copyright 2021 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var jsonNull = []byte("null")
|
||||
|
||||
// NullUUID represents a UUID that may be null.
|
||||
// NullUUID implements the SQL driver.Scanner interface so
|
||||
// it can be used as a scan destination:
|
||||
//
|
||||
// var u uuid.NullUUID
|
||||
// err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&u)
|
||||
// ...
|
||||
// if u.Valid {
|
||||
// // use u.UUID
|
||||
// } else {
|
||||
// // NULL value
|
||||
// }
|
||||
//
|
||||
type NullUUID struct {
|
||||
UUID UUID
|
||||
Valid bool // Valid is true if UUID is not NULL
|
||||
}
|
||||
|
||||
// Scan implements the SQL driver.Scanner interface.
|
||||
func (nu *NullUUID) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
nu.UUID, nu.Valid = Nil, false
|
||||
return nil
|
||||
}
|
||||
|
||||
err := nu.UUID.Scan(value)
|
||||
if err != nil {
|
||||
nu.Valid = false
|
||||
return err
|
||||
}
|
||||
|
||||
nu.Valid = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (nu NullUUID) Value() (driver.Value, error) {
|
||||
if !nu.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
// Delegate to UUID Value function
|
||||
return nu.UUID.Value()
|
||||
}
|
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler.
|
||||
func (nu NullUUID) MarshalBinary() ([]byte, error) {
|
||||
if nu.Valid {
|
||||
return nu.UUID[:], nil
|
||||
}
|
||||
|
||||
return []byte(nil), nil
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
|
||||
func (nu *NullUUID) UnmarshalBinary(data []byte) error {
|
||||
if len(data) != 16 {
|
||||
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
|
||||
}
|
||||
copy(nu.UUID[:], data)
|
||||
nu.Valid = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalText implements encoding.TextMarshaler.
|
||||
func (nu NullUUID) MarshalText() ([]byte, error) {
|
||||
if nu.Valid {
|
||||
return nu.UUID.MarshalText()
|
||||
}
|
||||
|
||||
return jsonNull, nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||
func (nu *NullUUID) UnmarshalText(data []byte) error {
|
||||
id, err := ParseBytes(data)
|
||||
if err != nil {
|
||||
nu.Valid = false
|
||||
return err
|
||||
}
|
||||
nu.UUID = id
|
||||
nu.Valid = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements json.Marshaler.
|
||||
func (nu NullUUID) MarshalJSON() ([]byte, error) {
|
||||
if nu.Valid {
|
||||
return json.Marshal(nu.UUID)
|
||||
}
|
||||
|
||||
return jsonNull, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler.
|
||||
func (nu *NullUUID) UnmarshalJSON(data []byte) error {
|
||||
if bytes.Equal(data, jsonNull) {
|
||||
*nu = NullUUID{}
|
||||
return nil // valid null UUID
|
||||
}
|
||||
err := json.Unmarshal(data, &nu.UUID)
|
||||
nu.Valid = err == nil
|
||||
return err
|
||||
}
|
|
@ -12,6 +12,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
|
||||
|
@ -33,7 +34,15 @@ const (
|
|||
Future // Reserved for future definition.
|
||||
)
|
||||
|
||||
var rander = rand.Reader // random function
|
||||
const randPoolSize = 16 * 16
|
||||
|
||||
var (
|
||||
rander = rand.Reader // random function
|
||||
poolEnabled = false
|
||||
poolMu sync.Mutex
|
||||
poolPos = randPoolSize // protected with poolMu
|
||||
pool [randPoolSize]byte // protected with poolMu
|
||||
)
|
||||
|
||||
type invalidLengthError struct{ len int }
|
||||
|
||||
|
@ -41,6 +50,12 @@ func (err invalidLengthError) Error() string {
|
|||
return fmt.Sprintf("invalid UUID length: %d", err.len)
|
||||
}
|
||||
|
||||
// IsInvalidLengthError is matcher function for custom error invalidLengthError
|
||||
func IsInvalidLengthError(err error) bool {
|
||||
_, ok := err.(invalidLengthError)
|
||||
return ok
|
||||
}
|
||||
|
||||
// Parse decodes s into a UUID or returns an error. Both the standard UUID
|
||||
// forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded as well as the
|
||||
|
@ -249,3 +264,31 @@ func SetRand(r io.Reader) {
|
|||
}
|
||||
rander = r
|
||||
}
|
||||
|
||||
// EnableRandPool enables internal randomness pool used for Random
|
||||
// (Version 4) UUID generation. The pool contains random bytes read from
|
||||
// the random number generator on demand in batches. Enabling the pool
|
||||
// may improve the UUID generation throughput significantly.
|
||||
//
|
||||
// Since the pool is stored on the Go heap, this feature may be a bad fit
|
||||
// for security sensitive applications.
|
||||
//
|
||||
// Both EnableRandPool and DisableRandPool are not thread-safe and should
|
||||
// only be called when there is no possibility that New or any other
|
||||
// UUID Version 4 generation function will be called concurrently.
|
||||
func EnableRandPool() {
|
||||
poolEnabled = true
|
||||
}
|
||||
|
||||
// DisableRandPool disables the randomness pool if it was previously
|
||||
// enabled with EnableRandPool.
|
||||
//
|
||||
// Both EnableRandPool and DisableRandPool are not thread-safe and should
|
||||
// only be called when there is no possibility that New or any other
|
||||
// UUID Version 4 generation function will be called concurrently.
|
||||
func DisableRandPool() {
|
||||
poolEnabled = false
|
||||
defer poolMu.Unlock()
|
||||
poolMu.Lock()
|
||||
poolPos = randPoolSize
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@ func NewString() string {
|
|||
// The strength of the UUIDs is based on the strength of the crypto/rand
|
||||
// package.
|
||||
//
|
||||
// Uses the randomness pool if it was enabled with EnableRandPool.
|
||||
//
|
||||
// A note about uniqueness derived from the UUID Wikipedia entry:
|
||||
//
|
||||
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
|
||||
|
@ -35,7 +37,10 @@ func NewString() string {
|
|||
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
|
||||
// year and having one duplicate.
|
||||
func NewRandom() (UUID, error) {
|
||||
return NewRandomFromReader(rander)
|
||||
if !poolEnabled {
|
||||
return NewRandomFromReader(rander)
|
||||
}
|
||||
return newRandomFromPool()
|
||||
}
|
||||
|
||||
// NewRandomFromReader returns a UUID based on bytes read from a given io.Reader.
|
||||
|
@ -49,3 +54,23 @@ func NewRandomFromReader(r io.Reader) (UUID, error) {
|
|||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
|
||||
return uuid, nil
|
||||
}
|
||||
|
||||
func newRandomFromPool() (UUID, error) {
|
||||
var uuid UUID
|
||||
poolMu.Lock()
|
||||
if poolPos == randPoolSize {
|
||||
_, err := io.ReadFull(rander, pool[:])
|
||||
if err != nil {
|
||||
poolMu.Unlock()
|
||||
return Nil, err
|
||||
}
|
||||
poolPos = 0
|
||||
}
|
||||
copy(uuid[:], pool[poolPos:(poolPos+16)])
|
||||
poolPos += 16
|
||||
poolMu.Unlock()
|
||||
|
||||
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
|
||||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
|
||||
return uuid, nil
|
||||
}
|
||||
|
|
|
@ -4,11 +4,20 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.9.0] - 2021-07-15
|
||||
### Added
|
||||
- Add `Float64.Swap` to match int atomic operations.
|
||||
- Add `atomic.Time` type for atomic operations on `time.Time` values.
|
||||
|
||||
[1.9.0]: https://github.com/uber-go/atomic/compare/v1.8.0...v1.9.0
|
||||
|
||||
## [1.8.0] - 2021-06-09
|
||||
### Added
|
||||
- Add `atomic.Uintptr` type for atomic operations on `uintptr` values.
|
||||
- Add `atomic.UnsafePointer` type for atomic operations on `unsafe.Pointer` values.
|
||||
|
||||
[1.8.0]: https://github.com/uber-go/atomic/compare/v1.7.0...v1.8.0
|
||||
|
||||
## [1.7.0] - 2020-09-14
|
||||
### Added
|
||||
- Support JSON serialization and deserialization of primitive atomic types.
|
||||
|
@ -20,32 +29,46 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
### Removed
|
||||
- Remove dependency on `golang.org/x/{lint, tools}`.
|
||||
|
||||
[1.7.0]: https://github.com/uber-go/atomic/compare/v1.6.0...v1.7.0
|
||||
|
||||
## [1.6.0] - 2020-02-24
|
||||
### Changed
|
||||
- Drop library dependency on `golang.org/x/{lint, tools}`.
|
||||
|
||||
[1.6.0]: https://github.com/uber-go/atomic/compare/v1.5.1...v1.6.0
|
||||
|
||||
## [1.5.1] - 2019-11-19
|
||||
- Fix bug where `Bool.CAS` and `Bool.Toggle` do work correctly together
|
||||
causing `CAS` to fail even though the old value matches.
|
||||
|
||||
[1.5.1]: https://github.com/uber-go/atomic/compare/v1.5.0...v1.5.1
|
||||
|
||||
## [1.5.0] - 2019-10-29
|
||||
### Changed
|
||||
- With Go modules, only the `go.uber.org/atomic` import path is supported now.
|
||||
If you need to use the old import path, please add a `replace` directive to
|
||||
your `go.mod`.
|
||||
|
||||
[1.5.0]: https://github.com/uber-go/atomic/compare/v1.4.0...v1.5.0
|
||||
|
||||
## [1.4.0] - 2019-05-01
|
||||
### Added
|
||||
- Add `atomic.Error` type for atomic operations on `error` values.
|
||||
|
||||
[1.4.0]: https://github.com/uber-go/atomic/compare/v1.3.2...v1.4.0
|
||||
|
||||
## [1.3.2] - 2018-05-02
|
||||
### Added
|
||||
- Add `atomic.Duration` type for atomic operations on `time.Duration` values.
|
||||
|
||||
[1.3.2]: https://github.com/uber-go/atomic/compare/v1.3.1...v1.3.2
|
||||
|
||||
## [1.3.1] - 2017-11-14
|
||||
### Fixed
|
||||
- Revert optimization for `atomic.String.Store("")` which caused data races.
|
||||
|
||||
[1.3.1]: https://github.com/uber-go/atomic/compare/v1.3.0...v1.3.1
|
||||
|
||||
## [1.3.0] - 2017-11-13
|
||||
### Added
|
||||
- Add `atomic.Bool.CAS` for compare-and-swap semantics on bools.
|
||||
|
@ -53,10 +76,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
### Changed
|
||||
- Optimize `atomic.String.Store("")` by avoiding an allocation.
|
||||
|
||||
[1.3.0]: https://github.com/uber-go/atomic/compare/v1.2.0...v1.3.0
|
||||
|
||||
## [1.2.0] - 2017-04-12
|
||||
### Added
|
||||
- Shadow `atomic.Value` from `sync/atomic`.
|
||||
|
||||
[1.2.0]: https://github.com/uber-go/atomic/compare/v1.1.0...v1.2.0
|
||||
|
||||
## [1.1.0] - 2017-03-10
|
||||
### Added
|
||||
- Add atomic `Float64` type.
|
||||
|
@ -64,19 +91,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
### Changed
|
||||
- Support new `go.uber.org/atomic` import path.
|
||||
|
||||
[1.1.0]: https://github.com/uber-go/atomic/compare/v1.0.0...v1.1.0
|
||||
|
||||
## [1.0.0] - 2016-07-18
|
||||
|
||||
- Initial release.
|
||||
|
||||
[1.8.0]: https://github.com/uber-go/atomic/compare/v1.7.0...v1.8.0
|
||||
[1.7.0]: https://github.com/uber-go/atomic/compare/v1.6.0...v1.7.0
|
||||
[1.6.0]: https://github.com/uber-go/atomic/compare/v1.5.1...v1.6.0
|
||||
[1.5.1]: https://github.com/uber-go/atomic/compare/v1.5.0...v1.5.1
|
||||
[1.5.0]: https://github.com/uber-go/atomic/compare/v1.4.0...v1.5.0
|
||||
[1.4.0]: https://github.com/uber-go/atomic/compare/v1.3.2...v1.4.0
|
||||
[1.3.2]: https://github.com/uber-go/atomic/compare/v1.3.1...v1.3.2
|
||||
[1.3.1]: https://github.com/uber-go/atomic/compare/v1.3.0...v1.3.1
|
||||
[1.3.0]: https://github.com/uber-go/atomic/compare/v1.2.0...v1.3.0
|
||||
[1.2.0]: https://github.com/uber-go/atomic/compare/v1.1.0...v1.2.0
|
||||
[1.1.0]: https://github.com/uber-go/atomic/compare/v1.0.0...v1.1.0
|
||||
[1.0.0]: https://github.com/uber-go/atomic/releases/tag/v1.0.0
|
||||
|
|
|
@ -36,10 +36,10 @@ type Bool struct {
|
|||
var _zeroBool bool
|
||||
|
||||
// NewBool creates a new Bool.
|
||||
func NewBool(v bool) *Bool {
|
||||
func NewBool(val bool) *Bool {
|
||||
x := &Bool{}
|
||||
if v != _zeroBool {
|
||||
x.Store(v)
|
||||
if val != _zeroBool {
|
||||
x.Store(val)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
@ -50,19 +50,19 @@ func (x *Bool) Load() bool {
|
|||
}
|
||||
|
||||
// Store atomically stores the passed bool.
|
||||
func (x *Bool) Store(v bool) {
|
||||
x.v.Store(boolToInt(v))
|
||||
func (x *Bool) Store(val bool) {
|
||||
x.v.Store(boolToInt(val))
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap for bool values.
|
||||
func (x *Bool) CAS(o, n bool) bool {
|
||||
return x.v.CAS(boolToInt(o), boolToInt(n))
|
||||
func (x *Bool) CAS(old, new bool) (swapped bool) {
|
||||
return x.v.CAS(boolToInt(old), boolToInt(new))
|
||||
}
|
||||
|
||||
// Swap atomically stores the given bool and returns the old
|
||||
// value.
|
||||
func (x *Bool) Swap(o bool) bool {
|
||||
return truthy(x.v.Swap(boolToInt(o)))
|
||||
func (x *Bool) Swap(val bool) (old bool) {
|
||||
return truthy(x.v.Swap(boolToInt(val)))
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the wrapped bool into JSON.
|
||||
|
|
|
@ -38,7 +38,7 @@ func boolToInt(b bool) uint32 {
|
|||
}
|
||||
|
||||
// Toggle atomically negates the Boolean and returns the previous value.
|
||||
func (b *Bool) Toggle() bool {
|
||||
func (b *Bool) Toggle() (old bool) {
|
||||
for {
|
||||
old := b.Load()
|
||||
if b.CAS(old, !old) {
|
||||
|
|
|
@ -37,10 +37,10 @@ type Duration struct {
|
|||
var _zeroDuration time.Duration
|
||||
|
||||
// NewDuration creates a new Duration.
|
||||
func NewDuration(v time.Duration) *Duration {
|
||||
func NewDuration(val time.Duration) *Duration {
|
||||
x := &Duration{}
|
||||
if v != _zeroDuration {
|
||||
x.Store(v)
|
||||
if val != _zeroDuration {
|
||||
x.Store(val)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
@ -51,19 +51,19 @@ func (x *Duration) Load() time.Duration {
|
|||
}
|
||||
|
||||
// Store atomically stores the passed time.Duration.
|
||||
func (x *Duration) Store(v time.Duration) {
|
||||
x.v.Store(int64(v))
|
||||
func (x *Duration) Store(val time.Duration) {
|
||||
x.v.Store(int64(val))
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap for time.Duration values.
|
||||
func (x *Duration) CAS(o, n time.Duration) bool {
|
||||
return x.v.CAS(int64(o), int64(n))
|
||||
func (x *Duration) CAS(old, new time.Duration) (swapped bool) {
|
||||
return x.v.CAS(int64(old), int64(new))
|
||||
}
|
||||
|
||||
// Swap atomically stores the given time.Duration and returns the old
|
||||
// value.
|
||||
func (x *Duration) Swap(o time.Duration) time.Duration {
|
||||
return time.Duration(x.v.Swap(int64(o)))
|
||||
func (x *Duration) Swap(val time.Duration) (old time.Duration) {
|
||||
return time.Duration(x.v.Swap(int64(val)))
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the wrapped time.Duration into JSON.
|
||||
|
|
|
@ -25,13 +25,13 @@ import "time"
|
|||
//go:generate bin/gen-atomicwrapper -name=Duration -type=time.Duration -wrapped=Int64 -pack=int64 -unpack=time.Duration -cas -swap -json -imports time -file=duration.go
|
||||
|
||||
// Add atomically adds to the wrapped time.Duration and returns the new value.
|
||||
func (d *Duration) Add(n time.Duration) time.Duration {
|
||||
return time.Duration(d.v.Add(int64(n)))
|
||||
func (d *Duration) Add(delta time.Duration) time.Duration {
|
||||
return time.Duration(d.v.Add(int64(delta)))
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped time.Duration and returns the new value.
|
||||
func (d *Duration) Sub(n time.Duration) time.Duration {
|
||||
return time.Duration(d.v.Sub(int64(n)))
|
||||
func (d *Duration) Sub(delta time.Duration) time.Duration {
|
||||
return time.Duration(d.v.Sub(int64(delta)))
|
||||
}
|
||||
|
||||
// String encodes the wrapped value as a string.
|
||||
|
|
|
@ -32,10 +32,10 @@ type Error struct {
|
|||
var _zeroError error
|
||||
|
||||
// NewError creates a new Error.
|
||||
func NewError(v error) *Error {
|
||||
func NewError(val error) *Error {
|
||||
x := &Error{}
|
||||
if v != _zeroError {
|
||||
x.Store(v)
|
||||
if val != _zeroError {
|
||||
x.Store(val)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
@ -46,6 +46,6 @@ func (x *Error) Load() error {
|
|||
}
|
||||
|
||||
// Store atomically stores the passed error.
|
||||
func (x *Error) Store(v error) {
|
||||
x.v.Store(packError(v))
|
||||
func (x *Error) Store(val error) {
|
||||
x.v.Store(packError(val))
|
||||
}
|
||||
|
|
|
@ -37,10 +37,10 @@ type Float64 struct {
|
|||
var _zeroFloat64 float64
|
||||
|
||||
// NewFloat64 creates a new Float64.
|
||||
func NewFloat64(v float64) *Float64 {
|
||||
func NewFloat64(val float64) *Float64 {
|
||||
x := &Float64{}
|
||||
if v != _zeroFloat64 {
|
||||
x.Store(v)
|
||||
if val != _zeroFloat64 {
|
||||
x.Store(val)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
@ -51,13 +51,14 @@ func (x *Float64) Load() float64 {
|
|||
}
|
||||
|
||||
// Store atomically stores the passed float64.
|
||||
func (x *Float64) Store(v float64) {
|
||||
x.v.Store(math.Float64bits(v))
|
||||
func (x *Float64) Store(val float64) {
|
||||
x.v.Store(math.Float64bits(val))
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap for float64 values.
|
||||
func (x *Float64) CAS(o, n float64) bool {
|
||||
return x.v.CAS(math.Float64bits(o), math.Float64bits(n))
|
||||
// Swap atomically stores the given float64 and returns the old
|
||||
// value.
|
||||
func (x *Float64) Swap(val float64) (old float64) {
|
||||
return math.Float64frombits(x.v.Swap(math.Float64bits(val)))
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the wrapped float64 into JSON.
|
||||
|
|
|
@ -20,15 +20,18 @@
|
|||
|
||||
package atomic
|
||||
|
||||
import "strconv"
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
//go:generate bin/gen-atomicwrapper -name=Float64 -type=float64 -wrapped=Uint64 -pack=math.Float64bits -unpack=math.Float64frombits -cas -json -imports math -file=float64.go
|
||||
//go:generate bin/gen-atomicwrapper -name=Float64 -type=float64 -wrapped=Uint64 -pack=math.Float64bits -unpack=math.Float64frombits -swap -json -imports math -file=float64.go
|
||||
|
||||
// Add atomically adds to the wrapped float64 and returns the new value.
|
||||
func (f *Float64) Add(s float64) float64 {
|
||||
func (f *Float64) Add(delta float64) float64 {
|
||||
for {
|
||||
old := f.Load()
|
||||
new := old + s
|
||||
new := old + delta
|
||||
if f.CAS(old, new) {
|
||||
return new
|
||||
}
|
||||
|
@ -36,8 +39,27 @@ func (f *Float64) Add(s float64) float64 {
|
|||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped float64 and returns the new value.
|
||||
func (f *Float64) Sub(s float64) float64 {
|
||||
return f.Add(-s)
|
||||
func (f *Float64) Sub(delta float64) float64 {
|
||||
return f.Add(-delta)
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap for float64 values.
|
||||
//
|
||||
// Note: CAS handles NaN incorrectly. NaN != NaN using Go's inbuilt operators
|
||||
// but CAS allows a stored NaN to compare equal to a passed in NaN.
|
||||
// This avoids typical CAS loops from blocking forever, e.g.,
|
||||
//
|
||||
// for {
|
||||
// old := atom.Load()
|
||||
// new = f(old)
|
||||
// if atom.CAS(old, new) {
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// If CAS did not match NaN to match, then the above would loop forever.
|
||||
func (f *Float64) CAS(old, new float64) (swapped bool) {
|
||||
return f.v.CAS(math.Float64bits(old), math.Float64bits(new))
|
||||
}
|
||||
|
||||
// String encodes the wrapped value as a string.
|
||||
|
|
|
@ -36,8 +36,8 @@ type Int32 struct {
|
|||
}
|
||||
|
||||
// NewInt32 creates a new Int32.
|
||||
func NewInt32(i int32) *Int32 {
|
||||
return &Int32{v: i}
|
||||
func NewInt32(val int32) *Int32 {
|
||||
return &Int32{v: val}
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped value.
|
||||
|
@ -46,13 +46,13 @@ func (i *Int32) Load() int32 {
|
|||
}
|
||||
|
||||
// Add atomically adds to the wrapped int32 and returns the new value.
|
||||
func (i *Int32) Add(n int32) int32 {
|
||||
return atomic.AddInt32(&i.v, n)
|
||||
func (i *Int32) Add(delta int32) int32 {
|
||||
return atomic.AddInt32(&i.v, delta)
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped int32 and returns the new value.
|
||||
func (i *Int32) Sub(n int32) int32 {
|
||||
return atomic.AddInt32(&i.v, -n)
|
||||
func (i *Int32) Sub(delta int32) int32 {
|
||||
return atomic.AddInt32(&i.v, -delta)
|
||||
}
|
||||
|
||||
// Inc atomically increments the wrapped int32 and returns the new value.
|
||||
|
@ -66,18 +66,18 @@ func (i *Int32) Dec() int32 {
|
|||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (i *Int32) CAS(old, new int32) bool {
|
||||
func (i *Int32) CAS(old, new int32) (swapped bool) {
|
||||
return atomic.CompareAndSwapInt32(&i.v, old, new)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (i *Int32) Store(n int32) {
|
||||
atomic.StoreInt32(&i.v, n)
|
||||
func (i *Int32) Store(val int32) {
|
||||
atomic.StoreInt32(&i.v, val)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped int32 and returns the old value.
|
||||
func (i *Int32) Swap(n int32) int32 {
|
||||
return atomic.SwapInt32(&i.v, n)
|
||||
func (i *Int32) Swap(val int32) (old int32) {
|
||||
return atomic.SwapInt32(&i.v, val)
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the wrapped int32 into JSON.
|
||||
|
|
|
@ -36,8 +36,8 @@ type Int64 struct {
|
|||
}
|
||||
|
||||
// NewInt64 creates a new Int64.
|
||||
func NewInt64(i int64) *Int64 {
|
||||
return &Int64{v: i}
|
||||
func NewInt64(val int64) *Int64 {
|
||||
return &Int64{v: val}
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped value.
|
||||
|
@ -46,13 +46,13 @@ func (i *Int64) Load() int64 {
|
|||
}
|
||||
|
||||
// Add atomically adds to the wrapped int64 and returns the new value.
|
||||
func (i *Int64) Add(n int64) int64 {
|
||||
return atomic.AddInt64(&i.v, n)
|
||||
func (i *Int64) Add(delta int64) int64 {
|
||||
return atomic.AddInt64(&i.v, delta)
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped int64 and returns the new value.
|
||||
func (i *Int64) Sub(n int64) int64 {
|
||||
return atomic.AddInt64(&i.v, -n)
|
||||
func (i *Int64) Sub(delta int64) int64 {
|
||||
return atomic.AddInt64(&i.v, -delta)
|
||||
}
|
||||
|
||||
// Inc atomically increments the wrapped int64 and returns the new value.
|
||||
|
@ -66,18 +66,18 @@ func (i *Int64) Dec() int64 {
|
|||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (i *Int64) CAS(old, new int64) bool {
|
||||
func (i *Int64) CAS(old, new int64) (swapped bool) {
|
||||
return atomic.CompareAndSwapInt64(&i.v, old, new)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (i *Int64) Store(n int64) {
|
||||
atomic.StoreInt64(&i.v, n)
|
||||
func (i *Int64) Store(val int64) {
|
||||
atomic.StoreInt64(&i.v, val)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped int64 and returns the old value.
|
||||
func (i *Int64) Swap(n int64) int64 {
|
||||
return atomic.SwapInt64(&i.v, n)
|
||||
func (i *Int64) Swap(val int64) (old int64) {
|
||||
return atomic.SwapInt64(&i.v, val)
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the wrapped int64 into JSON.
|
||||
|
|
|
@ -32,10 +32,10 @@ type String struct {
|
|||
var _zeroString string
|
||||
|
||||
// NewString creates a new String.
|
||||
func NewString(v string) *String {
|
||||
func NewString(val string) *String {
|
||||
x := &String{}
|
||||
if v != _zeroString {
|
||||
x.Store(v)
|
||||
if val != _zeroString {
|
||||
x.Store(val)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
@ -49,6 +49,6 @@ func (x *String) Load() string {
|
|||
}
|
||||
|
||||
// Store atomically stores the passed string.
|
||||
func (x *String) Store(v string) {
|
||||
x.v.Store(v)
|
||||
func (x *String) Store(val string) {
|
||||
x.v.Store(val)
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
package atomic
|
||||
|
||||
//go:generate bin/gen-atomicwrapper -name=String -type=string -wrapped=Value -file=string.go
|
||||
// Note: No Swap as String wraps Value, which wraps the stdlib sync/atomic.Value which
|
||||
// only supports Swap as of go1.17: https://github.com/golang/go/issues/39351
|
||||
|
||||
// String returns the wrapped value.
|
||||
func (s *String) String() string {
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
// @generated Code generated by gen-atomicwrapper.
|
||||
|
||||
// Copyright (c) 2020-2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Time is an atomic type-safe wrapper for time.Time values.
|
||||
type Time struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v Value
|
||||
}
|
||||
|
||||
var _zeroTime time.Time
|
||||
|
||||
// NewTime creates a new Time.
|
||||
func NewTime(val time.Time) *Time {
|
||||
x := &Time{}
|
||||
if val != _zeroTime {
|
||||
x.Store(val)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped time.Time.
|
||||
func (x *Time) Load() time.Time {
|
||||
return unpackTime(x.v.Load())
|
||||
}
|
||||
|
||||
// Store atomically stores the passed time.Time.
|
||||
func (x *Time) Store(val time.Time) {
|
||||
x.v.Store(packTime(val))
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) 2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import "time"
|
||||
|
||||
//go:generate bin/gen-atomicwrapper -name=Time -type=time.Time -wrapped=Value -pack=packTime -unpack=unpackTime -imports time -file=time.go
|
||||
|
||||
func packTime(t time.Time) interface{} {
|
||||
return t
|
||||
}
|
||||
|
||||
func unpackTime(v interface{}) time.Time {
|
||||
if t, ok := v.(time.Time); ok {
|
||||
return t
|
||||
}
|
||||
return time.Time{}
|
||||
}
|
|
@ -36,8 +36,8 @@ type Uint32 struct {
|
|||
}
|
||||
|
||||
// NewUint32 creates a new Uint32.
|
||||
func NewUint32(i uint32) *Uint32 {
|
||||
return &Uint32{v: i}
|
||||
func NewUint32(val uint32) *Uint32 {
|
||||
return &Uint32{v: val}
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped value.
|
||||
|
@ -46,13 +46,13 @@ func (i *Uint32) Load() uint32 {
|
|||
}
|
||||
|
||||
// Add atomically adds to the wrapped uint32 and returns the new value.
|
||||
func (i *Uint32) Add(n uint32) uint32 {
|
||||
return atomic.AddUint32(&i.v, n)
|
||||
func (i *Uint32) Add(delta uint32) uint32 {
|
||||
return atomic.AddUint32(&i.v, delta)
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped uint32 and returns the new value.
|
||||
func (i *Uint32) Sub(n uint32) uint32 {
|
||||
return atomic.AddUint32(&i.v, ^(n - 1))
|
||||
func (i *Uint32) Sub(delta uint32) uint32 {
|
||||
return atomic.AddUint32(&i.v, ^(delta - 1))
|
||||
}
|
||||
|
||||
// Inc atomically increments the wrapped uint32 and returns the new value.
|
||||
|
@ -66,18 +66,18 @@ func (i *Uint32) Dec() uint32 {
|
|||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (i *Uint32) CAS(old, new uint32) bool {
|
||||
func (i *Uint32) CAS(old, new uint32) (swapped bool) {
|
||||
return atomic.CompareAndSwapUint32(&i.v, old, new)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (i *Uint32) Store(n uint32) {
|
||||
atomic.StoreUint32(&i.v, n)
|
||||
func (i *Uint32) Store(val uint32) {
|
||||
atomic.StoreUint32(&i.v, val)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped uint32 and returns the old value.
|
||||
func (i *Uint32) Swap(n uint32) uint32 {
|
||||
return atomic.SwapUint32(&i.v, n)
|
||||
func (i *Uint32) Swap(val uint32) (old uint32) {
|
||||
return atomic.SwapUint32(&i.v, val)
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the wrapped uint32 into JSON.
|
||||
|
|
|
@ -36,8 +36,8 @@ type Uint64 struct {
|
|||
}
|
||||
|
||||
// NewUint64 creates a new Uint64.
|
||||
func NewUint64(i uint64) *Uint64 {
|
||||
return &Uint64{v: i}
|
||||
func NewUint64(val uint64) *Uint64 {
|
||||
return &Uint64{v: val}
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped value.
|
||||
|
@ -46,13 +46,13 @@ func (i *Uint64) Load() uint64 {
|
|||
}
|
||||
|
||||
// Add atomically adds to the wrapped uint64 and returns the new value.
|
||||
func (i *Uint64) Add(n uint64) uint64 {
|
||||
return atomic.AddUint64(&i.v, n)
|
||||
func (i *Uint64) Add(delta uint64) uint64 {
|
||||
return atomic.AddUint64(&i.v, delta)
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped uint64 and returns the new value.
|
||||
func (i *Uint64) Sub(n uint64) uint64 {
|
||||
return atomic.AddUint64(&i.v, ^(n - 1))
|
||||
func (i *Uint64) Sub(delta uint64) uint64 {
|
||||
return atomic.AddUint64(&i.v, ^(delta - 1))
|
||||
}
|
||||
|
||||
// Inc atomically increments the wrapped uint64 and returns the new value.
|
||||
|
@ -66,18 +66,18 @@ func (i *Uint64) Dec() uint64 {
|
|||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (i *Uint64) CAS(old, new uint64) bool {
|
||||
func (i *Uint64) CAS(old, new uint64) (swapped bool) {
|
||||
return atomic.CompareAndSwapUint64(&i.v, old, new)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (i *Uint64) Store(n uint64) {
|
||||
atomic.StoreUint64(&i.v, n)
|
||||
func (i *Uint64) Store(val uint64) {
|
||||
atomic.StoreUint64(&i.v, val)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped uint64 and returns the old value.
|
||||
func (i *Uint64) Swap(n uint64) uint64 {
|
||||
return atomic.SwapUint64(&i.v, n)
|
||||
func (i *Uint64) Swap(val uint64) (old uint64) {
|
||||
return atomic.SwapUint64(&i.v, val)
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the wrapped uint64 into JSON.
|
||||
|
|
|
@ -36,8 +36,8 @@ type Uintptr struct {
|
|||
}
|
||||
|
||||
// NewUintptr creates a new Uintptr.
|
||||
func NewUintptr(i uintptr) *Uintptr {
|
||||
return &Uintptr{v: i}
|
||||
func NewUintptr(val uintptr) *Uintptr {
|
||||
return &Uintptr{v: val}
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped value.
|
||||
|
@ -46,13 +46,13 @@ func (i *Uintptr) Load() uintptr {
|
|||
}
|
||||
|
||||
// Add atomically adds to the wrapped uintptr and returns the new value.
|
||||
func (i *Uintptr) Add(n uintptr) uintptr {
|
||||
return atomic.AddUintptr(&i.v, n)
|
||||
func (i *Uintptr) Add(delta uintptr) uintptr {
|
||||
return atomic.AddUintptr(&i.v, delta)
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped uintptr and returns the new value.
|
||||
func (i *Uintptr) Sub(n uintptr) uintptr {
|
||||
return atomic.AddUintptr(&i.v, ^(n - 1))
|
||||
func (i *Uintptr) Sub(delta uintptr) uintptr {
|
||||
return atomic.AddUintptr(&i.v, ^(delta - 1))
|
||||
}
|
||||
|
||||
// Inc atomically increments the wrapped uintptr and returns the new value.
|
||||
|
@ -66,18 +66,18 @@ func (i *Uintptr) Dec() uintptr {
|
|||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (i *Uintptr) CAS(old, new uintptr) bool {
|
||||
func (i *Uintptr) CAS(old, new uintptr) (swapped bool) {
|
||||
return atomic.CompareAndSwapUintptr(&i.v, old, new)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (i *Uintptr) Store(n uintptr) {
|
||||
atomic.StoreUintptr(&i.v, n)
|
||||
func (i *Uintptr) Store(val uintptr) {
|
||||
atomic.StoreUintptr(&i.v, val)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped uintptr and returns the old value.
|
||||
func (i *Uintptr) Swap(n uintptr) uintptr {
|
||||
return atomic.SwapUintptr(&i.v, n)
|
||||
func (i *Uintptr) Swap(val uintptr) (old uintptr) {
|
||||
return atomic.SwapUintptr(&i.v, val)
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the wrapped uintptr into JSON.
|
||||
|
|
|
@ -33,8 +33,8 @@ type UnsafePointer struct {
|
|||
}
|
||||
|
||||
// NewUnsafePointer creates a new UnsafePointer.
|
||||
func NewUnsafePointer(p unsafe.Pointer) *UnsafePointer {
|
||||
return &UnsafePointer{v: p}
|
||||
func NewUnsafePointer(val unsafe.Pointer) *UnsafePointer {
|
||||
return &UnsafePointer{v: val}
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped value.
|
||||
|
@ -43,16 +43,16 @@ func (p *UnsafePointer) Load() unsafe.Pointer {
|
|||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (p *UnsafePointer) Store(q unsafe.Pointer) {
|
||||
atomic.StorePointer(&p.v, q)
|
||||
func (p *UnsafePointer) Store(val unsafe.Pointer) {
|
||||
atomic.StorePointer(&p.v, val)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped unsafe.Pointer and returns the old value.
|
||||
func (p *UnsafePointer) Swap(q unsafe.Pointer) unsafe.Pointer {
|
||||
return atomic.SwapPointer(&p.v, q)
|
||||
func (p *UnsafePointer) Swap(val unsafe.Pointer) (old unsafe.Pointer) {
|
||||
return atomic.SwapPointer(&p.v, val)
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (p *UnsafePointer) CAS(old, new unsafe.Pointer) bool {
|
||||
func (p *UnsafePointer) CAS(old, new unsafe.Pointer) (swapped bool) {
|
||||
return atomic.CompareAndSwapPointer(&p.v, old, new)
|
||||
}
|
||||
|
|
|
@ -338,7 +338,7 @@ func (w *settingsAckSwallowWriter) Write(p []byte) (int, error) {
|
|||
}
|
||||
fSize := fh.Length + 9
|
||||
if uint32(len(w.buf)) < fSize {
|
||||
// Have not collected whole frame. Stop processing buf, and withold on
|
||||
// Have not collected whole frame. Stop processing buf, and withhold on
|
||||
// forward bytes to w.Writer until we get the full frame.
|
||||
break
|
||||
}
|
||||
|
|
|
@ -816,7 +816,7 @@ func (sc *serverConn) serve() {
|
|||
})
|
||||
sc.unackedSettings++
|
||||
|
||||
// Each connection starts with intialWindowSize inflow tokens.
|
||||
// Each connection starts with initialWindowSize inflow tokens.
|
||||
// If a higher value is configured, we add more tokens.
|
||||
if diff := sc.srv.initialConnRecvWindowSize() - initialWindowSize; diff > 0 {
|
||||
sc.sendWindowUpdate(nil, int(diff))
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
language: go
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- go: 1.14.x
|
||||
env: VET=1 GO111MODULE=on
|
||||
- go: 1.14.x
|
||||
env: RACE=1 GO111MODULE=on
|
||||
- go: 1.14.x
|
||||
env: RUN386=1
|
||||
- go: 1.14.x
|
||||
env: GRPC_GO_RETRY=on
|
||||
- go: 1.14.x
|
||||
env: TESTEXTRAS=1
|
||||
- go: 1.13.x
|
||||
env: GO111MODULE=on
|
||||
- go: 1.12.x
|
||||
env: GO111MODULE=on
|
||||
- go: 1.11.x # Keep until interop tests no longer require Go1.11
|
||||
env: GO111MODULE=on
|
||||
|
||||
go_import_path: google.golang.org/grpc
|
||||
|
||||
before_install:
|
||||
- if [[ "${GO111MODULE}" = "on" ]]; then mkdir "${HOME}/go"; export GOPATH="${HOME}/go"; fi
|
||||
- if [[ -n "${RUN386}" ]]; then export GOARCH=386; fi
|
||||
- if [[ "${TRAVIS_EVENT_TYPE}" = "cron" && -z "${RUN386}" ]]; then RACE=1; fi
|
||||
- if [[ "${TRAVIS_EVENT_TYPE}" != "cron" ]]; then export VET_SKIP_PROTO=1; fi
|
||||
|
||||
install:
|
||||
- try3() { eval "$*" || eval "$*" || eval "$*"; }
|
||||
- try3 'if [[ "${GO111MODULE}" = "on" ]]; then go mod download; else make testdeps; fi'
|
||||
- if [[ -n "${GAE}" ]]; then source ./install_gae.sh; make testappenginedeps; fi
|
||||
- if [[ -n "${VET}" ]]; then ./vet.sh -install; fi
|
||||
|
||||
script:
|
||||
- set -e
|
||||
- if [[ -n "${TESTEXTRAS}" ]]; then examples/examples_test.sh; security/advancedtls/examples/examples_test.sh; interop/interop_test.sh; make testsubmodule; exit 0; fi
|
||||
- if [[ -n "${VET}" ]]; then ./vet.sh; fi
|
||||
- if [[ -n "${GAE}" ]]; then make testappengine; exit 0; fi
|
||||
- if [[ -n "${RACE}" ]]; then make testrace; exit 0; fi
|
||||
- make test
|
|
@ -136,6 +136,6 @@ errors.
|
|||
[Go module]: https://github.com/golang/go/wiki/Modules
|
||||
[gRPC]: https://grpc.io
|
||||
[Go gRPC docs]: https://grpc.io/docs/languages/go
|
||||
[Performance benchmark]: https://performance-dot-grpc-testing.appspot.com/explore?dashboard=5652536396611584&widget=490377658&container=1286539696
|
||||
[Performance benchmark]: https://performance-dot-grpc-testing.appspot.com/explore?dashboard=5180705743044608
|
||||
[quick start]: https://grpc.io/docs/languages/go/quickstart
|
||||
[go-releases]: https://golang.org/doc/devel/release.html
|
||||
|
|
|
@ -43,7 +43,8 @@ type ccBalancerWrapper struct {
|
|||
cc *ClientConn
|
||||
balancerMu sync.Mutex // synchronizes calls to the balancer
|
||||
balancer balancer.Balancer
|
||||
scBuffer *buffer.Unbounded
|
||||
updateCh *buffer.Unbounded
|
||||
closed *grpcsync.Event
|
||||
done *grpcsync.Event
|
||||
|
||||
mu sync.Mutex
|
||||
|
@ -53,7 +54,8 @@ type ccBalancerWrapper struct {
|
|||
func newCCBalancerWrapper(cc *ClientConn, b balancer.Builder, bopts balancer.BuildOptions) *ccBalancerWrapper {
|
||||
ccb := &ccBalancerWrapper{
|
||||
cc: cc,
|
||||
scBuffer: buffer.NewUnbounded(),
|
||||
updateCh: buffer.NewUnbounded(),
|
||||
closed: grpcsync.NewEvent(),
|
||||
done: grpcsync.NewEvent(),
|
||||
subConns: make(map[*acBalancerWrapper]struct{}),
|
||||
}
|
||||
|
@ -67,35 +69,53 @@ func newCCBalancerWrapper(cc *ClientConn, b balancer.Builder, bopts balancer.Bui
|
|||
func (ccb *ccBalancerWrapper) watcher() {
|
||||
for {
|
||||
select {
|
||||
case t := <-ccb.scBuffer.Get():
|
||||
ccb.scBuffer.Load()
|
||||
if ccb.done.HasFired() {
|
||||
case t := <-ccb.updateCh.Get():
|
||||
ccb.updateCh.Load()
|
||||
if ccb.closed.HasFired() {
|
||||
break
|
||||
}
|
||||
ccb.balancerMu.Lock()
|
||||
su := t.(*scStateUpdate)
|
||||
ccb.balancer.UpdateSubConnState(su.sc, balancer.SubConnState{ConnectivityState: su.state, ConnectionError: su.err})
|
||||
ccb.balancerMu.Unlock()
|
||||
case <-ccb.done.Done():
|
||||
switch u := t.(type) {
|
||||
case *scStateUpdate:
|
||||
ccb.balancerMu.Lock()
|
||||
ccb.balancer.UpdateSubConnState(u.sc, balancer.SubConnState{ConnectivityState: u.state, ConnectionError: u.err})
|
||||
ccb.balancerMu.Unlock()
|
||||
case *acBalancerWrapper:
|
||||
ccb.mu.Lock()
|
||||
if ccb.subConns != nil {
|
||||
delete(ccb.subConns, u)
|
||||
ccb.cc.removeAddrConn(u.getAddrConn(), errConnDrain)
|
||||
}
|
||||
ccb.mu.Unlock()
|
||||
default:
|
||||
logger.Errorf("ccBalancerWrapper.watcher: unknown update %+v, type %T", t, t)
|
||||
}
|
||||
case <-ccb.closed.Done():
|
||||
}
|
||||
|
||||
if ccb.done.HasFired() {
|
||||
if ccb.closed.HasFired() {
|
||||
ccb.balancerMu.Lock()
|
||||
ccb.balancer.Close()
|
||||
ccb.balancerMu.Unlock()
|
||||
ccb.mu.Lock()
|
||||
scs := ccb.subConns
|
||||
ccb.subConns = nil
|
||||
ccb.mu.Unlock()
|
||||
ccb.UpdateState(balancer.State{ConnectivityState: connectivity.Connecting, Picker: nil})
|
||||
ccb.done.Fire()
|
||||
// Fire done before removing the addr conns. We can safely unblock
|
||||
// ccb.close and allow the removeAddrConns to happen
|
||||
// asynchronously.
|
||||
for acbw := range scs {
|
||||
ccb.cc.removeAddrConn(acbw.getAddrConn(), errConnDrain)
|
||||
}
|
||||
ccb.UpdateState(balancer.State{ConnectivityState: connectivity.Connecting, Picker: nil})
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ccb *ccBalancerWrapper) close() {
|
||||
ccb.done.Fire()
|
||||
ccb.closed.Fire()
|
||||
<-ccb.done.Done()
|
||||
}
|
||||
|
||||
func (ccb *ccBalancerWrapper) handleSubConnStateChange(sc balancer.SubConn, s connectivity.State, err error) {
|
||||
|
@ -109,7 +129,7 @@ func (ccb *ccBalancerWrapper) handleSubConnStateChange(sc balancer.SubConn, s co
|
|||
if sc == nil {
|
||||
return
|
||||
}
|
||||
ccb.scBuffer.Put(&scStateUpdate{
|
||||
ccb.updateCh.Put(&scStateUpdate{
|
||||
sc: sc,
|
||||
state: s,
|
||||
err: err,
|
||||
|
@ -150,17 +170,10 @@ func (ccb *ccBalancerWrapper) NewSubConn(addrs []resolver.Address, opts balancer
|
|||
}
|
||||
|
||||
func (ccb *ccBalancerWrapper) RemoveSubConn(sc balancer.SubConn) {
|
||||
acbw, ok := sc.(*acBalancerWrapper)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
ccb.mu.Lock()
|
||||
defer ccb.mu.Unlock()
|
||||
if ccb.subConns == nil {
|
||||
return
|
||||
}
|
||||
delete(ccb.subConns, acbw)
|
||||
ccb.cc.removeAddrConn(acbw.getAddrConn(), errConnDrain)
|
||||
// The RemoveSubConn() is handled in the run() goroutine, to avoid deadlock
|
||||
// during switchBalancer() if the old balancer calls RemoveSubConn() in its
|
||||
// Close().
|
||||
ccb.updateCh.Put(sc)
|
||||
}
|
||||
|
||||
func (ccb *ccBalancerWrapper) UpdateAddresses(sc balancer.SubConn, addrs []resolver.Address) {
|
||||
|
|
|
@ -711,7 +711,12 @@ func (cc *ClientConn) switchBalancer(name string) {
|
|||
return
|
||||
}
|
||||
if cc.balancerWrapper != nil {
|
||||
// Don't hold cc.mu while closing the balancers. The balancers may call
|
||||
// methods that require cc.mu (e.g. cc.NewSubConn()). Holding the mutex
|
||||
// would cause a deadlock in that case.
|
||||
cc.mu.Unlock()
|
||||
cc.balancerWrapper.close()
|
||||
cc.mu.Lock()
|
||||
}
|
||||
|
||||
builder := balancer.Get(name)
|
||||
|
@ -1046,12 +1051,12 @@ func (cc *ClientConn) Close() error {
|
|||
|
||||
cc.blockingpicker.close()
|
||||
|
||||
if rWrapper != nil {
|
||||
rWrapper.close()
|
||||
}
|
||||
if bWrapper != nil {
|
||||
bWrapper.close()
|
||||
}
|
||||
if rWrapper != nil {
|
||||
rWrapper.close()
|
||||
}
|
||||
|
||||
for ac := range conns {
|
||||
ac.tearDown(ErrClientConnClosing)
|
||||
|
|
|
@ -4,14 +4,14 @@ go 1.11
|
|||
|
||||
require (
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
|
||||
github.com/golang/protobuf v1.4.2
|
||||
github.com/golang/protobuf v1.4.3
|
||||
github.com/google/go-cmp v0.5.0
|
||||
github.com/google/uuid v1.1.2
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013
|
||||
google.golang.org/protobuf v1.25.0
|
||||
)
|
||||
|
|
|
@ -1,32 +1,42 @@
|
|||
cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403 h1:cqQfy1jclcSy/FwLjemeg3SR1yaINm74aQyupQ0Bl8M=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed h1:OZmjad4L3H8ncOIR8rnb5MREYqG8ixi5+WbeUsquF0c=
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d h1:QyzYnTnPE15SQyUeqU6qLbWxMkwyAyu+vGksa0b7j00=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0 h1:dulLQAYQFYtG5MTplgNGHWuV2D+OBD+Z8lmDBmbLg+s=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
|
@ -35,49 +45,64 @@ github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
|
|||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
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/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
|
||||
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=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
@ -90,7 +115,8 @@ google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4
|
|||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3 h1:fvjTMHxHEw/mxHbtzPi3JCcKXQRAnQTBRo6YCJSVHKI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
|
|
@ -31,26 +31,30 @@ var (
|
|||
mu sync.Mutex
|
||||
)
|
||||
|
||||
// Int implements rand.Int on the grpcrand global source.
|
||||
func Int() int {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
return r.Int()
|
||||
}
|
||||
|
||||
// Int63n implements rand.Int63n on the grpcrand global source.
|
||||
func Int63n(n int64) int64 {
|
||||
mu.Lock()
|
||||
res := r.Int63n(n)
|
||||
mu.Unlock()
|
||||
return res
|
||||
defer mu.Unlock()
|
||||
return r.Int63n(n)
|
||||
}
|
||||
|
||||
// Intn implements rand.Intn on the grpcrand global source.
|
||||
func Intn(n int) int {
|
||||
mu.Lock()
|
||||
res := r.Intn(n)
|
||||
mu.Unlock()
|
||||
return res
|
||||
defer mu.Unlock()
|
||||
return r.Intn(n)
|
||||
}
|
||||
|
||||
// Float64 implements rand.Float64 on the grpcrand global source.
|
||||
func Float64() float64 {
|
||||
mu.Lock()
|
||||
res := r.Float64()
|
||||
mu.Unlock()
|
||||
return res
|
||||
defer mu.Unlock()
|
||||
return r.Float64()
|
||||
}
|
||||
|
|
|
@ -296,7 +296,7 @@ type controlBuffer struct {
|
|||
// closed and nilled when transportResponseFrames drops below the
|
||||
// threshold. Both fields are protected by mu.
|
||||
transportResponseFrames int
|
||||
trfChan atomic.Value // *chan struct{}
|
||||
trfChan atomic.Value // chan struct{}
|
||||
}
|
||||
|
||||
func newControlBuffer(done <-chan struct{}) *controlBuffer {
|
||||
|
@ -310,10 +310,10 @@ func newControlBuffer(done <-chan struct{}) *controlBuffer {
|
|||
// throttle blocks if there are too many incomingSettings/cleanupStreams in the
|
||||
// controlbuf.
|
||||
func (c *controlBuffer) throttle() {
|
||||
ch, _ := c.trfChan.Load().(*chan struct{})
|
||||
ch, _ := c.trfChan.Load().(chan struct{})
|
||||
if ch != nil {
|
||||
select {
|
||||
case <-*ch:
|
||||
case <-ch:
|
||||
case <-c.done:
|
||||
}
|
||||
}
|
||||
|
@ -347,8 +347,7 @@ func (c *controlBuffer) executeAndPut(f func(it interface{}) bool, it cbItem) (b
|
|||
if c.transportResponseFrames == maxQueuedTransportResponseFrames {
|
||||
// We are adding the frame that puts us over the threshold; create
|
||||
// a throttling channel.
|
||||
ch := make(chan struct{})
|
||||
c.trfChan.Store(&ch)
|
||||
c.trfChan.Store(make(chan struct{}))
|
||||
}
|
||||
}
|
||||
c.mu.Unlock()
|
||||
|
@ -389,9 +388,9 @@ func (c *controlBuffer) get(block bool) (interface{}, error) {
|
|||
if c.transportResponseFrames == maxQueuedTransportResponseFrames {
|
||||
// We are removing the frame that put us over the
|
||||
// threshold; close and clear the throttling channel.
|
||||
ch := c.trfChan.Load().(*chan struct{})
|
||||
close(*ch)
|
||||
c.trfChan.Store((*chan struct{})(nil))
|
||||
ch := c.trfChan.Load().(chan struct{})
|
||||
close(ch)
|
||||
c.trfChan.Store((chan struct{})(nil))
|
||||
}
|
||||
c.transportResponseFrames--
|
||||
}
|
||||
|
@ -407,7 +406,6 @@ func (c *controlBuffer) get(block bool) (interface{}, error) {
|
|||
select {
|
||||
case <-c.ch:
|
||||
case <-c.done:
|
||||
c.finish()
|
||||
return nil, ErrConnClosing
|
||||
}
|
||||
}
|
||||
|
@ -432,6 +430,14 @@ func (c *controlBuffer) finish() {
|
|||
hdr.onOrphaned(ErrConnClosing)
|
||||
}
|
||||
}
|
||||
// In case throttle() is currently in flight, it needs to be unblocked.
|
||||
// Otherwise, the transport may not close, since the transport is closed by
|
||||
// the reader encountering the connection error.
|
||||
ch, _ := c.trfChan.Load().(chan struct{})
|
||||
if ch != nil {
|
||||
close(ch)
|
||||
}
|
||||
c.trfChan.Store((chan struct{})(nil))
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
|
|
|
@ -141,9 +141,8 @@ type serverHandlerTransport struct {
|
|||
stats stats.Handler
|
||||
}
|
||||
|
||||
func (ht *serverHandlerTransport) Close() error {
|
||||
func (ht *serverHandlerTransport) Close() {
|
||||
ht.closeOnce.Do(ht.closeCloseChanOnce)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ht *serverHandlerTransport) closeCloseChanOnce() { close(ht.closedCh) }
|
||||
|
|
|
@ -399,11 +399,10 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts
|
|||
logger.Errorf("transport: loopyWriter.run returning. Err: %v", err)
|
||||
}
|
||||
}
|
||||
// If it's a connection error, let reader goroutine handle it
|
||||
// since there might be data in the buffers.
|
||||
if _, ok := err.(net.Error); !ok {
|
||||
t.conn.Close()
|
||||
}
|
||||
// Do not close the transport. Let reader goroutine handle it since
|
||||
// there might be data in the buffers.
|
||||
t.conn.Close()
|
||||
t.controlBuf.finish()
|
||||
close(t.writerDone)
|
||||
}()
|
||||
return t, nil
|
||||
|
@ -878,12 +877,18 @@ func (t *http2Client) Close(err error) {
|
|||
// Append info about previous goaways if there were any, since this may be important
|
||||
// for understanding the root cause for this connection to be closed.
|
||||
_, goAwayDebugMessage := t.GetGoAwayReason()
|
||||
|
||||
var st *status.Status
|
||||
if len(goAwayDebugMessage) > 0 {
|
||||
err = fmt.Errorf("closing transport due to: %v, received prior goaway: %v", err, goAwayDebugMessage)
|
||||
st = status.Newf(codes.Unavailable, "closing transport due to: %v, received prior goaway: %v", err, goAwayDebugMessage)
|
||||
err = st.Err()
|
||||
} else {
|
||||
st = status.New(codes.Unavailable, err.Error())
|
||||
}
|
||||
|
||||
// Notify all active streams.
|
||||
for _, s := range streams {
|
||||
t.closeStream(s, err, false, http2.ErrCodeNo, status.New(codes.Unavailable, err.Error()), nil, false)
|
||||
t.closeStream(s, err, false, http2.ErrCodeNo, st, nil, false)
|
||||
}
|
||||
if t.statsHandler != nil {
|
||||
connEnd := &stats.ConnEnd{
|
||||
|
@ -1254,11 +1259,97 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
|
|||
return
|
||||
}
|
||||
|
||||
state := &decodeState{}
|
||||
// Initialize isGRPC value to be !initialHeader, since if a gRPC Response-Headers has already been received, then it means that the peer is speaking gRPC and we are in gRPC mode.
|
||||
state.data.isGRPC = !initialHeader
|
||||
if h2code, err := state.decodeHeader(frame); err != nil {
|
||||
t.closeStream(s, err, true, h2code, status.Convert(err), nil, endStream)
|
||||
// frame.Truncated is set to true when framer detects that the current header
|
||||
// list size hits MaxHeaderListSize limit.
|
||||
if frame.Truncated {
|
||||
se := status.New(codes.Internal, "peer header list size exceeded limit")
|
||||
t.closeStream(s, se.Err(), true, http2.ErrCodeFrameSize, se, nil, endStream)
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
// If a gRPC Response-Headers has already been received, then it means
|
||||
// that the peer is speaking gRPC and we are in gRPC mode.
|
||||
isGRPC = !initialHeader
|
||||
mdata = make(map[string][]string)
|
||||
contentTypeErr string
|
||||
grpcMessage string
|
||||
statusGen *status.Status
|
||||
|
||||
httpStatus string
|
||||
rawStatus string
|
||||
// headerError is set if an error is encountered while parsing the headers
|
||||
headerError string
|
||||
)
|
||||
|
||||
for _, hf := range frame.Fields {
|
||||
switch hf.Name {
|
||||
case "content-type":
|
||||
if _, validContentType := grpcutil.ContentSubtype(hf.Value); !validContentType {
|
||||
contentTypeErr = fmt.Sprintf("transport: received the unexpected content-type %q", hf.Value)
|
||||
break
|
||||
}
|
||||
mdata[hf.Name] = append(mdata[hf.Name], hf.Value)
|
||||
isGRPC = true
|
||||
case "grpc-encoding":
|
||||
s.recvCompress = hf.Value
|
||||
case "grpc-status":
|
||||
rawStatus = hf.Value
|
||||
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":
|
||||
httpStatus = hf.Value
|
||||
default:
|
||||
if isReservedHeader(hf.Name) && !isWhitelistedHeader(hf.Name) {
|
||||
break
|
||||
}
|
||||
v, err := decodeMetadataHeader(hf.Name, hf.Value)
|
||||
if err != nil {
|
||||
headerError = fmt.Sprintf("transport: malformed %s: %v", hf.Name, err)
|
||||
logger.Warningf("Failed to decode metadata header (%q, %q): %v", hf.Name, hf.Value, err)
|
||||
break
|
||||
}
|
||||
mdata[hf.Name] = append(mdata[hf.Name], v)
|
||||
}
|
||||
}
|
||||
|
||||
if !isGRPC {
|
||||
var (
|
||||
code = codes.Internal // when header does not include HTTP status, return INTERNAL
|
||||
httpStatusCode int
|
||||
)
|
||||
|
||||
if httpStatus != "" {
|
||||
c, err := strconv.ParseInt(httpStatus, 10, 32)
|
||||
if err != nil {
|
||||
se := status.New(codes.Internal, fmt.Sprintf("transport: malformed http-status: %v", err))
|
||||
t.closeStream(s, se.Err(), true, http2.ErrCodeProtocol, se, nil, endStream)
|
||||
return
|
||||
}
|
||||
httpStatusCode = int(c)
|
||||
|
||||
var ok bool
|
||||
code, ok = HTTPStatusConvTab[httpStatusCode]
|
||||
if !ok {
|
||||
code = codes.Unknown
|
||||
}
|
||||
}
|
||||
|
||||
// Verify the HTTP response is a 200.
|
||||
se := status.New(code, constructHTTPErrMsg(&httpStatusCode, contentTypeErr))
|
||||
t.closeStream(s, se.Err(), true, http2.ErrCodeProtocol, se, nil, endStream)
|
||||
return
|
||||
}
|
||||
|
||||
if headerError != "" {
|
||||
se := status.New(codes.Internal, headerError)
|
||||
t.closeStream(s, se.Err(), true, http2.ErrCodeProtocol, se, nil, endStream)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1293,9 +1384,8 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
|
|||
// 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.
|
||||
s.recvCompress = state.data.encoding
|
||||
if len(state.data.mdata) > 0 {
|
||||
s.header = state.data.mdata
|
||||
if len(mdata) > 0 {
|
||||
s.header = mdata
|
||||
}
|
||||
} else {
|
||||
// HEADERS frame block carries a Trailers-Only.
|
||||
|
@ -1308,9 +1398,23 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
|
|||
return
|
||||
}
|
||||
|
||||
if statusGen == nil {
|
||||
rawStatusCode := codes.Unknown
|
||||
if rawStatus != "" {
|
||||
code, err := strconv.ParseInt(rawStatus, 10, 32)
|
||||
if err != nil {
|
||||
se := status.New(codes.Internal, fmt.Sprintf("transport: malformed grpc-status: %v", err))
|
||||
t.closeStream(s, se.Err(), true, http2.ErrCodeProtocol, se, nil, endStream)
|
||||
return
|
||||
}
|
||||
rawStatusCode = codes.Code(uint32(code))
|
||||
}
|
||||
statusGen = status.New(rawStatusCode, grpcMessage)
|
||||
}
|
||||
|
||||
// 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, state.status(), state.data.mdata, true)
|
||||
t.closeStream(s, io.EOF, rst, http2.ErrCodeNo, statusGen, mdata, true)
|
||||
}
|
||||
|
||||
// reader runs as a separate goroutine in charge of reading data from network
|
||||
|
|
|
@ -102,11 +102,11 @@ type http2Server struct {
|
|||
|
||||
mu sync.Mutex // guard the following
|
||||
|
||||
// drainChan is initialized when drain(...) is called the first time.
|
||||
// drainChan is initialized when Drain() is called the first time.
|
||||
// After which the server writes out the first GoAway(with ID 2^31-1) frame.
|
||||
// Then an independent goroutine will be launched to later send the second GoAway.
|
||||
// During this time we don't want to write another first GoAway(with ID 2^31 -1) frame.
|
||||
// Thus call to drain(...) will be a no-op if drainChan is already initialized since draining is
|
||||
// Thus call to Drain() will be a no-op if drainChan is already initialized since draining is
|
||||
// already underway.
|
||||
drainChan chan struct{}
|
||||
state transportState
|
||||
|
@ -125,9 +125,14 @@ type http2Server struct {
|
|||
connectionID uint64
|
||||
}
|
||||
|
||||
// newHTTP2Server constructs a ServerTransport based on HTTP2. ConnectionError is
|
||||
// returned if something goes wrong.
|
||||
func newHTTP2Server(conn net.Conn, config *ServerConfig) (_ ServerTransport, err error) {
|
||||
// NewServerTransport creates a http2 transport with conn and configuration
|
||||
// options from config.
|
||||
//
|
||||
// It returns a non-nil transport and a nil error on success. On failure, it
|
||||
// returns a non-nil transport and a nil-error. For a special case where the
|
||||
// underlying conn gets closed before the client preface could be read, it
|
||||
// returns a nil transport and a nil error.
|
||||
func NewServerTransport(conn net.Conn, config *ServerConfig) (_ ServerTransport, err error) {
|
||||
writeBufSize := config.WriteBufferSize
|
||||
readBufSize := config.ReadBufferSize
|
||||
maxHeaderListSize := defaultServerMaxHeaderListSize
|
||||
|
@ -266,6 +271,13 @@ func newHTTP2Server(conn net.Conn, config *ServerConfig) (_ ServerTransport, err
|
|||
// Check the validity of client preface.
|
||||
preface := make([]byte, len(clientPreface))
|
||||
if _, err := io.ReadFull(t.conn, preface); err != nil {
|
||||
// In deployments where a gRPC server runs behind a cloud load balancer
|
||||
// which performs regular TCP level health checks, the connection is
|
||||
// closed immediately by the latter. Skipping the error here will help
|
||||
// reduce log clutter.
|
||||
if err == io.EOF {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, connectionErrorf(false, err, "transport: http2Server.HandleStreams failed to receive the preface from client: %v", err)
|
||||
}
|
||||
if !bytes.Equal(preface, clientPreface) {
|
||||
|
@ -295,6 +307,7 @@ func newHTTP2Server(conn net.Conn, config *ServerConfig) (_ ServerTransport, err
|
|||
}
|
||||
}
|
||||
t.conn.Close()
|
||||
t.controlBuf.finish()
|
||||
close(t.writerDone)
|
||||
}()
|
||||
go t.keepalive()
|
||||
|
@ -304,37 +317,92 @@ func newHTTP2Server(conn net.Conn, config *ServerConfig) (_ ServerTransport, err
|
|||
// operateHeader takes action on the decoded headers.
|
||||
func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(*Stream), traceCtx func(context.Context, string) context.Context) (fatal bool) {
|
||||
streamID := frame.Header().StreamID
|
||||
state := &decodeState{
|
||||
serverSide: true,
|
||||
}
|
||||
if h2code, err := state.decodeHeader(frame); err != nil {
|
||||
if _, ok := status.FromError(err); ok {
|
||||
t.controlBuf.put(&cleanupStream{
|
||||
streamID: streamID,
|
||||
rst: true,
|
||||
rstCode: h2code,
|
||||
onWrite: func() {},
|
||||
})
|
||||
}
|
||||
|
||||
// frame.Truncated is set to true when framer detects that the current header
|
||||
// list size hits MaxHeaderListSize limit.
|
||||
if frame.Truncated {
|
||||
t.controlBuf.put(&cleanupStream{
|
||||
streamID: streamID,
|
||||
rst: true,
|
||||
rstCode: http2.ErrCodeFrameSize,
|
||||
onWrite: func() {},
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
buf := newRecvBuffer()
|
||||
s := &Stream{
|
||||
id: streamID,
|
||||
st: t,
|
||||
buf: buf,
|
||||
fc: &inFlow{limit: uint32(t.initialWindowSize)},
|
||||
recvCompress: state.data.encoding,
|
||||
method: state.data.method,
|
||||
contentSubtype: state.data.contentSubtype,
|
||||
id: streamID,
|
||||
st: t,
|
||||
buf: buf,
|
||||
fc: &inFlow{limit: uint32(t.initialWindowSize)},
|
||||
}
|
||||
|
||||
var (
|
||||
// If a gRPC Response-Headers has already been received, then it means
|
||||
// that the peer is speaking gRPC and we are in gRPC mode.
|
||||
isGRPC = false
|
||||
mdata = make(map[string][]string)
|
||||
httpMethod string
|
||||
// headerError is set if an error is encountered while parsing the headers
|
||||
headerError bool
|
||||
|
||||
timeoutSet bool
|
||||
timeout time.Duration
|
||||
)
|
||||
|
||||
for _, hf := range frame.Fields {
|
||||
switch hf.Name {
|
||||
case "content-type":
|
||||
contentSubtype, validContentType := grpcutil.ContentSubtype(hf.Value)
|
||||
if !validContentType {
|
||||
break
|
||||
}
|
||||
mdata[hf.Name] = append(mdata[hf.Name], hf.Value)
|
||||
s.contentSubtype = contentSubtype
|
||||
isGRPC = true
|
||||
case "grpc-encoding":
|
||||
s.recvCompress = hf.Value
|
||||
case ":method":
|
||||
httpMethod = hf.Value
|
||||
case ":path":
|
||||
s.method = hf.Value
|
||||
case "grpc-timeout":
|
||||
timeoutSet = true
|
||||
var err error
|
||||
if timeout, err = decodeTimeout(hf.Value); err != nil {
|
||||
headerError = true
|
||||
}
|
||||
default:
|
||||
if isReservedHeader(hf.Name) && !isWhitelistedHeader(hf.Name) {
|
||||
break
|
||||
}
|
||||
v, err := decodeMetadataHeader(hf.Name, hf.Value)
|
||||
if err != nil {
|
||||
headerError = true
|
||||
logger.Warningf("Failed to decode metadata header (%q, %q): %v", hf.Name, hf.Value, err)
|
||||
break
|
||||
}
|
||||
mdata[hf.Name] = append(mdata[hf.Name], v)
|
||||
}
|
||||
}
|
||||
|
||||
if !isGRPC || headerError {
|
||||
t.controlBuf.put(&cleanupStream{
|
||||
streamID: streamID,
|
||||
rst: true,
|
||||
rstCode: http2.ErrCodeProtocol,
|
||||
onWrite: func() {},
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
if frame.StreamEnded() {
|
||||
// s is just created by the caller. No lock needed.
|
||||
s.state = streamReadDone
|
||||
}
|
||||
if state.data.timeoutSet {
|
||||
s.ctx, s.cancel = context.WithTimeout(t.ctx, state.data.timeout)
|
||||
if timeoutSet {
|
||||
s.ctx, s.cancel = context.WithTimeout(t.ctx, timeout)
|
||||
} else {
|
||||
s.ctx, s.cancel = context.WithCancel(t.ctx)
|
||||
}
|
||||
|
@ -347,14 +415,14 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(
|
|||
}
|
||||
s.ctx = peer.NewContext(s.ctx, pr)
|
||||
// Attach the received metadata to the context.
|
||||
if len(state.data.mdata) > 0 {
|
||||
s.ctx = metadata.NewIncomingContext(s.ctx, state.data.mdata)
|
||||
}
|
||||
if state.data.statsTags != nil {
|
||||
s.ctx = stats.SetIncomingTags(s.ctx, state.data.statsTags)
|
||||
}
|
||||
if state.data.statsTrace != nil {
|
||||
s.ctx = stats.SetIncomingTrace(s.ctx, state.data.statsTrace)
|
||||
if len(mdata) > 0 {
|
||||
s.ctx = metadata.NewIncomingContext(s.ctx, mdata)
|
||||
if statsTags := mdata["grpc-tags-bin"]; len(statsTags) > 0 {
|
||||
s.ctx = stats.SetIncomingTags(s.ctx, []byte(statsTags[len(statsTags)-1]))
|
||||
}
|
||||
if statsTrace := mdata["grpc-trace-bin"]; len(statsTrace) > 0 {
|
||||
s.ctx = stats.SetIncomingTrace(s.ctx, []byte(statsTrace[len(statsTrace)-1]))
|
||||
}
|
||||
}
|
||||
t.mu.Lock()
|
||||
if t.state != reachable {
|
||||
|
@ -383,10 +451,10 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(
|
|||
return true
|
||||
}
|
||||
t.maxStreamID = streamID
|
||||
if state.data.httpMethod != http.MethodPost {
|
||||
if httpMethod != http.MethodPost {
|
||||
t.mu.Unlock()
|
||||
if logger.V(logLevel) {
|
||||
logger.Warningf("transport: http2Server.operateHeaders parsed a :method field: %v which should be POST", state.data.httpMethod)
|
||||
logger.Infof("transport: http2Server.operateHeaders parsed a :method field: %v which should be POST", httpMethod)
|
||||
}
|
||||
t.controlBuf.put(&cleanupStream{
|
||||
streamID: streamID,
|
||||
|
@ -399,7 +467,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: state.data.method}); err != nil {
|
||||
if s.ctx, err = t.inTapHandle(s.ctx, &tap.Info{FullMethodName: s.method}); err != nil {
|
||||
t.mu.Unlock()
|
||||
if logger.V(logLevel) {
|
||||
logger.Infof("transport: http2Server.operateHeaders got an error from InTapHandle: %v", err)
|
||||
|
@ -437,7 +505,7 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(
|
|||
LocalAddr: t.localAddr,
|
||||
Compression: s.recvCompress,
|
||||
WireLength: int(frame.Header().Length),
|
||||
Header: metadata.MD(state.data.mdata).Copy(),
|
||||
Header: metadata.MD(mdata).Copy(),
|
||||
}
|
||||
t.stats.HandleRPC(s.ctx, inHeader)
|
||||
}
|
||||
|
@ -1004,12 +1072,12 @@ func (t *http2Server) keepalive() {
|
|||
if val <= 0 {
|
||||
// The connection has been idle for a duration of keepalive.MaxConnectionIdle or more.
|
||||
// Gracefully close the connection.
|
||||
t.drain(http2.ErrCodeNo, []byte{})
|
||||
t.Drain()
|
||||
return
|
||||
}
|
||||
idleTimer.Reset(val)
|
||||
case <-ageTimer.C:
|
||||
t.drain(http2.ErrCodeNo, []byte{})
|
||||
t.Drain()
|
||||
ageTimer.Reset(t.kp.MaxConnectionAgeGrace)
|
||||
select {
|
||||
case <-ageTimer.C:
|
||||
|
@ -1063,11 +1131,11 @@ func (t *http2Server) keepalive() {
|
|||
// Close starts shutting down the http2Server transport.
|
||||
// TODO(zhaoq): Now the destruction is not blocked on any pending streams. This
|
||||
// could cause some resource issue. Revisit this later.
|
||||
func (t *http2Server) Close() error {
|
||||
func (t *http2Server) Close() {
|
||||
t.mu.Lock()
|
||||
if t.state == closing {
|
||||
t.mu.Unlock()
|
||||
return errors.New("transport: Close() was already called")
|
||||
return
|
||||
}
|
||||
t.state = closing
|
||||
streams := t.activeStreams
|
||||
|
@ -1075,7 +1143,9 @@ func (t *http2Server) Close() error {
|
|||
t.mu.Unlock()
|
||||
t.controlBuf.finish()
|
||||
close(t.done)
|
||||
err := t.conn.Close()
|
||||
if err := t.conn.Close(); err != nil && logger.V(logLevel) {
|
||||
logger.Infof("transport: error closing conn during Close: %v", err)
|
||||
}
|
||||
if channelz.IsOn() {
|
||||
channelz.RemoveEntry(t.channelzID)
|
||||
}
|
||||
|
@ -1087,7 +1157,6 @@ func (t *http2Server) Close() error {
|
|||
connEnd := &stats.ConnEnd{}
|
||||
t.stats.HandleConn(t.ctx, connEnd)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// deleteStream deletes the stream s from transport's active streams.
|
||||
|
@ -1152,17 +1221,13 @@ func (t *http2Server) RemoteAddr() net.Addr {
|
|||
}
|
||||
|
||||
func (t *http2Server) Drain() {
|
||||
t.drain(http2.ErrCodeNo, []byte{})
|
||||
}
|
||||
|
||||
func (t *http2Server) drain(code http2.ErrCode, debugData []byte) {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
if t.drainChan != nil {
|
||||
return
|
||||
}
|
||||
t.drainChan = make(chan struct{})
|
||||
t.controlBuf.put(&goAway{code: code, debugData: debugData, headsUp: true})
|
||||
t.controlBuf.put(&goAway{code: http2.ErrCodeNo, debugData: []byte{}, headsUp: true})
|
||||
}
|
||||
|
||||
var goAwayPing = &ping{data: [8]byte{1, 6, 1, 8, 0, 3, 3, 9}}
|
||||
|
|
|
@ -39,7 +39,6 @@ import (
|
|||
spb "google.golang.org/genproto/googleapis/rpc/status"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
"google.golang.org/grpc/internal/grpcutil"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
|
@ -96,53 +95,6 @@ var (
|
|||
logger = grpclog.Component("transport")
|
||||
)
|
||||
|
||||
type parsedHeaderData struct {
|
||||
encoding string
|
||||
// statusGen caches the stream status received from the trailer the server
|
||||
// sent. Client side only. Do not access directly. After all trailers are
|
||||
// parsed, use the status method to retrieve the status.
|
||||
statusGen *status.Status
|
||||
// rawStatusCode and rawStatusMsg are set from the raw trailer fields and are not
|
||||
// intended for direct access outside of parsing.
|
||||
rawStatusCode *int
|
||||
rawStatusMsg string
|
||||
httpStatus *int
|
||||
// Server side only fields.
|
||||
timeoutSet bool
|
||||
timeout time.Duration
|
||||
method string
|
||||
httpMethod string
|
||||
// key-value metadata map from the peer.
|
||||
mdata map[string][]string
|
||||
statsTags []byte
|
||||
statsTrace []byte
|
||||
contentSubtype string
|
||||
|
||||
// isGRPC field indicates whether the peer is speaking gRPC (otherwise HTTP).
|
||||
//
|
||||
// We are in gRPC mode (peer speaking gRPC) if:
|
||||
// * We are client side and have already received a HEADER frame that indicates gRPC peer.
|
||||
// * The header contains valid a content-type, i.e. a string starts with "application/grpc"
|
||||
// And we should handle error specific to gRPC.
|
||||
//
|
||||
// Otherwise (i.e. a content-type string starts without "application/grpc", or does not exist), we
|
||||
// are in HTTP fallback mode, and should handle error specific to HTTP.
|
||||
isGRPC bool
|
||||
grpcErr error
|
||||
httpErr error
|
||||
contentTypeErr string
|
||||
}
|
||||
|
||||
// decodeState configures decoding criteria and records the decoded data.
|
||||
type decodeState struct {
|
||||
// whether decoding on server side or not
|
||||
serverSide bool
|
||||
|
||||
// Records the states during HPACK decoding. It will be filled with info parsed from HTTP HEADERS
|
||||
// frame once decodeHeader function has been invoked and returned.
|
||||
data parsedHeaderData
|
||||
}
|
||||
|
||||
// isReservedHeader checks whether hdr belongs to HTTP2 headers
|
||||
// reserved by gRPC protocol. Any other headers are classified as the
|
||||
// user-specified metadata.
|
||||
|
@ -180,14 +132,6 @@ func isWhitelistedHeader(hdr string) bool {
|
|||
}
|
||||
}
|
||||
|
||||
func (d *decodeState) status() *status.Status {
|
||||
if d.data.statusGen == nil {
|
||||
// No status-details were provided; generate status using code/msg.
|
||||
d.data.statusGen = status.New(codes.Code(int32(*(d.data.rawStatusCode))), d.data.rawStatusMsg)
|
||||
}
|
||||
return d.data.statusGen
|
||||
}
|
||||
|
||||
const binHdrSuffix = "-bin"
|
||||
|
||||
func encodeBinHeader(v []byte) string {
|
||||
|
@ -217,170 +161,38 @@ func decodeMetadataHeader(k, v string) (string, error) {
|
|||
return v, nil
|
||||
}
|
||||
|
||||
func (d *decodeState) decodeHeader(frame *http2.MetaHeadersFrame) (http2.ErrCode, error) {
|
||||
// frame.Truncated is set to true when framer detects that the current header
|
||||
// list size hits MaxHeaderListSize limit.
|
||||
if frame.Truncated {
|
||||
return http2.ErrCodeFrameSize, status.Error(codes.Internal, "peer header list size exceeded limit")
|
||||
func decodeGRPCStatusDetails(rawDetails string) (*status.Status, error) {
|
||||
v, err := decodeBinHeader(rawDetails)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, hf := range frame.Fields {
|
||||
d.processHeaderField(hf)
|
||||
st := &spb.Status{}
|
||||
if err = proto.Unmarshal(v, st); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if d.data.isGRPC {
|
||||
if d.data.grpcErr != nil {
|
||||
return http2.ErrCodeProtocol, d.data.grpcErr
|
||||
}
|
||||
if d.serverSide {
|
||||
return http2.ErrCodeNo, nil
|
||||
}
|
||||
if d.data.rawStatusCode == nil && d.data.statusGen == nil {
|
||||
// gRPC status doesn't exist.
|
||||
// Set rawStatusCode to be unknown and return nil error.
|
||||
// So that, if the stream has ended this Unknown status
|
||||
// will be propagated to the user.
|
||||
// Otherwise, it will be ignored. In which case, status from
|
||||
// a later trailer, that has StreamEnded flag set, is propagated.
|
||||
code := int(codes.Unknown)
|
||||
d.data.rawStatusCode = &code
|
||||
}
|
||||
return http2.ErrCodeNo, nil
|
||||
}
|
||||
|
||||
// HTTP fallback mode
|
||||
if d.data.httpErr != nil {
|
||||
return http2.ErrCodeProtocol, d.data.httpErr
|
||||
}
|
||||
|
||||
var (
|
||||
code = codes.Internal // when header does not include HTTP status, return INTERNAL
|
||||
ok bool
|
||||
)
|
||||
|
||||
if d.data.httpStatus != nil {
|
||||
code, ok = HTTPStatusConvTab[*(d.data.httpStatus)]
|
||||
if !ok {
|
||||
code = codes.Unknown
|
||||
}
|
||||
}
|
||||
|
||||
return http2.ErrCodeProtocol, status.Error(code, d.constructHTTPErrMsg())
|
||||
return status.FromProto(st), nil
|
||||
}
|
||||
|
||||
// constructErrMsg constructs error message to be returned in HTTP fallback mode.
|
||||
// Format: HTTP status code and its corresponding message + content-type error message.
|
||||
func (d *decodeState) constructHTTPErrMsg() string {
|
||||
func constructHTTPErrMsg(httpStatus *int, contentTypeErr string) string {
|
||||
var errMsgs []string
|
||||
|
||||
if d.data.httpStatus == nil {
|
||||
if httpStatus == nil {
|
||||
errMsgs = append(errMsgs, "malformed header: missing HTTP status")
|
||||
} else {
|
||||
errMsgs = append(errMsgs, fmt.Sprintf("%s: HTTP status code %d", http.StatusText(*(d.data.httpStatus)), *d.data.httpStatus))
|
||||
errMsgs = append(errMsgs, fmt.Sprintf("%s: HTTP status code %d", http.StatusText(*(httpStatus)), *httpStatus))
|
||||
}
|
||||
|
||||
if d.data.contentTypeErr == "" {
|
||||
if contentTypeErr == "" {
|
||||
errMsgs = append(errMsgs, "transport: missing content-type field")
|
||||
} else {
|
||||
errMsgs = append(errMsgs, d.data.contentTypeErr)
|
||||
errMsgs = append(errMsgs, contentTypeErr)
|
||||
}
|
||||
|
||||
return strings.Join(errMsgs, "; ")
|
||||
}
|
||||
|
||||
func (d *decodeState) addMetadata(k, v string) {
|
||||
if d.data.mdata == nil {
|
||||
d.data.mdata = make(map[string][]string)
|
||||
}
|
||||
d.data.mdata[k] = append(d.data.mdata[k], v)
|
||||
}
|
||||
|
||||
func (d *decodeState) processHeaderField(f hpack.HeaderField) {
|
||||
switch f.Name {
|
||||
case "content-type":
|
||||
contentSubtype, validContentType := grpcutil.ContentSubtype(f.Value)
|
||||
if !validContentType {
|
||||
d.data.contentTypeErr = fmt.Sprintf("transport: received the unexpected content-type %q", f.Value)
|
||||
return
|
||||
}
|
||||
d.data.contentSubtype = contentSubtype
|
||||
// TODO: do we want to propagate the whole content-type in the metadata,
|
||||
// or come up with a way to just propagate the content-subtype if it was set?
|
||||
// ie {"content-type": "application/grpc+proto"} or {"content-subtype": "proto"}
|
||||
// in the metadata?
|
||||
d.addMetadata(f.Name, f.Value)
|
||||
d.data.isGRPC = true
|
||||
case "grpc-encoding":
|
||||
d.data.encoding = f.Value
|
||||
case "grpc-status":
|
||||
code, err := strconv.Atoi(f.Value)
|
||||
if err != nil {
|
||||
d.data.grpcErr = status.Errorf(codes.Internal, "transport: malformed grpc-status: %v", err)
|
||||
return
|
||||
}
|
||||
d.data.rawStatusCode = &code
|
||||
case "grpc-message":
|
||||
d.data.rawStatusMsg = decodeGrpcMessage(f.Value)
|
||||
case "grpc-status-details-bin":
|
||||
v, err := decodeBinHeader(f.Value)
|
||||
if err != nil {
|
||||
d.data.grpcErr = status.Errorf(codes.Internal, "transport: malformed grpc-status-details-bin: %v", err)
|
||||
return
|
||||
}
|
||||
s := &spb.Status{}
|
||||
if err := proto.Unmarshal(v, s); err != nil {
|
||||
d.data.grpcErr = status.Errorf(codes.Internal, "transport: malformed grpc-status-details-bin: %v", err)
|
||||
return
|
||||
}
|
||||
d.data.statusGen = status.FromProto(s)
|
||||
case "grpc-timeout":
|
||||
d.data.timeoutSet = true
|
||||
var err error
|
||||
if d.data.timeout, err = decodeTimeout(f.Value); err != nil {
|
||||
d.data.grpcErr = status.Errorf(codes.Internal, "transport: malformed time-out: %v", err)
|
||||
}
|
||||
case ":path":
|
||||
d.data.method = f.Value
|
||||
case ":status":
|
||||
code, err := strconv.Atoi(f.Value)
|
||||
if err != nil {
|
||||
d.data.httpErr = status.Errorf(codes.Internal, "transport: malformed http-status: %v", err)
|
||||
return
|
||||
}
|
||||
d.data.httpStatus = &code
|
||||
case "grpc-tags-bin":
|
||||
v, err := decodeBinHeader(f.Value)
|
||||
if err != nil {
|
||||
d.data.grpcErr = status.Errorf(codes.Internal, "transport: malformed grpc-tags-bin: %v", err)
|
||||
return
|
||||
}
|
||||
d.data.statsTags = v
|
||||
d.addMetadata(f.Name, string(v))
|
||||
case "grpc-trace-bin":
|
||||
v, err := decodeBinHeader(f.Value)
|
||||
if err != nil {
|
||||
d.data.grpcErr = status.Errorf(codes.Internal, "transport: malformed grpc-trace-bin: %v", err)
|
||||
return
|
||||
}
|
||||
d.data.statsTrace = v
|
||||
d.addMetadata(f.Name, string(v))
|
||||
case ":method":
|
||||
d.data.httpMethod = f.Value
|
||||
default:
|
||||
if isReservedHeader(f.Name) && !isWhitelistedHeader(f.Name) {
|
||||
break
|
||||
}
|
||||
v, err := decodeMetadataHeader(f.Name, f.Value)
|
||||
if err != nil {
|
||||
if logger.V(logLevel) {
|
||||
logger.Errorf("Failed to decode metadata header (%q, %q): %v", f.Name, f.Value, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
d.addMetadata(f.Name, v)
|
||||
}
|
||||
}
|
||||
|
||||
type timeoutUnit uint8
|
||||
|
||||
const (
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
*/
|
||||
|
||||
// Package networktype declares the network type to be used in the default
|
||||
// dailer. Attribute of a resolver.Address.
|
||||
// dialer. Attribute of a resolver.Address.
|
||||
package networktype
|
||||
|
||||
import (
|
||||
|
|
|
@ -532,12 +532,6 @@ type ServerConfig struct {
|
|||
HeaderTableSize *uint32
|
||||
}
|
||||
|
||||
// NewServerTransport creates a ServerTransport with conn or non-nil error
|
||||
// if it fails.
|
||||
func NewServerTransport(protocol string, conn net.Conn, config *ServerConfig) (ServerTransport, error) {
|
||||
return newHTTP2Server(conn, config)
|
||||
}
|
||||
|
||||
// ConnectOptions covers all relevant options for communicating with the server.
|
||||
type ConnectOptions struct {
|
||||
// UserAgent is the application user agent.
|
||||
|
@ -694,7 +688,7 @@ type ServerTransport interface {
|
|||
// Close tears down the transport. Once it is called, the transport
|
||||
// should not be accessed any more. All the pending streams and their
|
||||
// handlers will be terminated asynchronously.
|
||||
Close() error
|
||||
Close()
|
||||
|
||||
// RemoteAddr returns the remote network address.
|
||||
RemoteAddr() net.Addr
|
||||
|
|
|
@ -93,12 +93,16 @@ func (md MD) Copy() MD {
|
|||
}
|
||||
|
||||
// Get obtains the values for a given key.
|
||||
//
|
||||
// k is converted to lowercase before searching in md.
|
||||
func (md MD) Get(k string) []string {
|
||||
k = strings.ToLower(k)
|
||||
return md[k]
|
||||
}
|
||||
|
||||
// Set sets the value of a given key with a slice of values.
|
||||
//
|
||||
// k is converted to lowercase before storing in md.
|
||||
func (md MD) Set(k string, vals ...string) {
|
||||
if len(vals) == 0 {
|
||||
return
|
||||
|
@ -107,7 +111,10 @@ func (md MD) Set(k string, vals ...string) {
|
|||
md[k] = vals
|
||||
}
|
||||
|
||||
// Append adds the values to key k, not overwriting what was already stored at that key.
|
||||
// Append adds the values to key k, not overwriting what was already stored at
|
||||
// that key.
|
||||
//
|
||||
// k is converted to lowercase before storing in md.
|
||||
func (md MD) Append(k string, vals ...string) {
|
||||
if len(vals) == 0 {
|
||||
return
|
||||
|
@ -117,8 +124,9 @@ func (md MD) Append(k string, vals ...string) {
|
|||
}
|
||||
|
||||
// Join joins any number of mds into a single MD.
|
||||
// The order of values for each key is determined by the order in which
|
||||
// the mds containing those values are presented to Join.
|
||||
//
|
||||
// The order of values for each key is determined by the order in which the mds
|
||||
// containing those values are presented to Join.
|
||||
func Join(mds ...MD) MD {
|
||||
out := MD{}
|
||||
for _, md := range mds {
|
||||
|
@ -145,8 +153,8 @@ func NewOutgoingContext(ctx context.Context, md MD) context.Context {
|
|||
}
|
||||
|
||||
// AppendToOutgoingContext returns a new context with the provided kv merged
|
||||
// with any existing metadata in the context. Please refer to the
|
||||
// documentation of Pairs for a description of kv.
|
||||
// with any existing metadata in the context. Please refer to the documentation
|
||||
// of Pairs for a description of kv.
|
||||
func AppendToOutgoingContext(ctx context.Context, kv ...string) context.Context {
|
||||
if len(kv)%2 == 1 {
|
||||
panic(fmt.Sprintf("metadata: AppendToOutgoingContext got an odd number of input pairs for metadata: %d", len(kv)))
|
||||
|
@ -159,20 +167,34 @@ func AppendToOutgoingContext(ctx context.Context, kv ...string) context.Context
|
|||
return context.WithValue(ctx, mdOutgoingKey{}, rawMD{md: md.md, added: added})
|
||||
}
|
||||
|
||||
// FromIncomingContext returns the incoming metadata in ctx if it exists. The
|
||||
// returned MD should not be modified. Writing to it may cause races.
|
||||
// Modification should be made to copies of the returned MD.
|
||||
func FromIncomingContext(ctx context.Context) (md MD, ok bool) {
|
||||
md, ok = ctx.Value(mdIncomingKey{}).(MD)
|
||||
return
|
||||
// FromIncomingContext returns the incoming metadata in ctx if it exists.
|
||||
//
|
||||
// All keys in the returned MD are lowercase.
|
||||
func FromIncomingContext(ctx context.Context) (MD, bool) {
|
||||
md, ok := ctx.Value(mdIncomingKey{}).(MD)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
out := MD{}
|
||||
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.
|
||||
key := strings.ToLower(k)
|
||||
out[key] = v
|
||||
}
|
||||
return out, true
|
||||
}
|
||||
|
||||
// FromOutgoingContextRaw returns the un-merged, intermediary contents
|
||||
// of rawMD. Remember to perform strings.ToLower on the keys. The returned
|
||||
// MD should not be modified. Writing to it may cause races. Modification
|
||||
// should be made to copies of the returned MD.
|
||||
// FromOutgoingContextRaw returns the un-merged, intermediary contents of rawMD.
|
||||
//
|
||||
// This is intended for gRPC-internal use ONLY.
|
||||
// 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) {
|
||||
raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD)
|
||||
if !ok {
|
||||
|
@ -182,16 +204,23 @@ func FromOutgoingContextRaw(ctx context.Context) (MD, [][]string, bool) {
|
|||
return raw.md, raw.added, true
|
||||
}
|
||||
|
||||
// FromOutgoingContext returns the outgoing metadata in ctx if it exists. The
|
||||
// returned MD should not be modified. Writing to it may cause races.
|
||||
// Modification should be made to copies of the returned MD.
|
||||
// FromOutgoingContext returns the outgoing metadata in ctx if it exists.
|
||||
//
|
||||
// All keys in the returned MD are lowercase.
|
||||
func FromOutgoingContext(ctx context.Context) (MD, bool) {
|
||||
raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
out := raw.md.Copy()
|
||||
out := MD{}
|
||||
for k, v := range raw.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.
|
||||
key := strings.ToLower(k)
|
||||
out[key] = v
|
||||
}
|
||||
for _, added := range raw.added {
|
||||
if len(added)%2 == 1 {
|
||||
panic(fmt.Sprintf("metadata: FromOutgoingContext got an odd number of input pairs for metadata: %d", len(added)))
|
||||
|
|
|
@ -39,6 +39,8 @@ type ccResolverWrapper struct {
|
|||
resolver resolver.Resolver
|
||||
done *grpcsync.Event
|
||||
curState resolver.State
|
||||
|
||||
incomingMu sync.Mutex // Synchronizes all the incoming calls.
|
||||
}
|
||||
|
||||
// newCCResolverWrapper uses the resolver.Builder to build a Resolver and
|
||||
|
@ -90,6 +92,8 @@ func (ccr *ccResolverWrapper) close() {
|
|||
}
|
||||
|
||||
func (ccr *ccResolverWrapper) UpdateState(s resolver.State) error {
|
||||
ccr.incomingMu.Lock()
|
||||
defer ccr.incomingMu.Unlock()
|
||||
if ccr.done.HasFired() {
|
||||
return nil
|
||||
}
|
||||
|
@ -105,6 +109,8 @@ func (ccr *ccResolverWrapper) UpdateState(s resolver.State) error {
|
|||
}
|
||||
|
||||
func (ccr *ccResolverWrapper) ReportError(err error) {
|
||||
ccr.incomingMu.Lock()
|
||||
defer ccr.incomingMu.Unlock()
|
||||
if ccr.done.HasFired() {
|
||||
return
|
||||
}
|
||||
|
@ -114,6 +120,8 @@ func (ccr *ccResolverWrapper) ReportError(err error) {
|
|||
|
||||
// NewAddress is called by the resolver implementation to send addresses to gRPC.
|
||||
func (ccr *ccResolverWrapper) NewAddress(addrs []resolver.Address) {
|
||||
ccr.incomingMu.Lock()
|
||||
defer ccr.incomingMu.Unlock()
|
||||
if ccr.done.HasFired() {
|
||||
return
|
||||
}
|
||||
|
@ -128,6 +136,8 @@ func (ccr *ccResolverWrapper) NewAddress(addrs []resolver.Address) {
|
|||
// NewServiceConfig is called by the resolver implementation to send service
|
||||
// configs to gRPC.
|
||||
func (ccr *ccResolverWrapper) NewServiceConfig(sc string) {
|
||||
ccr.incomingMu.Lock()
|
||||
defer ccr.incomingMu.Unlock()
|
||||
if ccr.done.HasFired() {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -258,7 +258,8 @@ func (o PeerCallOption) after(c *callInfo, attempt *csAttempt) {
|
|||
}
|
||||
|
||||
// WaitForReady configures the action to take when an RPC is attempted on broken
|
||||
// connections or unreachable servers. If waitForReady is false, the RPC will fail
|
||||
// connections or unreachable servers. If waitForReady is false and the
|
||||
// connection is in the TRANSIENT_FAILURE state, the RPC will fail
|
||||
// immediately. Otherwise, the RPC client will block the call until a
|
||||
// connection is available (or the call is canceled or times out) and will
|
||||
// retry the call if it fails due to a transient error. gRPC will not retry if
|
||||
|
|
|
@ -844,10 +844,16 @@ func (s *Server) handleRawConn(lisAddr string, rawConn net.Conn) {
|
|||
// ErrConnDispatched means that the connection was dispatched away from
|
||||
// gRPC; those connections should be left open.
|
||||
if err != credentials.ErrConnDispatched {
|
||||
s.mu.Lock()
|
||||
s.errorf("ServerHandshake(%q) failed: %v", rawConn.RemoteAddr(), err)
|
||||
s.mu.Unlock()
|
||||
channelz.Warningf(logger, s.channelzID, "grpc: Server.Serve failed to complete security handshake from %q: %v", rawConn.RemoteAddr(), err)
|
||||
// In deployments where a gRPC server runs behind a cloud load
|
||||
// balancer which performs regular TCP level health checks, the
|
||||
// connection is closed immediately by the latter. Skipping the
|
||||
// error here will help reduce log clutter.
|
||||
if err != io.EOF {
|
||||
s.mu.Lock()
|
||||
s.errorf("ServerHandshake(%q) failed: %v", rawConn.RemoteAddr(), err)
|
||||
s.mu.Unlock()
|
||||
channelz.Warningf(logger, s.channelzID, "grpc: Server.Serve failed to complete security handshake from %q: %v", rawConn.RemoteAddr(), err)
|
||||
}
|
||||
rawConn.Close()
|
||||
}
|
||||
rawConn.SetDeadline(time.Time{})
|
||||
|
@ -897,7 +903,7 @@ func (s *Server) newHTTP2Transport(c net.Conn, authInfo credentials.AuthInfo) tr
|
|||
MaxHeaderListSize: s.opts.maxHeaderListSize,
|
||||
HeaderTableSize: s.opts.headerTableSize,
|
||||
}
|
||||
st, err := transport.NewServerTransport("http2", c, config)
|
||||
st, err := transport.NewServerTransport(c, config)
|
||||
if err != nil {
|
||||
s.mu.Lock()
|
||||
s.errorf("NewServerTransport(%q) failed: %v", c.RemoteAddr(), err)
|
||||
|
@ -1521,6 +1527,8 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp
|
|||
}
|
||||
}
|
||||
|
||||
ss.ctx = newContextWithRPCInfo(ss.ctx, false, ss.codec, ss.cp, ss.comp)
|
||||
|
||||
if trInfo != nil {
|
||||
trInfo.tr.LazyLog(&trInfo.firstLine, false)
|
||||
}
|
||||
|
@ -1588,7 +1596,7 @@ func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Str
|
|||
trInfo.tr.SetError()
|
||||
}
|
||||
errDesc := fmt.Sprintf("malformed method name: %q", stream.Method())
|
||||
if err := t.WriteStatus(stream, status.New(codes.ResourceExhausted, errDesc)); err != nil {
|
||||
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()
|
||||
|
|
|
@ -19,4 +19,4 @@
|
|||
package grpc
|
||||
|
||||
// Version is the current grpc version.
|
||||
const Version = "1.38.0"
|
||||
const Version = "1.39.0"
|
||||
|
|
|
@ -32,26 +32,14 @@ PATH="${HOME}/go/bin:${GOROOT}/bin:${PATH}"
|
|||
go version
|
||||
|
||||
if [[ "$1" = "-install" ]]; then
|
||||
# Check for module support
|
||||
if go help mod >& /dev/null; 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
|
||||
popd
|
||||
else
|
||||
# Ye olde `go get` incantation.
|
||||
# Note: this gets the latest version of all tools (vs. the pinned versions
|
||||
# with Go modules).
|
||||
go get -u \
|
||||
golang.org/x/lint/golint \
|
||||
golang.org/x/tools/cmd/goimports \
|
||||
honnef.co/go/tools/cmd/staticcheck \
|
||||
github.com/client9/misspell/cmd/misspell
|
||||
fi
|
||||
# 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
|
||||
popd
|
||||
if [[ -z "${VET_SKIP_PROTO}" ]]; then
|
||||
if [[ "${TRAVIS}" = "true" ]]; then
|
||||
PROTOBUF_VERSION=3.14.0
|
||||
|
|
|
@ -744,9 +744,6 @@ func (d decoder) skipValue() error {
|
|||
// Skip items. This will not validate whether skipped values are
|
||||
// of the same type or not, same behavior as C++
|
||||
// TextFormat::Parser::AllowUnknownField(true) version 3.8.0.
|
||||
if err := d.skipValue(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -263,3 +263,8 @@ func (e *Encoder) Snapshot() encoderState {
|
|||
func (e *Encoder) Reset(es encoderState) {
|
||||
e.encoderState = es
|
||||
}
|
||||
|
||||
// AppendString appends the escaped form of the input string to b.
|
||||
func AppendString(b []byte, s string) []byte {
|
||||
return appendString(b, s, false)
|
||||
}
|
||||
|
|
|
@ -440,6 +440,13 @@ func legacyMerge(in piface.MergeInput) piface.MergeOutput {
|
|||
if !ok {
|
||||
return piface.MergeOutput{}
|
||||
}
|
||||
if !in.Source.IsValid() {
|
||||
// Legacy Marshal methods may not function on nil messages.
|
||||
// Check for a typed nil source only after we confirm that
|
||||
// legacy Marshal/Unmarshal methods are present, for
|
||||
// consistency.
|
||||
return piface.MergeOutput{Flags: piface.MergeComplete}
|
||||
}
|
||||
b, err := marshaler.Marshal()
|
||||
if err != nil {
|
||||
return piface.MergeOutput{}
|
||||
|
|
|
@ -52,8 +52,8 @@ import (
|
|||
// 10. Send out the CL for review and submit it.
|
||||
const (
|
||||
Major = 1
|
||||
Minor = 26
|
||||
Patch = 0
|
||||
Minor = 27
|
||||
Patch = 1
|
||||
PreRelease = ""
|
||||
)
|
||||
|
||||
|
|
|
@ -94,7 +94,8 @@ type Files struct {
|
|||
// Note that enum values are in the top-level since that are in the same
|
||||
// scope as the parent enum.
|
||||
descsByName map[protoreflect.FullName]interface{}
|
||||
filesByPath map[string]protoreflect.FileDescriptor
|
||||
filesByPath map[string][]protoreflect.FileDescriptor
|
||||
numFiles int
|
||||
}
|
||||
|
||||
type packageDescriptor struct {
|
||||
|
@ -117,17 +118,16 @@ func (r *Files) RegisterFile(file protoreflect.FileDescriptor) error {
|
|||
r.descsByName = map[protoreflect.FullName]interface{}{
|
||||
"": &packageDescriptor{},
|
||||
}
|
||||
r.filesByPath = make(map[string]protoreflect.FileDescriptor)
|
||||
r.filesByPath = make(map[string][]protoreflect.FileDescriptor)
|
||||
}
|
||||
path := file.Path()
|
||||
if prev := r.filesByPath[path]; prev != nil {
|
||||
if prev := r.filesByPath[path]; len(prev) > 0 {
|
||||
r.checkGenProtoConflict(path)
|
||||
err := errors.New("file %q is already registered", file.Path())
|
||||
err = amendErrorWithCaller(err, prev, file)
|
||||
if r == GlobalFiles && ignoreConflict(file, err) {
|
||||
err = nil
|
||||
err = amendErrorWithCaller(err, prev[0], file)
|
||||
if !(r == GlobalFiles && ignoreConflict(file, err)) {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
for name := file.Package(); name != ""; name = name.Parent() {
|
||||
|
@ -168,7 +168,8 @@ func (r *Files) RegisterFile(file protoreflect.FileDescriptor) error {
|
|||
rangeTopLevelDescriptors(file, func(d protoreflect.Descriptor) {
|
||||
r.descsByName[d.FullName()] = d
|
||||
})
|
||||
r.filesByPath[path] = file
|
||||
r.filesByPath[path] = append(r.filesByPath[path], file)
|
||||
r.numFiles++
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -308,6 +309,7 @@ func (s *nameSuffix) Pop() (name protoreflect.Name) {
|
|||
// FindFileByPath looks up a file by the path.
|
||||
//
|
||||
// This returns (nil, NotFound) if not found.
|
||||
// This returns an error if multiple files have the same path.
|
||||
func (r *Files) FindFileByPath(path string) (protoreflect.FileDescriptor, error) {
|
||||
if r == nil {
|
||||
return nil, NotFound
|
||||
|
@ -316,13 +318,19 @@ func (r *Files) FindFileByPath(path string) (protoreflect.FileDescriptor, error)
|
|||
globalMutex.RLock()
|
||||
defer globalMutex.RUnlock()
|
||||
}
|
||||
if fd, ok := r.filesByPath[path]; ok {
|
||||
return fd, nil
|
||||
fds := r.filesByPath[path]
|
||||
switch len(fds) {
|
||||
case 0:
|
||||
return nil, NotFound
|
||||
case 1:
|
||||
return fds[0], nil
|
||||
default:
|
||||
return nil, errors.New("multiple files named %q", path)
|
||||
}
|
||||
return nil, NotFound
|
||||
}
|
||||
|
||||
// NumFiles reports the number of registered files.
|
||||
// NumFiles reports the number of registered files,
|
||||
// including duplicate files with the same name.
|
||||
func (r *Files) NumFiles() int {
|
||||
if r == nil {
|
||||
return 0
|
||||
|
@ -331,10 +339,11 @@ func (r *Files) NumFiles() int {
|
|||
globalMutex.RLock()
|
||||
defer globalMutex.RUnlock()
|
||||
}
|
||||
return len(r.filesByPath)
|
||||
return r.numFiles
|
||||
}
|
||||
|
||||
// RangeFiles iterates over all registered files while f returns true.
|
||||
// If multiple files have the same name, RangeFiles iterates over all of them.
|
||||
// The iteration order is undefined.
|
||||
func (r *Files) RangeFiles(f func(protoreflect.FileDescriptor) bool) {
|
||||
if r == nil {
|
||||
|
@ -344,9 +353,11 @@ func (r *Files) RangeFiles(f func(protoreflect.FileDescriptor) bool) {
|
|||
globalMutex.RLock()
|
||||
defer globalMutex.RUnlock()
|
||||
}
|
||||
for _, file := range r.filesByPath {
|
||||
if !f(file) {
|
||||
return
|
||||
for _, files := range r.filesByPath {
|
||||
for _, file := range files {
|
||||
if !f(file) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,6 @@ package descriptorpb
|
|||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoiface "google.golang.org/protobuf/runtime/protoiface"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
|
@ -829,15 +828,6 @@ func (*ExtensionRangeOptions) Descriptor() ([]byte, []int) {
|
|||
return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
var extRange_ExtensionRangeOptions = []protoiface.ExtensionRangeV1{
|
||||
{Start: 1000, End: 536870911},
|
||||
}
|
||||
|
||||
// Deprecated: Use ExtensionRangeOptions.ProtoReflect.Descriptor.ExtensionRanges instead.
|
||||
func (*ExtensionRangeOptions) ExtensionRangeArray() []protoiface.ExtensionRangeV1 {
|
||||
return extRange_ExtensionRangeOptions
|
||||
}
|
||||
|
||||
func (x *ExtensionRangeOptions) GetUninterpretedOption() []*UninterpretedOption {
|
||||
if x != nil {
|
||||
return x.UninterpretedOption
|
||||
|
@ -1520,15 +1510,6 @@ func (*FileOptions) Descriptor() ([]byte, []int) {
|
|||
return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{10}
|
||||
}
|
||||
|
||||
var extRange_FileOptions = []protoiface.ExtensionRangeV1{
|
||||
{Start: 1000, End: 536870911},
|
||||
}
|
||||
|
||||
// Deprecated: Use FileOptions.ProtoReflect.Descriptor.ExtensionRanges instead.
|
||||
func (*FileOptions) ExtensionRangeArray() []protoiface.ExtensionRangeV1 {
|
||||
return extRange_FileOptions
|
||||
}
|
||||
|
||||
func (x *FileOptions) GetJavaPackage() string {
|
||||
if x != nil && x.JavaPackage != nil {
|
||||
return *x.JavaPackage
|
||||
|
@ -1776,15 +1757,6 @@ func (*MessageOptions) Descriptor() ([]byte, []int) {
|
|||
return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{11}
|
||||
}
|
||||
|
||||
var extRange_MessageOptions = []protoiface.ExtensionRangeV1{
|
||||
{Start: 1000, End: 536870911},
|
||||
}
|
||||
|
||||
// Deprecated: Use MessageOptions.ProtoReflect.Descriptor.ExtensionRanges instead.
|
||||
func (*MessageOptions) ExtensionRangeArray() []protoiface.ExtensionRangeV1 {
|
||||
return extRange_MessageOptions
|
||||
}
|
||||
|
||||
func (x *MessageOptions) GetMessageSetWireFormat() bool {
|
||||
if x != nil && x.MessageSetWireFormat != nil {
|
||||
return *x.MessageSetWireFormat
|
||||
|
@ -1930,15 +1902,6 @@ func (*FieldOptions) Descriptor() ([]byte, []int) {
|
|||
return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{12}
|
||||
}
|
||||
|
||||
var extRange_FieldOptions = []protoiface.ExtensionRangeV1{
|
||||
{Start: 1000, End: 536870911},
|
||||
}
|
||||
|
||||
// Deprecated: Use FieldOptions.ProtoReflect.Descriptor.ExtensionRanges instead.
|
||||
func (*FieldOptions) ExtensionRangeArray() []protoiface.ExtensionRangeV1 {
|
||||
return extRange_FieldOptions
|
||||
}
|
||||
|
||||
func (x *FieldOptions) GetCtype() FieldOptions_CType {
|
||||
if x != nil && x.Ctype != nil {
|
||||
return *x.Ctype
|
||||
|
@ -2030,15 +1993,6 @@ func (*OneofOptions) Descriptor() ([]byte, []int) {
|
|||
return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{13}
|
||||
}
|
||||
|
||||
var extRange_OneofOptions = []protoiface.ExtensionRangeV1{
|
||||
{Start: 1000, End: 536870911},
|
||||
}
|
||||
|
||||
// Deprecated: Use OneofOptions.ProtoReflect.Descriptor.ExtensionRanges instead.
|
||||
func (*OneofOptions) ExtensionRangeArray() []protoiface.ExtensionRangeV1 {
|
||||
return extRange_OneofOptions
|
||||
}
|
||||
|
||||
func (x *OneofOptions) GetUninterpretedOption() []*UninterpretedOption {
|
||||
if x != nil {
|
||||
return x.UninterpretedOption
|
||||
|
@ -2101,15 +2055,6 @@ func (*EnumOptions) Descriptor() ([]byte, []int) {
|
|||
return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{14}
|
||||
}
|
||||
|
||||
var extRange_EnumOptions = []protoiface.ExtensionRangeV1{
|
||||
{Start: 1000, End: 536870911},
|
||||
}
|
||||
|
||||
// Deprecated: Use EnumOptions.ProtoReflect.Descriptor.ExtensionRanges instead.
|
||||
func (*EnumOptions) ExtensionRangeArray() []protoiface.ExtensionRangeV1 {
|
||||
return extRange_EnumOptions
|
||||
}
|
||||
|
||||
func (x *EnumOptions) GetAllowAlias() bool {
|
||||
if x != nil && x.AllowAlias != nil {
|
||||
return *x.AllowAlias
|
||||
|
@ -2183,15 +2128,6 @@ func (*EnumValueOptions) Descriptor() ([]byte, []int) {
|
|||
return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{15}
|
||||
}
|
||||
|
||||
var extRange_EnumValueOptions = []protoiface.ExtensionRangeV1{
|
||||
{Start: 1000, End: 536870911},
|
||||
}
|
||||
|
||||
// Deprecated: Use EnumValueOptions.ProtoReflect.Descriptor.ExtensionRanges instead.
|
||||
func (*EnumValueOptions) ExtensionRangeArray() []protoiface.ExtensionRangeV1 {
|
||||
return extRange_EnumValueOptions
|
||||
}
|
||||
|
||||
func (x *EnumValueOptions) GetDeprecated() bool {
|
||||
if x != nil && x.Deprecated != nil {
|
||||
return *x.Deprecated
|
||||
|
@ -2258,15 +2194,6 @@ func (*ServiceOptions) Descriptor() ([]byte, []int) {
|
|||
return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{16}
|
||||
}
|
||||
|
||||
var extRange_ServiceOptions = []protoiface.ExtensionRangeV1{
|
||||
{Start: 1000, End: 536870911},
|
||||
}
|
||||
|
||||
// Deprecated: Use ServiceOptions.ProtoReflect.Descriptor.ExtensionRanges instead.
|
||||
func (*ServiceOptions) ExtensionRangeArray() []protoiface.ExtensionRangeV1 {
|
||||
return extRange_ServiceOptions
|
||||
}
|
||||
|
||||
func (x *ServiceOptions) GetDeprecated() bool {
|
||||
if x != nil && x.Deprecated != nil {
|
||||
return *x.Deprecated
|
||||
|
@ -2335,15 +2262,6 @@ func (*MethodOptions) Descriptor() ([]byte, []int) {
|
|||
return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{17}
|
||||
}
|
||||
|
||||
var extRange_MethodOptions = []protoiface.ExtensionRangeV1{
|
||||
{Start: 1000, End: 536870911},
|
||||
}
|
||||
|
||||
// Deprecated: Use MethodOptions.ProtoReflect.Descriptor.ExtensionRanges instead.
|
||||
func (*MethodOptions) ExtensionRangeArray() []protoiface.ExtensionRangeV1 {
|
||||
return extRange_MethodOptions
|
||||
}
|
||||
|
||||
func (x *MethodOptions) GetDeprecated() bool {
|
||||
if x != nil && x.Deprecated != nil {
|
||||
return *x.Deprecated
|
||||
|
|
|
@ -80,13 +80,13 @@ github.com/google/licenseclassifier/stringclassifier
|
|||
github.com/google/licenseclassifier/stringclassifier/internal/pq
|
||||
github.com/google/licenseclassifier/stringclassifier/searchset
|
||||
github.com/google/licenseclassifier/stringclassifier/searchset/tokenizer
|
||||
# github.com/google/uuid v1.2.0
|
||||
# github.com/google/uuid v1.3.0
|
||||
github.com/google/uuid
|
||||
# github.com/googleapis/gnostic v0.4.1
|
||||
github.com/googleapis/gnostic/compiler
|
||||
github.com/googleapis/gnostic/extensions
|
||||
github.com/googleapis/gnostic/openapiv2
|
||||
# github.com/grpc-ecosystem/grpc-gateway v1.14.8
|
||||
# github.com/grpc-ecosystem/grpc-gateway v1.16.0
|
||||
github.com/grpc-ecosystem/grpc-gateway/internal
|
||||
github.com/grpc-ecosystem/grpc-gateway/runtime
|
||||
github.com/grpc-ecosystem/grpc-gateway/utilities
|
||||
|
@ -173,7 +173,7 @@ go.opencensus.io/trace
|
|||
go.opencensus.io/trace/internal
|
||||
go.opencensus.io/trace/propagation
|
||||
go.opencensus.io/trace/tracestate
|
||||
# go.uber.org/atomic v1.8.0
|
||||
# go.uber.org/atomic v1.9.0
|
||||
go.uber.org/atomic
|
||||
# go.uber.org/multierr v1.6.0
|
||||
go.uber.org/multierr
|
||||
|
@ -190,7 +190,7 @@ golang.org/x/crypto/ssh/terminal
|
|||
# golang.org/x/mod v0.4.2
|
||||
golang.org/x/mod/module
|
||||
golang.org/x/mod/semver
|
||||
# golang.org/x/net v0.0.0-20210614182718-04defd469f4e
|
||||
# golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985
|
||||
golang.org/x/net/context
|
||||
golang.org/x/net/context/ctxhttp
|
||||
golang.org/x/net/http/httpguts
|
||||
|
@ -223,7 +223,7 @@ golang.org/x/text/unicode/norm
|
|||
golang.org/x/text/width
|
||||
# golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
|
||||
golang.org/x/time/rate
|
||||
# golang.org/x/tools v0.1.4
|
||||
# golang.org/x/tools v0.1.5
|
||||
golang.org/x/tools/go/ast/astutil
|
||||
golang.org/x/tools/imports
|
||||
golang.org/x/tools/internal/event
|
||||
|
@ -254,7 +254,7 @@ google.golang.org/appengine/urlfetch
|
|||
google.golang.org/genproto/googleapis/api/httpbody
|
||||
google.golang.org/genproto/googleapis/rpc/status
|
||||
google.golang.org/genproto/protobuf/field_mask
|
||||
# google.golang.org/grpc v1.38.0
|
||||
# google.golang.org/grpc v1.39.0
|
||||
google.golang.org/grpc
|
||||
google.golang.org/grpc/attributes
|
||||
google.golang.org/grpc/backoff
|
||||
|
@ -299,7 +299,7 @@ google.golang.org/grpc/serviceconfig
|
|||
google.golang.org/grpc/stats
|
||||
google.golang.org/grpc/status
|
||||
google.golang.org/grpc/tap
|
||||
# google.golang.org/protobuf v1.26.0
|
||||
# google.golang.org/protobuf v1.27.1
|
||||
google.golang.org/protobuf/encoding/protojson
|
||||
google.golang.org/protobuf/encoding/prototext
|
||||
google.golang.org/protobuf/encoding/protowire
|
||||
|
@ -578,7 +578,7 @@ k8s.io/utils/trace
|
|||
# knative.dev/hack v0.0.0-20210622141627-e28525d8d260
|
||||
## explicit
|
||||
knative.dev/hack
|
||||
# knative.dev/pkg v0.0.0-20210731072840-64ab22bbaab9
|
||||
# knative.dev/pkg v0.0.0-20210803160015-21eb4c167cc5
|
||||
## explicit
|
||||
knative.dev/pkg/apis
|
||||
knative.dev/pkg/apis/duck
|
||||
|
|
Loading…
Reference in New Issue