From beb59ebc0e8707c57e34471ac509a0dcd04c77f2 Mon Sep 17 00:00:00 2001 From: Emruz Hossain Date: Mon, 1 Aug 2022 17:02:01 +0600 Subject: [PATCH] Remove `url.QueryEscape()` Signed-off-by: Emruz Hossain --- go.mod | 11 +- go.sum | 16 +- main.go | 3 +- .../mediocregopher/radix/v3/.travis.yml | 21 --- .../mediocregopher/radix/v3/CHANGELOG.md | 19 +++ .../mediocregopher/radix/v3/README.md | 64 ++++---- .../mediocregopher/radix/v3/action.go | 15 +- .../mediocregopher/radix/v3/cluster.go | 19 +-- .../mediocregopher/radix/v3/cluster_crc16.go | 4 +- .../mediocregopher/radix/v3/cluster_topo.go | 17 +-- .../mediocregopher/radix/v3/conn.go | 12 +- .../github.com/mediocregopher/radix/v3/go.mod | 10 -- .../github.com/mediocregopher/radix/v3/go.sum | 8 - .../radix/v3/internal/bytesutil/bytesutil.go | 7 +- .../mediocregopher/radix/v3/pool.go | 107 ++++++++++---- .../mediocregopher/radix/v3/pubsub.go | 14 +- .../radix/v3/pubsub_persistent.go | 2 +- .../mediocregopher/radix/v3/pubsub_stub.go | 2 +- .../mediocregopher/radix/v3/radix.go | 2 +- .../radix/v3/resp/resp2/resp.go | 103 ++++++++----- .../mediocregopher/radix/v3/resp/util.go | 2 +- .../mediocregopher/radix/v3/scanner.go | 4 +- .../mediocregopher/radix/v3/sentinel.go | 28 ++-- .../mediocregopher/radix/v3/stream.go | 15 +- .../mediocregopher/radix/v3/stub.go | 2 +- .../mediocregopher/radix/v3/timer.go | 2 +- .../mediocregopher/radix/v3/trace/pool.go | 4 + vendor/golang.org/x/xerrors/fmt.go | 138 ++++-------------- vendor/golang.org/x/xerrors/go.mod | 3 - vendor/modules.txt | 12 +- 30 files changed, 317 insertions(+), 349 deletions(-) delete mode 100644 vendor/github.com/mediocregopher/radix/v3/.travis.yml delete mode 100644 vendor/github.com/mediocregopher/radix/v3/go.mod delete mode 100644 vendor/github.com/mediocregopher/radix/v3/go.sum delete mode 100644 vendor/golang.org/x/xerrors/go.mod diff --git a/go.mod b/go.mod index def9075..8cab39e 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,7 @@ module github.com/yannh/redis-dump-go -go 1.16 +go 1.18 -require ( - github.com/mediocregopher/radix/v3 v3.7.0 - github.com/stretchr/testify v1.4.0 // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect - gopkg.in/yaml.v2 v2.2.7 // indirect -) +require github.com/mediocregopher/radix/v3 v3.8.0 + +require golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 // indirect diff --git a/go.sum b/go.sum index 1f308f0..8eb6d03 100644 --- a/go.sum +++ b/go.sum @@ -1,18 +1,10 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/mediocregopher/radix/v3 v3.7.0 h1:SM9zJdme5pYGEVvh1HttjBjDmIaNBDKy+oDCv5w81Wo= -github.com/mediocregopher/radix/v3 v3.7.0/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= +github.com/mediocregopher/radix/v3 v3.8.0 h1:HI8EgkaM7WzsrFpYAkOXIgUKbjNonb2Ne7K6Le61Pmg= +github.com/mediocregopher/radix/v3 v3.8.0/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= 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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/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= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= -gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/main.go b/main.go index 8228276..7b57e1c 100644 --- a/main.go +++ b/main.go @@ -4,7 +4,6 @@ import ( "fmt" "io" "log" - "net/url" "os" "sync" @@ -109,7 +108,7 @@ func realMain() int { s := redisdump.Host{ Host: c.Host, Port: c.Port, - Password: url.QueryEscape(redisPassword), + Password: redisPassword, TlsHandler: tlshandler, } diff --git a/vendor/github.com/mediocregopher/radix/v3/.travis.yml b/vendor/github.com/mediocregopher/radix/v3/.travis.yml deleted file mode 100644 index 6640ac0..0000000 --- a/vendor/github.com/mediocregopher/radix/v3/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ ---- -language: go -go: - - "1.13.x" - - "1.14.x" - -services: - - redis-server - -before_install: - # update to latest version of redis - - sudo apt-get install -y redis-server - - GO111MODULE=on go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.24.0 - -script: - # for some reason go test -v -race ./... doesn't work on travis, so use this - - go list ./... | xargs -n1 go test -v -race - - golangci-lint run -D errcheck -E goimports -E golint -E misspell -E stylecheck -E unconvert - -after_failure: - - tail -n100 ./*.log diff --git a/vendor/github.com/mediocregopher/radix/v3/CHANGELOG.md b/vendor/github.com/mediocregopher/radix/v3/CHANGELOG.md index e800aae..1a04e28 100644 --- a/vendor/github.com/mediocregopher/radix/v3/CHANGELOG.md +++ b/vendor/github.com/mediocregopher/radix/v3/CHANGELOG.md @@ -1,5 +1,24 @@ Changelog from v3.0.1 and up. Prior changes don't have a changelog. +# v3.8.0 + +**New** + +* Add `PoolMaxLifetime` option for `Pool`. (PR #294) + +**Fixes And Improvements** + +* Switched to using `errors` package, rather than `golang.org/x/xerrors`. (PR + #300) + +* Switch to using Github Actions from travis. (PR #300) + +* Fixed IPv6 addresses breaking `Cluster`. (Issue #288) + +# v3.7.1 + +* Release the RLock in `Sentinel`'s `Do`. (PR #272) + # v3.7.0 **New** diff --git a/vendor/github.com/mediocregopher/radix/v3/README.md b/vendor/github.com/mediocregopher/radix/v3/README.md index 766602e..4ad0763 100644 --- a/vendor/github.com/mediocregopher/radix/v3/README.md +++ b/vendor/github.com/mediocregopher/radix/v3/README.md @@ -1,49 +1,43 @@ # Radix -[![Build Status](https://travis-ci.org/mediocregopher/radix.svg)](https://travis-ci.org/mediocregopher/radix) - -[![Go v3 reference](https://pkg.go.dev/badge/github.com/mediocregopher/radix/v3.svg)](https://pkg.go.dev/github.com/mediocregopher/radix/v3#section-documentation) (v3) - -[![Go v4 reference](https://pkg.go.dev/badge/github.com/mediocregopher/radix/v4.svg)](https://pkg.go.dev/github.com/mediocregopher/radix/v4#section-documentation) (v4, still in beta) - Radix is a full-featured [Redis][redis] client for Go. See the reference links -above for documentation and general usage examples. +below for documentation and general usage examples. -## Versions +**[v3 Documentation](https://pkg.go.dev/github.com/mediocregopher/radix/v3#section-documentation)** -There are two major versions of radix being supported at the moment: +**[v4 Documentation](https://pkg.go.dev/github.com/mediocregopher/radix/v4#section-documentation)** -* v3 is the more mature version, and is still being actively supported at the - moment. +## Features -* v4 is in beta, but is essentially stable. You can view the v4 - [CHANGELOG][v4changelog] to see what changed between the two versions. The - biggest selling point is that connection sharing (called "implicit pipelining" - in v3) now works with Pipeline and EvalScript, plus many other performance and - usability enhancements. +* Standard print-like API which supports **all current and future redis commands**. -[v4changelog]: https://github.com/mediocregopher/radix/blob/v4/CHANGELOG.md +* Connection pool which uses **connection sharing** to minimize system calls. -## Features +* Full support for [Sentinel][sentinel] and [Cluster][cluster]. + +* Helpers for [EVAL][eval], [SCAN][scan], [Streams][stream], and [Pipelining][pipelining]. -* Standard print-like API which supports all current and future redis commands. +* Support for [pubsub][pubsub], as well as persistent pubsub wherein if a + connection is lost a new one transparently replaces it. -* Support for using an io.Reader as a command argument and writing responses to - an io.Writer, as well as marshaling/unmarshaling command arguments from - structs. +* API design allows for custom implementations of nearly anything. + +## Versions -* Connection pooling, which takes advantage of implicit pipelining to reduce - system calls. +There are two major versions of radix being supported: -* Helpers for [EVAL][eval], [SCAN][scan], and manual [pipelining][pipelining]. +* v3 is the more mature version, but lacks the polished API of v4. v3 is only accepting bug fixes at this point. + +* v4 has feature parity with v3 and more! The biggest selling points are: -* Support for [pubsub][pubsub], as well as persistent pubsub wherein if a - connection is lost a new one transparently replaces it. + * More polished API. + * Full [RESP3][resp3] support. + * Support for [context.Context][context] on all blocking operations. + * Connection sharing (called "implicit pipelining" in v3) now works with Pipeline and EvalScript. -* Full support for [sentinel][sentinel] and [cluster][cluster]. + View the [CHANGELOG][v4changelog] for more details. -* Nearly all important types are interfaces, allowing for custom implementations - of nearly anything. +[v4changelog]: https://github.com/mediocregopher/radix/blob/v4/CHANGELOG.md ## Installation and Usage @@ -66,11 +60,6 @@ to support others prior to those two. ## Benchmarks -(When reading these it should be noted that radixv4 has not been totally -optimized for performance. It still performs well compared to v3 and other -drivers and is quite usable, but there is some work left which can be done, -specifically around its `Conn` implementation.) - Benchmarks were run in as close to a "real" environment as possible. Two GCE instances were booted up, one hosting the redis server with 2vCPUs, the other running the benchmarks (found in the `bench` directory) with 16vCPUs. @@ -159,7 +148,6 @@ BenchmarkDrivers/serial/no_pipeline/large_kv/redispipe_pause0-16 BenchmarkDrivers/serial/no_pipeline/large_kv/go-redis-16 236379 225677 ns/op 13976 B/op 14 allocs/op ``` - [bench results]: https://github.com/mediocregopher/radix/blob/v4/bench/bench_results.txt ## Copyright and licensing @@ -168,12 +156,14 @@ Unless otherwise noted, the source files are distributed under the *MIT License* found in the LICENSE.txt file. [redis]: http://redis.io -[godoc]: https://godoc.org/github.com/mediocregopher/radix [eval]: https://redis.io/commands/eval [scan]: https://redis.io/commands/scan +[stream]: https://redis.io/topics/streams-intro [pipelining]: https://redis.io/topics/pipelining [pubsub]: https://redis.io/topics/pubsub [sentinel]: http://redis.io/topics/sentinel [cluster]: http://redis.io/topics/cluster-spec [module]: https://github.com/golang/go/wiki/Modules [redispipe]: https://github.com/joomcode/redispipe +[context]: https://pkg.go.dev/context +[resp3]: https://github.com/antirez/RESP3/blob/master/spec.md diff --git a/vendor/github.com/mediocregopher/radix/v3/action.go b/vendor/github.com/mediocregopher/radix/v3/action.go index 554757e..ac83266 100644 --- a/vendor/github.com/mediocregopher/radix/v3/action.go +++ b/vendor/github.com/mediocregopher/radix/v3/action.go @@ -11,10 +11,9 @@ import ( "strings" "sync" - "golang.org/x/xerrors" - "github.com/mediocregopher/radix/v3/resp" "github.com/mediocregopher/radix/v3/resp/resp2" + "golang.org/x/xerrors" ) // Action performs a task using a Conn. @@ -141,7 +140,7 @@ type cmdAction struct { flatArgs []interface{} } -// BREAM: Benchmarks Rule Everything Around Me +// BREAM: Benchmarks Rule Everything Around Me. var cmdActionPool sync.Pool func getCmdAction() *cmdAction { @@ -305,6 +304,8 @@ type MaybeNil struct { func (mn *MaybeNil) UnmarshalRESP(br *bufio.Reader) error { var rm resp2.RawMessage err := rm.UnmarshalRESP(br) + mn.Nil = false + mn.EmptyArray = false switch { case err != nil: return err @@ -373,7 +374,7 @@ type EvalScript struct { } // NewEvalScript initializes a EvalScript instance. numKeys corresponds to the -// number of arguments which will be keys when Cmd is called +// number of arguments which will be keys when Cmd is called. func NewEvalScript(numKeys int, script string) EvalScript { sumRaw := sha1.Sum([]byte(script)) sum := hex.EncodeToString(sumRaw[:]) @@ -556,13 +557,13 @@ func (p pipeline) drain(c Conn, n int) { func decodeErr(cmd CmdAction, err error) error { c, ok := cmd.(*cmdAction) if ok { - return xerrors.Errorf( + return fmt.Errorf( "failed to decode pipeline CmdAction '%v' with keys %v: %w", c.cmd, c.Keys(), err) } - return xerrors.Errorf( + return fmt.Errorf( "failed to decode pipeline CmdAction '%v': %w", cmd, err) @@ -608,7 +609,7 @@ type withConn struct { // // NOTE that WithConn only ensures all inner Actions are performed on the same // Conn, it doesn't make them transactional. Use MULTI/WATCH/EXEC within a -// WithConn for transactions, or use EvalScript +// WithConn for transactions, or use EvalScript. func WithConn(key string, fn func(Conn) error) Action { return &withConn{[1]string{key}, fn} } diff --git a/vendor/github.com/mediocregopher/radix/v3/cluster.go b/vendor/github.com/mediocregopher/radix/v3/cluster.go index 6c032cb..5c47271 100644 --- a/vendor/github.com/mediocregopher/radix/v3/cluster.go +++ b/vendor/github.com/mediocregopher/radix/v3/cluster.go @@ -1,13 +1,14 @@ package radix import ( + "fmt" "reflect" "strings" "sync" "sync/atomic" "time" - errors "golang.org/x/xerrors" + "errors" "github.com/mediocregopher/radix/v3/resp" "github.com/mediocregopher/radix/v3/resp/resp2" @@ -65,7 +66,7 @@ type clusterOpts struct { } // ClusterOpt is an optional behavior which can be applied to the NewCluster -// function to effect a Cluster's behavior +// function to effect a Cluster's behavior. type ClusterOpt func(*clusterOpts) // ClusterPoolFunc tells the Cluster to use the given ClientFunc when creating @@ -123,7 +124,7 @@ func ClusterOnInitAllowUnavailable(initAllowUnavailable bool) ClusterOpt { // Cluster contains all information about a redis cluster needed to interact // with it, including a set of pools to each of its instances. All methods on -// Cluster are thread-safe +// Cluster are thread-safe. type Cluster struct { // Atomic fields must be at the beginning of the struct since they must be // correctly aligned or else access may cause panics on 32-bit architectures @@ -246,7 +247,7 @@ func assertKeysSlot(keys []string) error { if !ok { ok = true } else if slot != thisSlot { - return errors.Errorf("keys %q and %q do not belong to the same slot", prevKey, key) + return fmt.Errorf("keys %q and %q do not belong to the same slot", prevKey, key) } prevKey = key slot = thisSlot @@ -254,7 +255,7 @@ func assertKeysSlot(keys []string) error { return nil } -// may return nil, nil if no pool for the addr +// may return nil, nil if no pool for the addr. func (c *Cluster) rpool(addr string) (Client, error) { c.l.RLock() defer c.l.RUnlock() @@ -295,7 +296,7 @@ func (c *Cluster) Client(addr string) (Client, error) { } // if addr is "" returns a random pool. If addr is given but there's no pool for -// it one will be created on-the-fly +// it one will be created on-the-fly. func (c *Cluster) pool(addr string) (Client, error) { p, err := c.rpool(addr) if p != nil || err != nil { @@ -348,7 +349,7 @@ func (c *Cluster) getTopo(p Client) (ClusterTopo, error) { // Sync will synchronize the Cluster with the actual cluster, making new pools // to new instances and removing ones from instances no longer in the cluster. // This will be called periodically automatically, but you can manually call it -// at any time as well +// at any time as well. func (c *Cluster) Sync() error { p, err := c.pool("") if err != nil { @@ -423,7 +424,7 @@ func (c *Cluster) sync(p Client, silenceFlag bool) error { if silenceFlag { continue } else { - return errors.Errorf("error connecting to %s: %w", t.Addr, err) + return fmt.Errorf("error connecting to %s: %w", t.Addr, err) } } } @@ -727,7 +728,7 @@ func (c *Cluster) doInner(a Action, addr, key string, ask bool, attempts int) er msgParts := strings.Split(msg, " ") if len(msgParts) < 3 { - return errors.Errorf("malformed MOVED/ASK error %q", msg) + return fmt.Errorf("malformed MOVED/ASK error %q", msg) } ogAddr, addr := addr, msgParts[2] diff --git a/vendor/github.com/mediocregopher/radix/v3/cluster_crc16.go b/vendor/github.com/mediocregopher/radix/v3/cluster_crc16.go index f9dbc94..110f72e 100644 --- a/vendor/github.com/mediocregopher/radix/v3/cluster_crc16.go +++ b/vendor/github.com/mediocregopher/radix/v3/cluster_crc16.go @@ -42,7 +42,7 @@ var tab = [256]uint16{ const numSlots = 16384 // CRC16 returns checksum for a given set of bytes based on the crc algorithm -// defined for hashing redis keys in a cluster setup +// defined for hashing redis keys in a cluster setup. func CRC16(buf []byte) uint16 { crc := uint16(0) for _, b := range buf { @@ -53,7 +53,7 @@ func CRC16(buf []byte) uint16 { } // ClusterSlot returns the slot number the key belongs to in any redis cluster, -// taking into account key hash tags +// taking into account key hash tags. func ClusterSlot(key []byte) uint16 { if start := bytes.Index(key, []byte("{")); start >= 0 { if end := bytes.Index(key[start+1:], []byte("}")); end > 0 { diff --git a/vendor/github.com/mediocregopher/radix/v3/cluster_topo.go b/vendor/github.com/mediocregopher/radix/v3/cluster_topo.go index ef94e21..b105a0a 100644 --- a/vendor/github.com/mediocregopher/radix/v3/cluster_topo.go +++ b/vendor/github.com/mediocregopher/radix/v3/cluster_topo.go @@ -2,12 +2,11 @@ package radix import ( "bufio" + "fmt" "io" "net" "sort" - errors "golang.org/x/xerrors" - "github.com/mediocregopher/radix/v3/resp" "github.com/mediocregopher/radix/v3/resp/resp2" ) @@ -29,7 +28,7 @@ type ClusterNode struct { type ClusterTopo []ClusterNode // MarshalRESP implements the resp.Marshaler interface, and will marshal the -// ClusterTopo in the same format as the return from CLUSTER SLOTS +// ClusterTopo in the same format as the return from CLUSTER SLOTS. func (tt ClusterTopo) MarshalRESP(w io.Writer) error { m := map[[2]uint16]topoSlotSet{} for _, t := range tt { @@ -65,7 +64,7 @@ func (tt ClusterTopo) MarshalRESP(w io.Writer) error { // UnmarshalRESP implements the resp.Unmarshaler interface, but only supports // unmarshaling the return from CLUSTER SLOTS. The unmarshaled nodes will be -// sorted before they are returned +// sorted before they are returned. func (tt *ClusterTopo) UnmarshalRESP(br *bufio.Reader) error { var arrHead resp2.ArrayHeader if err := arrHead.UnmarshalRESP(br); err != nil { @@ -117,7 +116,7 @@ func (tt ClusterTopo) sort() { } -// Map returns the topology as a mapping of node address to its ClusterNode +// Map returns the topology as a mapping of node address to its ClusterNode. func (tt ClusterTopo) Map() map[string]ClusterNode { m := make(map[string]ClusterNode, len(tt)) for _, t := range tt { @@ -127,7 +126,7 @@ func (tt ClusterTopo) Map() map[string]ClusterNode { } // Primaries returns a ClusterTopo instance containing only the primary nodes -// from the ClusterTopo being called on +// from the ClusterTopo being called on. func (tt ClusterTopo) Primaries() ClusterTopo { mtt := make(ClusterTopo, 0, len(tt)) for _, node := range tt { @@ -139,7 +138,7 @@ func (tt ClusterTopo) Primaries() ClusterTopo { } // we only use this type during unmarshalling, the topo Unmarshal method will -// convert these into ClusterNodes +// convert these into ClusterNodes. type topoSlotSet struct { slots [2]uint16 nodes []ClusterNode @@ -191,7 +190,7 @@ func (tss *topoSlotSet) UnmarshalRESP(br *bufio.Reader) error { if err := (resp2.Any{I: &nodeStrs}).UnmarshalRESP(br); err != nil { return err } else if len(nodeStrs) < 2 { - return errors.Errorf("malformed node array: %#v", nodeStrs) + return fmt.Errorf("malformed node array: %#v", nodeStrs) } ip, port := nodeStrs[0], nodeStrs[1] var id string @@ -200,7 +199,7 @@ func (tss *topoSlotSet) UnmarshalRESP(br *bufio.Reader) error { } node := ClusterNode{ - Addr: ip + ":" + port, + Addr: net.JoinHostPort(ip, port), ID: id, Slots: [][2]uint16{tss.slots}, } diff --git a/vendor/github.com/mediocregopher/radix/v3/conn.go b/vendor/github.com/mediocregopher/radix/v3/conn.go index 7eb9b9c..08bd360 100644 --- a/vendor/github.com/mediocregopher/radix/v3/conn.go +++ b/vendor/github.com/mediocregopher/radix/v3/conn.go @@ -16,7 +16,7 @@ import ( // reads/writes data using the redis resp protocol. // // A Conn can be used directly as a Client, but in general you probably want to -// use a *Pool instead +// use a *Pool instead. type Conn interface { // The Do method of a Conn is _not_ expected to be thread-safe with the // other methods of Conn, and merely calls the Action's Run method with @@ -197,14 +197,20 @@ type timeoutConn struct { func (tc *timeoutConn) Read(b []byte) (int, error) { if tc.readTimeout > 0 { - tc.Conn.SetReadDeadline(time.Now().Add(tc.readTimeout)) + err := tc.Conn.SetReadDeadline(time.Now().Add(tc.readTimeout)) + if err != nil { + return 0, err + } } return tc.Conn.Read(b) } func (tc *timeoutConn) Write(b []byte) (int, error) { if tc.writeTimeout > 0 { - tc.Conn.SetWriteDeadline(time.Now().Add(tc.writeTimeout)) + err := tc.Conn.SetWriteDeadline(time.Now().Add(tc.writeTimeout)) + if err != nil { + return 0, err + } } return tc.Conn.Write(b) } diff --git a/vendor/github.com/mediocregopher/radix/v3/go.mod b/vendor/github.com/mediocregopher/radix/v3/go.mod deleted file mode 100644 index bb9be39..0000000 --- a/vendor/github.com/mediocregopher/radix/v3/go.mod +++ /dev/null @@ -1,10 +0,0 @@ -module github.com/mediocregopher/radix/v3 - -require ( - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/stretchr/testify v1.2.2 - golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 -) - -go 1.13 diff --git a/vendor/github.com/mediocregopher/radix/v3/go.sum b/vendor/github.com/mediocregopher/radix/v3/go.sum deleted file mode 100644 index 86807e8..0000000 --- a/vendor/github.com/mediocregopher/radix/v3/go.sum +++ /dev/null @@ -1,8 +0,0 @@ -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/vendor/github.com/mediocregopher/radix/v3/internal/bytesutil/bytesutil.go b/vendor/github.com/mediocregopher/radix/v3/internal/bytesutil/bytesutil.go index f15da03..ef48252 100644 --- a/vendor/github.com/mediocregopher/radix/v3/internal/bytesutil/bytesutil.go +++ b/vendor/github.com/mediocregopher/radix/v3/internal/bytesutil/bytesutil.go @@ -9,8 +9,9 @@ import ( "strconv" "sync" + "errors" + "github.com/mediocregopher/radix/v3/resp" - errors "golang.org/x/xerrors" ) // AnyIntToInt64 converts a value of any of Go's integer types (signed and unsigned) into a signed int64. @@ -102,7 +103,7 @@ func ParseUint(b []byte) (uint64, error) { for i, c := range b { if c < '0' || c > '9' { - return 0, errors.Errorf("invalid character %c at position %d in parseUint", c, i) + return 0, fmt.Errorf("invalid character %c at position %d in parseUint", c, i) } n *= 10 @@ -130,7 +131,7 @@ func BufferedBytesDelim(br *bufio.Reader) ([]byte, error) { if err != nil { return nil, err } else if len(b) < 2 || b[len(b)-2] != '\r' { - return nil, errors.Errorf("malformed resp %q", b) + return nil, fmt.Errorf("malformed resp %q", b) } return b[:len(b)-2], err } diff --git a/vendor/github.com/mediocregopher/radix/v3/pool.go b/vendor/github.com/mediocregopher/radix/v3/pool.go index 1a13c05..d83f283 100644 --- a/vendor/github.com/mediocregopher/radix/v3/pool.go +++ b/vendor/github.com/mediocregopher/radix/v3/pool.go @@ -7,19 +7,19 @@ import ( "sync/atomic" "time" - errors "golang.org/x/xerrors" + "errors" "github.com/mediocregopher/radix/v3/resp" "github.com/mediocregopher/radix/v3/trace" ) -// ErrPoolEmpty is used by Pools created using the PoolOnEmptyErrAfter option +// ErrPoolEmpty is used by Pools created using the PoolOnEmptyErrAfter option. var ErrPoolEmpty = errors.New("connection pool is empty") var errPoolFull = errors.New("connection pool is full") // ioErrConn is a Conn which tracks the last net.Error which was seen either -// during an Encode call or a Decode call +// during an Encode call or a Decode call. type ioErrConn struct { Conn @@ -28,10 +28,13 @@ type ioErrConn struct { // level error, e.g. a timeout, disconnect, etc... Close is automatically // called on the client when it encounters a critical network error lastIOErr error + + // conn create time + createdAt time.Time } func newIOErrConn(c Conn) *ioErrConn { - return &ioErrConn{Conn: c} + return &ioErrConn{Conn: c, createdAt: time.Now()} } func (ioc *ioErrConn) Encode(m resp.Marshaler) error { @@ -39,7 +42,7 @@ func (ioc *ioErrConn) Encode(m resp.Marshaler) error { return ioc.lastIOErr } err := ioc.Conn.Encode(m) - if nerr, _ := err.(net.Error); nerr != nil { + if nerr := net.Error(nil); errors.As(err, &nerr) { ioc.lastIOErr = err } return err @@ -50,7 +53,7 @@ func (ioc *ioErrConn) Decode(m resp.Unmarshaler) error { return ioc.lastIOErr } err := ioc.Conn.Decode(m) - if nerr, _ := err.(net.Error); nerr != nil { + if nerr := net.Error(nil); errors.As(err, &nerr) { ioc.lastIOErr = err } else if err != nil && !errors.As(err, new(resp.ErrDiscarded)) { ioc.lastIOErr = err @@ -67,6 +70,13 @@ func (ioc *ioErrConn) Close() error { return ioc.Conn.Close() } +func (ioc *ioErrConn) expired(timeout time.Duration) bool { + if timeout <= 0 { + return false + } + return time.Since(ioc.createdAt) >= timeout +} + //////////////////////////////////////////////////////////////////////////////// type poolOpts struct { @@ -81,12 +91,23 @@ type poolOpts struct { pipelineLimit int pipelineWindow time.Duration pt trace.PoolTrace + maxLifetime time.Duration // maximum amount of time a connection may be reused } // PoolOpt is an optional behavior which can be applied to the NewPool function -// to effect a Pool's behavior +// to effect a Pool's behavior. type PoolOpt func(*poolOpts) +// PoolMaxLifetime sets the maximum amount of time a connection may be reused. +// Expired connections may be closed lazily before reuse. +// +// If d <= 0, connections are not closed due to a connection's age. +func PoolMaxLifetime(d time.Duration) PoolOpt { + return func(po *poolOpts) { + po.maxLifetime = d + } +} + // PoolConnFunc tells the Pool to use the given ConnFunc when creating new // Conns to its redis instance. The ConnFunc can be used to set timeouts, // perform AUTH, or even use custom Conn implementations. @@ -370,7 +391,11 @@ func NewPool(network, addr string, size int, opts ...PoolOpt) (*Pool, error) { ) } if p.opts.pingInterval > 0 && size > 0 { - p.atIntervalDo(p.opts.pingInterval, func() { p.Do(Cmd(nil, "PING")) }) + p.atIntervalDo(p.opts.pingInterval, func() { + // don't worry about the return value, the whole point is to find + // erroring connections + _ = p.Do(Cmd(nil, "PING")) + }) } if p.opts.refillInterval > 0 && size > 0 { p.atIntervalDo(p.opts.refillInterval, p.doRefill) @@ -463,7 +488,7 @@ func (p *Pool) doRefill() { ioc, err := p.newConn(trace.PoolConnCreatedReasonRefill) if err == nil { p.put(ioc) - } else if err != errPoolFull { + } else if errors.Is(err, errPoolFull) { p.err(err) } } @@ -498,13 +523,22 @@ func (p *Pool) doOverflowDrain() { func (p *Pool) getExisting() (*ioErrConn, error) { // Fast-path if the pool is not empty. Return error if pool has been closed. - select { - case ioc, ok := <-p.pool: - if !ok { - return nil, errClientClosed + for { + select { + case ioc, ok := <-p.pool: + if !ok { + return nil, errClientClosed + } + if ioc.expired(p.opts.maxLifetime) { + ioc.Close() + p.traceConnClosed(trace.PoolConnClosedReasonConnExpired) + atomic.AddInt64(&p.totalConns, -1) + continue + } + return ioc, nil + default: } - return ioc, nil - default: + break // Failed to get from pool, so jump out to conduct for the next move. } if p.opts.onEmptyWait == 0 { @@ -522,14 +556,22 @@ func (p *Pool) getExisting() (*ioErrConn, error) { tc = t.C } - select { - case ioc, ok := <-p.pool: - if !ok { - return nil, errClientClosed + for { + select { + case ioc, ok := <-p.pool: + if !ok { + return nil, errClientClosed + } + if ioc.expired(p.opts.maxLifetime) { + ioc.Close() + p.traceConnClosed(trace.PoolConnClosedReasonConnExpired) + atomic.AddInt64(&p.totalConns, -1) + continue + } + return ioc, nil + case <-tc: + return nil, p.opts.errOnEmpty } - return ioc, nil - case <-tc: - return nil, p.opts.errOnEmpty } } @@ -547,12 +589,15 @@ func (p *Pool) get() (*ioErrConn, error) { // discarded. func (p *Pool) put(ioc *ioErrConn) bool { p.l.RLock() + var expired bool if ioc.lastIOErr == nil && !p.closed { - select { - case p.pool <- ioc: - p.l.RUnlock() - return true - default: + if expired = ioc.expired(p.opts.maxLifetime); !expired { + select { + case p.pool <- ioc: + p.l.RUnlock() + return true + default: + } } } p.l.RUnlock() @@ -560,7 +605,11 @@ func (p *Pool) put(ioc *ioErrConn) bool { // the pool might close here, but that's fine, because all that's happening // at this point is that the connection is being closed ioc.Close() - p.traceConnClosed(trace.PoolConnClosedReasonPoolFull) + if expired { + p.traceConnClosed(trace.PoolConnClosedReasonConnExpired) + } else { + p.traceConnClosed(trace.PoolConnClosedReasonPoolFull) + } atomic.AddInt64(&p.totalConns, -1) return false } @@ -616,7 +665,7 @@ func (p *Pool) NumAvailConns() int { return len(p.pool) } -// Close implements the Close method of the Client +// Close implements the Close method of the Client. func (p *Pool) Close() error { p.l.Lock() if p.closed { diff --git a/vendor/github.com/mediocregopher/radix/v3/pubsub.go b/vendor/github.com/mediocregopher/radix/v3/pubsub.go index fe708b1..c15e2f8 100644 --- a/vendor/github.com/mediocregopher/radix/v3/pubsub.go +++ b/vendor/github.com/mediocregopher/radix/v3/pubsub.go @@ -8,13 +8,13 @@ import ( "sync" "time" - errors "golang.org/x/xerrors" + "errors" "github.com/mediocregopher/radix/v3/resp" "github.com/mediocregopher/radix/v3/resp/resp2" ) -// PubSubMessage describes a message being published to a subscribed channel +// PubSubMessage describes a message being published to a subscribed channel. type PubSubMessage struct { Type string // "message" or "pmessage" Pattern string // will be set if Type is "pmessage" @@ -48,7 +48,7 @@ func (m PubSubMessage) MarshalRESP(w io.Writer) error { var errNotPubSubMessage = errors.New("message is not a PubSubMessage") -// UnmarshalRESP implements the Unmarshaler interface +// UnmarshalRESP implements the Unmarshaler interface. func (m *PubSubMessage) UnmarshalRESP(br *bufio.Reader) error { // This method will fully consume the message on the wire, regardless of if // it is a PubSubMessage or not. If it is not then errNotPubSubMessage is @@ -309,21 +309,23 @@ func (c *pubSubConn) spin() { for { var m PubSubMessage err := c.conn.Decode(&m) - if nerr, ok := err.(net.Error); ok && nerr.Timeout() { + if nerr := net.Error(nil); errors.As(err, &nerr) && nerr.Timeout() { c.testEvent("timeout") continue } else if errors.Is(err, errNotPubSubMessage) { c.cmdResCh <- nil continue } else if err != nil { - c.closeInner(err) + // closeInner returns the error from closing the Conn, which doesn't + // really matter here. + _ = c.closeInner(err) return } c.publish(m) } } -// NOTE cmdL _must_ be held to use do +// NOTE cmdL _must_ be held to use do. func (c *pubSubConn) do(exp int, cmd string, args ...string) error { rcmd := Cmd(nil, cmd, args...) if err := c.conn.Encode(rcmd); err != nil { diff --git a/vendor/github.com/mediocregopher/radix/v3/pubsub_persistent.go b/vendor/github.com/mediocregopher/radix/v3/pubsub_persistent.go index dffbb79..1eba969 100644 --- a/vendor/github.com/mediocregopher/radix/v3/pubsub_persistent.go +++ b/vendor/github.com/mediocregopher/radix/v3/pubsub_persistent.go @@ -136,7 +136,7 @@ func PersistentPubSub(network, addr string, connFn ConnFunc) PubSubConn { return p } -// refresh only returns an error if the connection could not be made +// refresh only returns an error if the connection could not be made. func (p *persistentPubSub) refresh() error { if p.curr != nil { p.curr.Close() diff --git a/vendor/github.com/mediocregopher/radix/v3/pubsub_stub.go b/vendor/github.com/mediocregopher/radix/v3/pubsub_stub.go index d2c266e..0adc603 100644 --- a/vendor/github.com/mediocregopher/radix/v3/pubsub_stub.go +++ b/vendor/github.com/mediocregopher/radix/v3/pubsub_stub.go @@ -6,7 +6,7 @@ import ( "strings" "sync" - errors "golang.org/x/xerrors" + "errors" "github.com/mediocregopher/radix/v3/resp" "github.com/mediocregopher/radix/v3/resp/resp2" diff --git a/vendor/github.com/mediocregopher/radix/v3/radix.go b/vendor/github.com/mediocregopher/radix/v3/radix.go index b0909ba..a251607 100644 --- a/vendor/github.com/mediocregopher/radix/v3/radix.go +++ b/vendor/github.com/mediocregopher/radix/v3/radix.go @@ -163,7 +163,7 @@ package radix import ( - errors "golang.org/x/xerrors" + "errors" ) var errClientClosed = errors.New("client is closed") diff --git a/vendor/github.com/mediocregopher/radix/v3/resp/resp2/resp.go b/vendor/github.com/mediocregopher/radix/v3/resp/resp2/resp.go index 48edff9..482679c 100644 --- a/vendor/github.com/mediocregopher/radix/v3/resp/resp2/resp.go +++ b/vendor/github.com/mediocregopher/radix/v3/resp/resp2/resp.go @@ -16,7 +16,7 @@ import ( "strconv" "sync" - errors "golang.org/x/xerrors" + "errors" "github.com/mediocregopher/radix/v3/internal/bytesutil" "github.com/mediocregopher/radix/v3/resp" @@ -128,12 +128,12 @@ func assertBufferedPrefix(br *bufio.Reader, pref []byte) error { //////////////////////////////////////////////////////////////////////////////// -// SimpleString represents the simple string type in the RESP protocol +// SimpleString represents the simple string type in the RESP protocol. type SimpleString struct { S string } -// MarshalRESP implements the Marshaler method +// MarshalRESP implements the Marshaler method. func (ss SimpleString) MarshalRESP(w io.Writer) error { scratch := bytesutil.GetBytes() *scratch = append(*scratch, SimpleStringPrefix...) @@ -144,7 +144,7 @@ func (ss SimpleString) MarshalRESP(w io.Writer) error { return err } -// UnmarshalRESP implements the Unmarshaler method +// UnmarshalRESP implements the Unmarshaler method. func (ss *SimpleString) UnmarshalRESP(br *bufio.Reader) error { if err := assertBufferedPrefix(br, SimpleStringPrefix); err != nil { return err @@ -163,7 +163,7 @@ func (ss *SimpleString) UnmarshalRESP(br *bufio.Reader) error { // Error represents an error type in the RESP protocol. Note that this only // represents an actual error message being read/written on the stream, it is // separate from network or parsing errors. An E value of nil is equivalent to -// an empty error string +// an empty error string. type Error struct { E error } @@ -172,7 +172,7 @@ func (e Error) Error() string { return e.E.Error() } -// MarshalRESP implements the Marshaler method +// MarshalRESP implements the Marshaler method. func (e Error) MarshalRESP(w io.Writer) error { scratch := bytesutil.GetBytes() *scratch = append(*scratch, ErrorPrefix...) @@ -185,7 +185,7 @@ func (e Error) MarshalRESP(w io.Writer) error { return err } -// UnmarshalRESP implements the Unmarshaler method +// UnmarshalRESP implements the Unmarshaler method. func (e *Error) UnmarshalRESP(br *bufio.Reader) error { if err := assertBufferedPrefix(br, ErrorPrefix); err != nil { return err @@ -208,12 +208,12 @@ func (e Error) As(target interface{}) bool { //////////////////////////////////////////////////////////////////////////////// -// Int represents an int type in the RESP protocol +// Int represents an int type in the RESP protocol. type Int struct { I int64 } -// MarshalRESP implements the Marshaler method +// MarshalRESP implements the Marshaler method. func (i Int) MarshalRESP(w io.Writer) error { scratch := bytesutil.GetBytes() *scratch = append(*scratch, IntPrefix...) @@ -224,7 +224,7 @@ func (i Int) MarshalRESP(w io.Writer) error { return err } -// UnmarshalRESP implements the Unmarshaler method +// UnmarshalRESP implements the Unmarshaler method. func (i *Int) UnmarshalRESP(br *bufio.Reader) error { if err := assertBufferedPrefix(br, IntPrefix); err != nil { return err @@ -247,7 +247,7 @@ type BulkStringBytes struct { MarshalNotNil bool } -// MarshalRESP implements the Marshaler method +// MarshalRESP implements the Marshaler method. func (b BulkStringBytes) MarshalRESP(w io.Writer) error { if b.B == nil && !b.MarshalNotNil { _, err := w.Write(nilBulkString) @@ -264,7 +264,7 @@ func (b BulkStringBytes) MarshalRESP(w io.Writer) error { return err } -// UnmarshalRESP implements the Unmarshaler method +// UnmarshalRESP implements the Unmarshaler method. func (b *BulkStringBytes) UnmarshalRESP(br *bufio.Reader) error { if err := assertBufferedPrefix(br, BulkStringPrefix); err != nil { return err @@ -299,7 +299,7 @@ type BulkString struct { S string } -// MarshalRESP implements the Marshaler method +// MarshalRESP implements the Marshaler method. func (b BulkString) MarshalRESP(w io.Writer) error { scratch := bytesutil.GetBytes() *scratch = append(*scratch, BulkStringPrefix...) @@ -344,12 +344,12 @@ func (b *BulkString) UnmarshalRESP(br *bufio.Reader) error { // BulkReader is like BulkString, but it only supports marshalling and will use // the given LenReader to do so. If LR is nil then the nil bulk string RESP will -// be written +// be written. type BulkReader struct { LR resp.LenReader } -// MarshalRESP implements the Marshaler method +// MarshalRESP implements the Marshaler method. func (b BulkReader) MarshalRESP(w io.Writer) error { if b.LR == nil { _, err := w.Write(nilBulkString) @@ -381,12 +381,12 @@ func (b BulkReader) MarshalRESP(w io.Writer) error { // protocol. It does not actually encompass any elements itself, it only // declares how many elements will come after it. // -// An N of -1 may also be used to indicate a nil response, as per the RESP spec +// An N of -1 may also be used to indicate a nil response, as per the RESP spec. type ArrayHeader struct { N int } -// MarshalRESP implements the Marshaler method +// MarshalRESP implements the Marshaler method. func (ah ArrayHeader) MarshalRESP(w io.Writer) error { scratch := bytesutil.GetBytes() *scratch = append(*scratch, ArrayPrefix...) @@ -397,7 +397,7 @@ func (ah ArrayHeader) MarshalRESP(w io.Writer) error { return err } -// UnmarshalRESP implements the Unmarshaler method +// UnmarshalRESP implements the Unmarshaler method. func (ah *ArrayHeader) UnmarshalRESP(br *bufio.Reader) error { if err := assertBufferedPrefix(br, ArrayPrefix); err != nil { return err @@ -415,7 +415,7 @@ type Array struct { A []resp.Marshaler } -// MarshalRESP implements the Marshaler method +// MarshalRESP implements the Marshaler method. func (a Array) MarshalRESP(w io.Writer) error { ah := ArrayHeader{N: len(a.A)} if a.A == nil { @@ -538,7 +538,7 @@ func numElems(vv reflect.Value) int { case reflect.Ptr: return numElems(reflect.Indirect(vv)) case reflect.Slice, reflect.Array: - // TODO does []rune need extra support here? + // NOTE []rune might need extra support here if vv.Type() == byteSliceT { return 1 } @@ -599,7 +599,7 @@ func numElemsStruct(vv reflect.Value, flat bool) int { return c } -// MarshalRESP implements the Marshaler method +// MarshalRESP implements the Marshaler method. func (a Any) MarshalRESP(w io.Writer) error { marshalBulk := func(b []byte) error { bs := BulkStringBytes{B: b, MarshalNotNil: a.MarshalBulkString} @@ -727,7 +727,7 @@ func (a Any) MarshalRESP(w io.Writer) error { return a.marshalStruct(w, vv, false) default: - return errors.Errorf("could not marshal value of type %T", a.I) + return fmt.Errorf("could not marshal value of type %T", a.I) } return err @@ -794,7 +794,7 @@ func saneDefault(prefix byte) interface{} { // which has a simple string or bulk string (the vast majority of them) is going // to go through one of these. var ( - // RawMessage.UnmarshalInto also uses these + // RawMessage.UnmarshalInto also uses these. byteReaderPool = sync.Pool{ New: func() interface{} { return bytes.NewReader(nil) @@ -807,7 +807,7 @@ var ( } ) -// UnmarshalRESP implements the Unmarshaler method +// UnmarshalRESP implements the Unmarshaler method. func (a Any) UnmarshalRESP(br *bufio.Reader) error { // if I is itself an Unmarshaler just hit that directly if u, ok := a.I.(resp.Unmarshaler); ok { @@ -833,7 +833,10 @@ func (a Any) UnmarshalRESP(br *bufio.Reader) error { return nil } - br.Discard(1) + if _, err = br.Discard(1); err != nil { + return err + } + b, err = bytesutil.BufferedBytesDelim(br) if err != nil { return err @@ -879,7 +882,7 @@ func (a Any) UnmarshalRESP(br *bufio.Reader) error { byteReaderPool.Put(reader) return err default: - return errors.Errorf("unknown type prefix %q", b[0]) + return fmt.Errorf("unknown type prefix %q", b[0]) } } @@ -962,7 +965,7 @@ func (a Any) unmarshalSingle(body io.Reader, n int) error { break } err = resp.ErrDiscarded{ - Err: errors.Errorf("can't unmarshal into %T, message body was: %q", a.I, *scratch), + Err: fmt.Errorf("can't unmarshal into %T, message body was: %q", a.I, *scratch), } bytesutil.PutBytes(scratch) } @@ -992,7 +995,7 @@ func (a Any) unmarshalArray(br *bufio.Reader, l int64) error { v := reflect.ValueOf(a.I) if v.Kind() != reflect.Ptr { err := resp.ErrDiscarded{ - Err: errors.Errorf("can't unmarshal array into %T", a.I), + Err: fmt.Errorf("can't unmarshal array into %T", a.I), } return discardArrayAfterErr(br, int(l), err) } @@ -1068,12 +1071,35 @@ func (a Any) unmarshalArray(br *bufio.Reader, l int64) error { var field BulkStringBytes for i := 0; i < size; i += 2 { - if err := field.UnmarshalRESP(br); err != nil { - return discardArrayAfterErr(br, int(l)-i-1, err) + + var structField structField + var ok bool + + prefix, err := br.Peek(1) + switch { + case err != nil: + return discardArrayAfterErr(br, int(l)-i, err) + + case bytes.Equal(prefix, SimpleStringPrefix): + var field SimpleString + if err := field.UnmarshalRESP(br); err != nil { + return discardArrayAfterErr(br, int(l)-i-1, err) + } + structField, ok = structFields[field.S] + + case bytes.Equal(prefix, BulkStringPrefix): + if err := field.UnmarshalRESP(br); err != nil { + return discardArrayAfterErr(br, int(l)-i-1, err) + } + structField, ok = structFields[string(field.B)] // no allocation, since Go 1.3 + + default: + var err error = errUnexpectedPrefix{Prefix: prefix, ExpectedPrefix: BulkStringPrefix} + err = resp.ErrDiscarded{Err: err} + return discardArrayAfterErr(br, int(l)-i, err) } var vv reflect.Value - structField, ok := structFields[string(field.B)] // no allocation, since Go 1.3 if ok { vv = getStructField(v, structField.indices) } @@ -1083,10 +1109,7 @@ func (a Any) unmarshalArray(br *bufio.Reader, l int64) error { if err := (Any{}).UnmarshalRESP(br); err != nil { return discardArrayAfterErr(br, int(l)-i-2, err) } - continue - } - - if err := (Any{I: vv.Interface()}).UnmarshalRESP(br); err != nil { + } else if err := (Any{I: vv.Interface()}).UnmarshalRESP(br); err != nil { return discardArrayAfterErr(br, int(l)-i-2, err) } } @@ -1094,7 +1117,7 @@ func (a Any) unmarshalArray(br *bufio.Reader, l int64) error { return nil default: - err := resp.ErrDiscarded{Err: errors.Errorf("cannot decode redis array into %v", v.Type())} + err := resp.ErrDiscarded{Err: fmt.Errorf("cannot decode redis array into %v", v.Type())} return discardArrayAfterErr(br, int(l), err) } } @@ -1130,7 +1153,7 @@ type structField struct { indices []int } -// encoding/json uses a similar pattern for unmarshaling into structs +// encoding/json uses a similar pattern for unmarshaling into structs. var structFieldsCache sync.Map // aka map[reflect.Type]map[string]structField func getStructFields(t reflect.Type) map[string]structField { @@ -1220,13 +1243,13 @@ func getStructField(v reflect.Value, ii []int) reflect.Value { // read into the RawMessage's bytes. type RawMessage []byte -// MarshalRESP implements the Marshaler method +// MarshalRESP implements the Marshaler method. func (rm RawMessage) MarshalRESP(w io.Writer) error { _, err := w.Write(rm) return err } -// UnmarshalRESP implements the Unmarshaler method +// UnmarshalRESP implements the Unmarshaler method. func (rm *RawMessage) UnmarshalRESP(br *bufio.Reader) error { *rm = (*rm)[:0] return rm.unmarshal(br) @@ -1270,7 +1293,7 @@ func (rm *RawMessage) unmarshal(br *bufio.Reader) error { case ErrorPrefix[0], SimpleStringPrefix[0], IntPrefix[0]: return nil default: - return errors.Errorf("unknown type prefix %q", b[0]) + return fmt.Errorf("unknown type prefix %q", b[0]) } } diff --git a/vendor/github.com/mediocregopher/radix/v3/resp/util.go b/vendor/github.com/mediocregopher/radix/v3/resp/util.go index 829fb8c..60dffd6 100644 --- a/vendor/github.com/mediocregopher/radix/v3/resp/util.go +++ b/vendor/github.com/mediocregopher/radix/v3/resp/util.go @@ -17,7 +17,7 @@ type lenReader struct { } // NewLenReader wraps an existing io.Reader whose length is known so that it -// implements LenReader +// implements LenReader. func NewLenReader(r io.Reader, l int64) LenReader { return &lenReader{r: r, l: l} } diff --git a/vendor/github.com/mediocregopher/radix/v3/scanner.go b/vendor/github.com/mediocregopher/radix/v3/scanner.go index f5a8eca..c282517 100644 --- a/vendor/github.com/mediocregopher/radix/v3/scanner.go +++ b/vendor/github.com/mediocregopher/radix/v3/scanner.go @@ -5,7 +5,7 @@ import ( "strconv" "strings" - errors "golang.org/x/xerrors" + "errors" "github.com/mediocregopher/radix/v3/resp/resp2" ) @@ -68,7 +68,7 @@ func (o ScanOpts) cmd(rcv interface{}, cursor string) CmdAction { return Cmd(rcv, cmdStr, args...) } -// ScanAllKeys is a shortcut ScanOpts which can be used to scan all keys +// ScanAllKeys is a shortcut ScanOpts which can be used to scan all keys. var ScanAllKeys = ScanOpts{ Command: "SCAN", } diff --git a/vendor/github.com/mediocregopher/radix/v3/sentinel.go b/vendor/github.com/mediocregopher/radix/v3/sentinel.go index 53f18a6..9d0b9f6 100644 --- a/vendor/github.com/mediocregopher/radix/v3/sentinel.go +++ b/vendor/github.com/mediocregopher/radix/v3/sentinel.go @@ -1,12 +1,11 @@ package radix import ( + "fmt" "net" "sync" "sync/atomic" "time" - - errors "golang.org/x/xerrors" ) type sentinelOpts struct { @@ -50,7 +49,7 @@ func SentinelPoolFunc(pf ClientFunc) SentinelOpt { // creates a new Client to the new primary // // * Keeps track of other sentinels in the cluster, and uses them if the -// currently connected one becomes unreachable +// currently connected one becomes unreachable. // type Sentinel struct { so sentinelOpts @@ -148,7 +147,9 @@ func NewSentinel(primaryName string, sentinelAddrs []string, opts ...SentinelOpt sc.pconn = PersistentPubSub("", "", func(_, _ string) (Conn, error) { return sc.dialSentinel() }) - sc.pconn.Subscribe(sc.pconnCh, "switch-master") + + // persistent pubsub doesn't return errors + _ = sc.pconn.Subscribe(sc.pconnCh, "switch-master") sc.closeWG.Add(1) go sc.spin() @@ -201,8 +202,9 @@ func (sc *Sentinel) dialSentinel() (Conn, error) { // Action will likely fail and return an error. func (sc *Sentinel) Do(a Action) error { sc.l.RLock() - defer sc.l.RUnlock() - return sc.clients[sc.primAddr].Do(a) + client := sc.clients[sc.primAddr] + sc.l.RUnlock() + return client.Do(a) } // DoSecondary is like Do but executes the Action on a random replica if possible. @@ -329,16 +331,16 @@ func (sc *Sentinel) Close() error { return closeErr } -// cmd should be the command called which generated m +// cmd should be the command called which generated m. func sentinelMtoAddr(m map[string]string, cmd string) (string, error) { if m["ip"] == "" || m["port"] == "" { - return "", errors.Errorf("malformed %q response: %#v", cmd, m) + return "", fmt.Errorf("malformed %q response: %#v", cmd, m) } return net.JoinHostPort(m["ip"], m["port"]), nil } // given a connection to a sentinel, ensures that the Clients currently being -// held agrees with what the sentinel thinks they should be +// held agrees with what the sentinel thinks they should be. func (sc *Sentinel) ensureClients(conn Conn) error { var primM map[string]string var secMM []map[string]string @@ -366,7 +368,7 @@ func (sc *Sentinel) ensureClients(conn Conn) error { return sc.setClients(newPrimAddr, newClients) } -// all values of newClients should be nil +// all values of newClients should be nil. func (sc *Sentinel) setClients(newPrimAddr string, newClients map[string]Client) error { newClients[newPrimAddr] = nil var toClose []Client @@ -429,7 +431,7 @@ func (sc *Sentinel) setClients(newPrimAddr string, newClients map[string]Client) } // annoyingly the SENTINEL SENTINELS command doesn't return _this_ -// sentinel instance, only the others it knows about for that primary +// sentinel instance, only the others it knows about for that primary. func (sc *Sentinel) ensureSentinelAddrs(conn Conn) error { var mm []map[string]string err := conn.Do(Cmd(&mm, "SENTINEL", "SENTINELS", sc.name)) @@ -493,7 +495,9 @@ func (sc *Sentinel) innerSpin() error { } else if err := sc.ensureClients(conn); err != nil { return err } - sc.pconn.Ping() + + // persistent pubsub methods don't return an error + _ = sc.pconn.Ping() // the tests want to know when the client state has been updated due to // a switch-master event diff --git a/vendor/github.com/mediocregopher/radix/v3/stream.go b/vendor/github.com/mediocregopher/radix/v3/stream.go index 8749051..084a18b 100644 --- a/vendor/github.com/mediocregopher/radix/v3/stream.go +++ b/vendor/github.com/mediocregopher/radix/v3/stream.go @@ -9,7 +9,7 @@ import ( "strconv" "time" - errors "golang.org/x/xerrors" + "errors" "github.com/mediocregopher/radix/v3/internal/bytesutil" "github.com/mediocregopher/radix/v3/resp" @@ -265,18 +265,23 @@ type StreamReaderOpts struct { Count int } -// StreamReader allows reading from on or more streams, always returning newer entries +// StreamReader allows reading from on or more streams, always returning newer +// entries. type StreamReader interface { - // Err returns any error that happened while calling Next or nil if no error happened. + + // Err returns any error that happened while calling Next or nil if no error + // happened. // - // Once Err returns a non-nil error, all successive calls will return the same error. + // Once Err returns a non-nil error, all successive calls will return the + // same error. Err() error // Next returns new entries for any of the configured streams. // // The returned slice is only valid until the next call to Next. // - // If there was an error, ok will be false. Otherwise, even if no entries were read, ok will be true. + // If there was an error, ok will be false. Otherwise, even if no entries + // were read, ok will be true. // // If there was an error, all future calls to Next will return ok == false. Next() (stream string, entries []StreamEntry, ok bool) diff --git a/vendor/github.com/mediocregopher/radix/v3/stub.go b/vendor/github.com/mediocregopher/radix/v3/stub.go index 72c51f8..2f63383 100644 --- a/vendor/github.com/mediocregopher/radix/v3/stub.go +++ b/vendor/github.com/mediocregopher/radix/v3/stub.go @@ -7,7 +7,7 @@ import ( "sync" "time" - errors "golang.org/x/xerrors" + "errors" "github.com/mediocregopher/radix/v3/resp" "github.com/mediocregopher/radix/v3/resp/resp2" diff --git a/vendor/github.com/mediocregopher/radix/v3/timer.go b/vendor/github.com/mediocregopher/radix/v3/timer.go index 348e21d..a32a469 100644 --- a/vendor/github.com/mediocregopher/radix/v3/timer.go +++ b/vendor/github.com/mediocregopher/radix/v3/timer.go @@ -5,7 +5,7 @@ import ( "time" ) -// global pool of *time.Timer's +// global pool of *time.Timer's. var timerPool sync.Pool // get returns a timer that completes after the given duration. diff --git a/vendor/github.com/mediocregopher/radix/v3/trace/pool.go b/vendor/github.com/mediocregopher/radix/v3/trace/pool.go index b3622bf..b5600a9 100644 --- a/vendor/github.com/mediocregopher/radix/v3/trace/pool.go +++ b/vendor/github.com/mediocregopher/radix/v3/trace/pool.go @@ -88,6 +88,10 @@ const ( // PoolConnClosedReasonPoolFull indicates a connection was closed due to // the Pool already being full. See The radix.PoolOnFullClose options. PoolConnClosedReasonPoolFull PoolConnClosedReason = "pool full" + + // PoolConnClosedReasonConnExpired indicates a connection was closed because + // the connection was expired. See The radix.PoolMaxLifetime options. + PoolConnClosedReasonConnExpired PoolConnClosedReason = "conn expired" ) // PoolConnClosed is passed into the PoolTrace.ConnClosed callback whenever the diff --git a/vendor/golang.org/x/xerrors/fmt.go b/vendor/golang.org/x/xerrors/fmt.go index 829862d..74c1c93 100644 --- a/vendor/golang.org/x/xerrors/fmt.go +++ b/vendor/golang.org/x/xerrors/fmt.go @@ -7,14 +7,10 @@ package xerrors import ( "fmt" "strings" - "unicode" - "unicode/utf8" "golang.org/x/xerrors/internal" ) -const percentBangString = "%!" - // Errorf formats according to a format specifier and returns the string as a // value that satisfies error. // @@ -22,71 +18,29 @@ const percentBangString = "%!" // formatted with additional detail enabled. If the last argument is an error // the returned error's Format method will return it if the format string ends // with ": %s", ": %v", or ": %w". If the last argument is an error and the -// format string ends with ": %w", the returned error implements an Unwrap -// method returning it. -// -// If the format specifier includes a %w verb with an error operand in a -// position other than at the end, the returned error will still implement an -// Unwrap method returning the operand, but the error's Format method will not -// return the wrapped error. -// -// It is invalid to include more than one %w verb or to supply it with an -// operand that does not implement the error interface. The %w verb is otherwise -// a synonym for %v. +// format string ends with ": %w", the returned error implements Wrapper +// with an Unwrap method returning it. func Errorf(format string, a ...interface{}) error { + err, wrap := lastError(format, a) format = formatPlusW(format) - // Support a ": %[wsv]" suffix, which works well with xerrors.Formatter. - wrap := strings.HasSuffix(format, ": %w") - idx, format2, ok := parsePercentW(format) - percentWElsewhere := !wrap && idx >= 0 - if !percentWElsewhere && (wrap || strings.HasSuffix(format, ": %s") || strings.HasSuffix(format, ": %v")) { - err := errorAt(a, len(a)-1) - if err == nil { - return &noWrapError{fmt.Sprintf(format, a...), nil, Caller(1)} - } - // TODO: this is not entirely correct. The error value could be - // printed elsewhere in format if it mixes numbered with unnumbered - // substitutions. With relatively small changes to doPrintf we can - // have it optionally ignore extra arguments and pass the argument - // list in its entirety. - msg := fmt.Sprintf(format[:len(format)-len(": %s")], a[:len(a)-1]...) - frame := Frame{} - if internal.EnableTrace { - frame = Caller(1) - } - if wrap { - return &wrapError{msg, err, frame} - } - return &noWrapError{msg, err, frame} - } - // Support %w anywhere. - // TODO: don't repeat the wrapped error's message when %w occurs in the middle. - msg := fmt.Sprintf(format2, a...) - if idx < 0 { - return &noWrapError{msg, nil, Caller(1)} - } - err := errorAt(a, idx) - if !ok || err == nil { - // Too many %ws or argument of %w is not an error. Approximate the Go - // 1.13 fmt.Errorf message. - return &noWrapError{fmt.Sprintf("%sw(%s)", percentBangString, msg), nil, Caller(1)} + if err == nil { + return &noWrapError{fmt.Sprintf(format, a...), nil, Caller(1)} } + + // TODO: this is not entirely correct. The error value could be + // printed elsewhere in format if it mixes numbered with unnumbered + // substitutions. With relatively small changes to doPrintf we can + // have it optionally ignore extra arguments and pass the argument + // list in its entirety. + msg := fmt.Sprintf(format[:len(format)-len(": %s")], a[:len(a)-1]...) frame := Frame{} if internal.EnableTrace { frame = Caller(1) } - return &wrapError{msg, err, frame} -} - -func errorAt(args []interface{}, i int) error { - if i < 0 || i >= len(args) { - return nil + if wrap { + return &wrapError{msg, err, frame} } - err, ok := args[i].(error) - if !ok { - return nil - } - return err + return &noWrapError{msg, err, frame} } // formatPlusW is used to avoid the vet check that will barf at %w. @@ -94,56 +48,24 @@ func formatPlusW(s string) string { return s } -// Return the index of the only %w in format, or -1 if none. -// Also return a rewritten format string with %w replaced by %v, and -// false if there is more than one %w. -// TODO: handle "%[N]w". -func parsePercentW(format string) (idx int, newFormat string, ok bool) { - // Loosely copied from golang.org/x/tools/go/analysis/passes/printf/printf.go. - idx = -1 - ok = true - n := 0 - sz := 0 - var isW bool - for i := 0; i < len(format); i += sz { - if format[i] != '%' { - sz = 1 - continue - } - // "%%" is not a format directive. - if i+1 < len(format) && format[i+1] == '%' { - sz = 2 - continue - } - sz, isW = parsePrintfVerb(format[i:]) - if isW { - if idx >= 0 { - ok = false - } else { - idx = n - } - // "Replace" the last character, the 'w', with a 'v'. - p := i + sz - 1 - format = format[:p] + "v" + format[p+1:] - } - n++ +func lastError(format string, a []interface{}) (err error, wrap bool) { + wrap = strings.HasSuffix(format, ": %w") + if !wrap && + !strings.HasSuffix(format, ": %s") && + !strings.HasSuffix(format, ": %v") { + return nil, false } - return idx, format, ok -} -// Parse the printf verb starting with a % at s[0]. -// Return how many bytes it occupies and whether the verb is 'w'. -func parsePrintfVerb(s string) (int, bool) { - // Assume only that the directive is a sequence of non-letters followed by a single letter. - sz := 0 - var r rune - for i := 1; i < len(s); i += sz { - r, sz = utf8.DecodeRuneInString(s[i:]) - if unicode.IsLetter(r) { - return i + sz, r == 'w' - } + if len(a) == 0 { + return nil, false } - return len(s), false + + err, ok := a[len(a)-1].(error) + if !ok { + return nil, false + } + + return err, wrap } type noWrapError struct { diff --git a/vendor/golang.org/x/xerrors/go.mod b/vendor/golang.org/x/xerrors/go.mod deleted file mode 100644 index 870d4f6..0000000 --- a/vendor/golang.org/x/xerrors/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module golang.org/x/xerrors - -go 1.11 diff --git a/vendor/modules.txt b/vendor/modules.txt index 805e53b..14a095d 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,15 +1,11 @@ -# github.com/mediocregopher/radix/v3 v3.7.0 -## explicit +# github.com/mediocregopher/radix/v3 v3.8.0 +## explicit; go 1.13 github.com/mediocregopher/radix/v3 github.com/mediocregopher/radix/v3/internal/bytesutil github.com/mediocregopher/radix/v3/resp github.com/mediocregopher/radix/v3/resp/resp2 github.com/mediocregopher/radix/v3/trace -# github.com/stretchr/testify v1.4.0 -## explicit -# golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 -## explicit +# golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 +## explicit; go 1.11 golang.org/x/xerrors golang.org/x/xerrors/internal -# gopkg.in/yaml.v2 v2.2.7 -## explicit