diff --git a/vendor/github.com/thehowl/go-osuapi/osubool.go b/vendor/github.com/thehowl/go-osuapi/osubool.go index 7e83b6e..9835c13 100644 --- a/vendor/github.com/thehowl/go-osuapi/osubool.go +++ b/vendor/github.com/thehowl/go-osuapi/osubool.go @@ -9,7 +9,7 @@ type OsuBool bool // UnmarshalJSON converts `"0"` to false and `"1"` to true. func (o *OsuBool) UnmarshalJSON(data []byte) error { - if string(data) == `"0"` { + if string(data) == `0` { *o = false return nil } diff --git a/vendor/gopkg.in/redis.v5/Makefile b/vendor/gopkg.in/redis.v5/Makefile index 4562692..50fdc55 100644 --- a/vendor/gopkg.in/redis.v5/Makefile +++ b/vendor/gopkg.in/redis.v5/Makefile @@ -15,4 +15,5 @@ testdata/redis: wget -qO- https://github.com/antirez/redis/archive/unstable.tar.gz | tar xvz --strip-components=1 -C $@ testdata/redis/src/redis-server: testdata/redis + sed -i 's/libjemalloc.a/libjemalloc.a -lrt/g' $ 0 { go c.reaper(opt.IdleCheckFrequency) @@ -366,10 +374,11 @@ func NewClusterClient(opt *ClusterOptions) *ClusterClient { func (c *ClusterClient) state() *clusterState { v := c._state.Load() - if v == nil { - return nil + if v != nil { + return v.(*clusterState) } - return v.(*clusterState) + c.lazyReloadSlots() + return nil } func (c *ClusterClient) cmdSlotAndNode(state *clusterState, cmd Cmder) (int, *clusterNode, error) { @@ -397,10 +406,12 @@ func (c *ClusterClient) cmdSlotAndNode(state *clusterState, cmd Cmder) (int, *cl } func (c *ClusterClient) Watch(fn func(*Tx) error, keys ...string) error { + state := c.state() + var node *clusterNode var err error - if len(keys) > 0 { - node, err = c.state().slotMasterNode(hashtag.Slot(keys[0])) + if state != nil && len(keys) > 0 { + node, err = state.slotMasterNode(hashtag.Slot(keys[0])) } else { node, err = c.nodes.Random() } @@ -463,8 +474,9 @@ func (c *ClusterClient) Process(cmd Cmder) error { var addr string moved, ask, addr = internal.IsMovedError(err) if moved || ask { - if slot >= 0 { - master, _ := c.state().slotMasterNode(slot) + state := c.state() + if state != nil && slot >= 0 { + master, _ := state.slotMasterNode(slot) if moved && (master == nil || master.Client.getAddr() != addr) { c.lazyReloadSlots() } @@ -523,7 +535,7 @@ func (c *ClusterClient) ForEachNode(fn func(client *Client) error) error { func (c *ClusterClient) ForEachMaster(fn func(client *Client) error) error { state := c.state() if state == nil { - return nil + return errNilClusterState } var wg sync.WaitGroup @@ -564,12 +576,13 @@ func (c *ClusterClient) ForEachMaster(fn func(client *Client) error) error { // PoolStats returns accumulated connection pool stats. func (c *ClusterClient) PoolStats() *PoolStats { + var acc PoolStats + nodes, err := c.nodes.All() if err != nil { - return nil + return &acc } - var acc PoolStats for _, node := range nodes { s := node.Client.connPool.Stats() acc.Requests += s.Requests @@ -585,37 +598,46 @@ func (c *ClusterClient) lazyReloadSlots() { if !atomic.CompareAndSwapUint32(&c.reloading, 0, 1) { return } + go func() { - c.reloadSlots() + for i := 0; i < 1000; i++ { + state, err := c.reloadSlots() + if err == pool.ErrClosed { + break + } + if err == nil { + c._state.Store(state) + break + } + time.Sleep(time.Millisecond) + } + + time.Sleep(3 * time.Second) atomic.StoreUint32(&c.reloading, 0) }() } -func (c *ClusterClient) reloadSlots() { - for i := 0; i < 10; i++ { - node, err := c.nodes.Random() - if err != nil { - return - } - - if c.cmds == nil { - cmds, err := node.Client.Command().Result() - if err == nil { - c.cmds = cmds - } - } - - slots, err := node.Client.ClusterSlots().Result() - if err != nil { - continue - } - - state, err := newClusterState(c.nodes, slots) - if err != nil { - return - } - c._state.Store(state) +func (c *ClusterClient) reloadSlots() (*clusterState, error) { + node, err := c.nodes.Random() + if err != nil { + return nil, err } + + // TODO: fix race + if c.cmds == nil { + cmds, err := node.Client.Command().Result() + if err != nil { + return nil, err + } + c.cmds = cmds + } + + slots, err := node.Client.ClusterSlots().Result() + if err != nil { + return nil, err + } + + return newClusterState(c.nodes, slots) } // reaper closes idle connections to the cluster. @@ -789,8 +811,13 @@ func (c *ClusterClient) txPipelineExec(cmds []Cmder) error { return err } + state := c.state() + if state == nil { + return errNilClusterState + } + for slot, cmds := range cmdsMap { - node, err := c.state().slotMasterNode(slot) + node, err := state.slotMasterNode(slot) if err != nil { setCmdsErr(cmds, err) continue diff --git a/vendor/gopkg.in/redis.v5/command.go b/vendor/gopkg.in/redis.v5/command.go index 2adb629..8ad982b 100644 --- a/vendor/gopkg.in/redis.v5/command.go +++ b/vendor/gopkg.in/redis.v5/command.go @@ -58,7 +58,7 @@ func writeCmd(cn *pool.Conn, cmds ...Cmder) error { } } - _, err := cn.NetConn.Write(cn.Wb.Bytes()) + _, err := cn.Write(cn.Wb.Bytes()) return err } @@ -445,7 +445,7 @@ func (cmd *StringCmd) Result() (string, error) { } func (cmd *StringCmd) Bytes() ([]byte, error) { - return []byte(cmd.val), cmd.err + return cmd.val, cmd.err } func (cmd *StringCmd) Int64() (int64, error) { @@ -542,6 +542,10 @@ func (cmd *StringSliceCmd) String() string { return cmdString(cmd, cmd.val) } +func (cmd *StringSliceCmd) ScanSlice(container interface{}) error { + return proto.ScanSlice(cmd.Val(), container) +} + func (cmd *StringSliceCmd) readReply(cn *pool.Conn) error { var v interface{} v, cmd.err = cn.Rd.ReadArrayReply(stringSliceParser) diff --git a/vendor/gopkg.in/redis.v5/commands.go b/vendor/gopkg.in/redis.v5/commands.go index 2e50cda..b96da7b 100644 --- a/vendor/gopkg.in/redis.v5/commands.go +++ b/vendor/gopkg.in/redis.v5/commands.go @@ -50,14 +50,16 @@ type Cmdable interface { Unlink(keys ...string) *IntCmd Dump(key string) *StringCmd Exists(key string) *BoolCmd + // TODO: merge with Exists in v6 + ExistsMulti(keys ...string) *IntCmd Expire(key string, expiration time.Duration) *BoolCmd ExpireAt(key string, tm time.Time) *BoolCmd Keys(pattern string) *StringSliceCmd Migrate(host, port, key string, db int64, timeout time.Duration) *StatusCmd Move(key string, db int64) *BoolCmd - ObjectRefCount(keys ...string) *IntCmd - ObjectEncoding(keys ...string) *StringCmd - ObjectIdleTime(keys ...string) *DurationCmd + ObjectRefCount(key string) *IntCmd + ObjectEncoding(key string) *StringCmd + ObjectIdleTime(key string) *DurationCmd Persist(key string) *BoolCmd PExpire(key string, expiration time.Duration) *BoolCmd PExpireAt(key string, tm time.Time) *BoolCmd @@ -170,6 +172,7 @@ type Cmdable interface { ZRem(key string, members ...interface{}) *IntCmd ZRemRangeByRank(key string, start, stop int64) *IntCmd ZRemRangeByScore(key, min, max string) *IntCmd + ZRemRangeByLex(key, min, max string) *IntCmd ZRevRange(key string, start, stop int64) *StringSliceCmd ZRevRangeWithScores(key string, start, stop int64) *ZSliceCmd ZRevRangeByScore(key string, opt ZRangeBy) *StringSliceCmd @@ -270,6 +273,13 @@ func (c *cmdable) Ping() *StatusCmd { return cmd } +func (c *cmdable) Wait(numSlaves int, timeout time.Duration) *IntCmd { + + cmd := NewIntCmd("wait", numSlaves, int(timeout/time.Millisecond)) + c.process(cmd) + return cmd +} + func (c *cmdable) Quit() *StatusCmd { panic("not implemented") } @@ -316,6 +326,17 @@ func (c *cmdable) Exists(key string) *BoolCmd { return cmd } +func (c *cmdable) ExistsMulti(keys ...string) *IntCmd { + args := make([]interface{}, 1+len(keys)) + args[0] = "exists" + for i, key := range keys { + args[1+i] = key + } + cmd := NewIntCmd(args...) + c.process(cmd) + return cmd +} + func (c *cmdable) Expire(key string, expiration time.Duration) *BoolCmd { cmd := NewBoolCmd("expire", key, formatSec(expiration)) c.process(cmd) @@ -354,38 +375,20 @@ func (c *cmdable) Move(key string, db int64) *BoolCmd { return cmd } -func (c *cmdable) ObjectRefCount(keys ...string) *IntCmd { - args := make([]interface{}, 2+len(keys)) - args[0] = "object" - args[1] = "refcount" - for i, key := range keys { - args[2+i] = key - } - cmd := NewIntCmd(args...) +func (c *cmdable) ObjectRefCount(key string) *IntCmd { + cmd := NewIntCmd("object", "refcount", key) c.process(cmd) return cmd } -func (c *cmdable) ObjectEncoding(keys ...string) *StringCmd { - args := make([]interface{}, 2+len(keys)) - args[0] = "object" - args[1] = "encoding" - for i, key := range keys { - args[2+i] = key - } - cmd := NewStringCmd(args...) +func (c *cmdable) ObjectEncoding(key string) *StringCmd { + cmd := NewStringCmd("object", "encoding", key) c.process(cmd) return cmd } -func (c *cmdable) ObjectIdleTime(keys ...string) *DurationCmd { - args := make([]interface{}, 2+len(keys)) - args[0] = "object" - args[1] = "idletime" - for i, key := range keys { - args[2+i] = key - } - cmd := NewDurationCmd(time.Second, args...) +func (c *cmdable) ObjectIdleTime(key string) *DurationCmd { + cmd := NewDurationCmd(time.Second, "object", "idletime", key) c.process(cmd) return cmd } @@ -731,6 +734,7 @@ func (c *cmdable) MSetNX(pairs ...interface{}) *BoolCmd { // Redis `SET key value [expiration]` command. // +// Use expiration for `SETEX`-like behavior. // Zero expiration means the key has no expiration time. func (c *cmdable) Set(key string, value interface{}, expiration time.Duration) *StatusCmd { args := make([]interface{}, 3, 4) @@ -1468,6 +1472,12 @@ func (c *cmdable) ZRemRangeByScore(key, min, max string) *IntCmd { return cmd } +func (c *cmdable) ZRemRangeByLex(key, min, max string) *IntCmd { + cmd := NewIntCmd("zremrangebylex", key, min, max) + c.process(cmd) + return cmd +} + func (c *cmdable) ZRevRange(key string, start, stop int64) *StringSliceCmd { cmd := NewStringSliceCmd("zrevrange", key, start, stop) c.process(cmd) diff --git a/vendor/gopkg.in/redis.v5/internal/pool/conn.go b/vendor/gopkg.in/redis.v5/internal/pool/conn.go index b716cc2..2a135ae 100644 --- a/vendor/gopkg.in/redis.v5/internal/pool/conn.go +++ b/vendor/gopkg.in/redis.v5/internal/pool/conn.go @@ -2,56 +2,77 @@ package pool import ( "net" + "sync/atomic" "time" "gopkg.in/redis.v5/internal/proto" ) -const defaultBufSize = 4096 - var noDeadline = time.Time{} type Conn struct { - NetConn net.Conn - Rd *proto.Reader - Wb *proto.WriteBuffer + netConn net.Conn + + Rd *proto.Reader + Wb *proto.WriteBuffer Inited bool - UsedAt time.Time + usedAt atomic.Value } func NewConn(netConn net.Conn) *Conn { cn := &Conn{ - NetConn: netConn, + netConn: netConn, Wb: proto.NewWriteBuffer(), - - UsedAt: time.Now(), } - cn.Rd = proto.NewReader(cn.NetConn) + cn.Rd = proto.NewReader(cn.netConn) + cn.SetUsedAt(time.Now()) return cn } +func (cn *Conn) UsedAt() time.Time { + return cn.usedAt.Load().(time.Time) +} + +func (cn *Conn) SetUsedAt(tm time.Time) { + cn.usedAt.Store(tm) +} + +func (cn *Conn) SetNetConn(netConn net.Conn) { + cn.netConn = netConn + cn.Rd.Reset(netConn) +} + func (cn *Conn) IsStale(timeout time.Duration) bool { - return timeout > 0 && time.Since(cn.UsedAt) > timeout + return timeout > 0 && time.Since(cn.UsedAt()) > timeout } func (cn *Conn) SetReadTimeout(timeout time.Duration) error { - cn.UsedAt = time.Now() + now := time.Now() + cn.SetUsedAt(now) if timeout > 0 { - return cn.NetConn.SetReadDeadline(cn.UsedAt.Add(timeout)) + return cn.netConn.SetReadDeadline(now.Add(timeout)) } - return cn.NetConn.SetReadDeadline(noDeadline) - + return cn.netConn.SetReadDeadline(noDeadline) } func (cn *Conn) SetWriteTimeout(timeout time.Duration) error { - cn.UsedAt = time.Now() + now := time.Now() + cn.SetUsedAt(now) if timeout > 0 { - return cn.NetConn.SetWriteDeadline(cn.UsedAt.Add(timeout)) + return cn.netConn.SetWriteDeadline(now.Add(timeout)) } - return cn.NetConn.SetWriteDeadline(noDeadline) + return cn.netConn.SetWriteDeadline(noDeadline) +} + +func (cn *Conn) Write(b []byte) (int, error) { + return cn.netConn.Write(b) +} + +func (cn *Conn) RemoteAddr() net.Addr { + return cn.netConn.RemoteAddr() } func (cn *Conn) Close() error { - return cn.NetConn.Close() + return cn.netConn.Close() } diff --git a/vendor/gopkg.in/redis.v5/internal/pool/pool.go b/vendor/gopkg.in/redis.v5/internal/pool/pool.go index 6a0e057..c97875f 100644 --- a/vendor/gopkg.in/redis.v5/internal/pool/pool.go +++ b/vendor/gopkg.in/redis.v5/internal/pool/pool.go @@ -19,7 +19,9 @@ var ( var timers = sync.Pool{ New: func() interface{} { - return time.NewTimer(0) + t := time.NewTimer(time.Hour) + t.Stop() + return t }, } @@ -41,7 +43,6 @@ type Pooler interface { FreeLen() int Stats() *Stats Close() error - Closed() bool } type dialer func() (net.Conn, error) @@ -96,12 +97,13 @@ func (p *ConnPool) NewConn() (*Conn, error) { func (p *ConnPool) PopFree() *Conn { timer := timers.Get().(*time.Timer) - if !timer.Reset(p.poolTimeout) { - <-timer.C - } + timer.Reset(p.poolTimeout) select { case p.queue <- struct{}{}: + if !timer.Stop() { + <-timer.C + } timers.Put(timer) case <-timer.C: timers.Put(timer) @@ -132,19 +134,20 @@ func (p *ConnPool) popFree() *Conn { // Get returns existed connection from the pool or creates a new one. func (p *ConnPool) Get() (*Conn, bool, error) { - if p.Closed() { + if p.closed() { return nil, false, ErrClosed } atomic.AddUint32(&p.stats.Requests, 1) timer := timers.Get().(*time.Timer) - if !timer.Reset(p.poolTimeout) { - <-timer.C - } + timer.Reset(p.poolTimeout) select { case p.queue <- struct{}{}: + if !timer.Stop() { + <-timer.C + } timers.Put(timer) case <-timer.C: timers.Put(timer) @@ -241,7 +244,7 @@ func (p *ConnPool) Stats() *Stats { } } -func (p *ConnPool) Closed() bool { +func (p *ConnPool) closed() bool { return atomic.LoadInt32(&p._closed) == 1 } @@ -318,7 +321,7 @@ func (p *ConnPool) reaper(frequency time.Duration) { defer ticker.Stop() for _ = range ticker.C { - if p.Closed() { + if p.closed() { break } n, err := p.ReapStaleConns() diff --git a/vendor/gopkg.in/redis.v5/internal/pool/pool_single.go b/vendor/gopkg.in/redis.v5/internal/pool/pool_single.go index 18ca616..22eaba9 100644 --- a/vendor/gopkg.in/redis.v5/internal/pool/pool_single.go +++ b/vendor/gopkg.in/redis.v5/internal/pool/pool_single.go @@ -12,10 +12,6 @@ func NewSingleConnPool(cn *Conn) *SingleConnPool { } } -func (p *SingleConnPool) First() *Conn { - return p.cn -} - func (p *SingleConnPool) Get() (*Conn, bool, error) { return p.cn, false, nil } @@ -49,7 +45,3 @@ func (p *SingleConnPool) Stats() *Stats { func (p *SingleConnPool) Close() error { return nil } - -func (p *SingleConnPool) Closed() bool { - return false -} diff --git a/vendor/gopkg.in/redis.v5/internal/pool/pool_sticky.go b/vendor/gopkg.in/redis.v5/internal/pool/pool_sticky.go index d25bf99..7426cd2 100644 --- a/vendor/gopkg.in/redis.v5/internal/pool/pool_sticky.go +++ b/vendor/gopkg.in/redis.v5/internal/pool/pool_sticky.go @@ -11,7 +11,7 @@ type StickyConnPool struct { cn *Conn closed bool - mx sync.Mutex + mu sync.Mutex } var _ Pooler = (*StickyConnPool)(nil) @@ -23,16 +23,9 @@ func NewStickyConnPool(pool *ConnPool, reusable bool) *StickyConnPool { } } -func (p *StickyConnPool) First() *Conn { - p.mx.Lock() - cn := p.cn - p.mx.Unlock() - return cn -} - func (p *StickyConnPool) Get() (*Conn, bool, error) { - defer p.mx.Unlock() - p.mx.Lock() + p.mu.Lock() + defer p.mu.Unlock() if p.closed { return nil, false, ErrClosed @@ -56,14 +49,12 @@ func (p *StickyConnPool) putUpstream() (err error) { } func (p *StickyConnPool) Put(cn *Conn) error { - defer p.mx.Unlock() - p.mx.Lock() + p.mu.Lock() + defer p.mu.Unlock() + if p.closed { return ErrClosed } - if p.cn != cn { - panic("p.cn != cn") - } return nil } @@ -74,23 +65,19 @@ func (p *StickyConnPool) removeUpstream(reason error) error { } func (p *StickyConnPool) Remove(cn *Conn, reason error) error { - defer p.mx.Unlock() - p.mx.Lock() + p.mu.Lock() + defer p.mu.Unlock() + if p.closed { return nil } - if p.cn == nil { - panic("p.cn == nil") - } - if cn != nil && p.cn != cn { - panic("p.cn != cn") - } return p.removeUpstream(reason) } func (p *StickyConnPool) Len() int { - defer p.mx.Unlock() - p.mx.Lock() + p.mu.Lock() + defer p.mu.Unlock() + if p.cn == nil { return 0 } @@ -98,8 +85,9 @@ func (p *StickyConnPool) Len() int { } func (p *StickyConnPool) FreeLen() int { - defer p.mx.Unlock() - p.mx.Lock() + p.mu.Lock() + defer p.mu.Unlock() + if p.cn == nil { return 1 } @@ -111,8 +99,9 @@ func (p *StickyConnPool) Stats() *Stats { } func (p *StickyConnPool) Close() error { - defer p.mx.Unlock() - p.mx.Lock() + p.mu.Lock() + defer p.mu.Unlock() + if p.closed { return ErrClosed } @@ -128,10 +117,3 @@ func (p *StickyConnPool) Close() error { } return err } - -func (p *StickyConnPool) Closed() bool { - p.mx.Lock() - closed := p.closed - p.mx.Unlock() - return closed -} diff --git a/vendor/gopkg.in/redis.v5/internal/proto/reader.go b/vendor/gopkg.in/redis.v5/internal/proto/reader.go index ee811c8..e5dc95e 100644 --- a/vendor/gopkg.in/redis.v5/internal/proto/reader.go +++ b/vendor/gopkg.in/redis.v5/internal/proto/reader.go @@ -29,10 +29,14 @@ type Reader struct { func NewReader(rd io.Reader) *Reader { return &Reader{ src: bufio.NewReader(rd), - buf: make([]byte, 0, bufferSize), + buf: make([]byte, 4096), } } +func (r *Reader) Reset(rd io.Reader) { + r.src.Reset(rd) +} + func (p *Reader) PeekBuffered() []byte { if n := p.src.Buffered(); n != 0 { b, _ := p.src.Peek(n) @@ -42,7 +46,12 @@ func (p *Reader) PeekBuffered() []byte { } func (p *Reader) ReadN(n int) ([]byte, error) { - return readN(p.src, p.buf, n) + b, err := readN(p.src, p.buf, n) + if err != nil { + return nil, err + } + p.buf = b + return b, nil } func (p *Reader) ReadLine() ([]byte, error) { @@ -72,11 +81,11 @@ func (p *Reader) ReadReply(m MultiBulkParse) (interface{}, error) { case ErrorReply: return nil, ParseErrorReply(line) case StatusReply: - return parseStatusValue(line) + return parseStatusValue(line), nil case IntReply: return parseInt(line[1:], 10, 64) case StringReply: - return p.readBytesValue(line) + return p.readTmpBytesValue(line) case ArrayReply: n, err := parseArrayLen(line) if err != nil { @@ -111,9 +120,9 @@ func (p *Reader) ReadTmpBytesReply() ([]byte, error) { case ErrorReply: return nil, ParseErrorReply(line) case StringReply: - return p.readBytesValue(line) + return p.readTmpBytesValue(line) case StatusReply: - return parseStatusValue(line) + return parseStatusValue(line), nil default: return nil, fmt.Errorf("redis: can't parse string reply: %.100q", line) } @@ -210,7 +219,7 @@ func (p *Reader) ReadScanReply() ([]string, uint64, error) { return keys, cursor, err } -func (p *Reader) readBytesValue(line []byte) ([]byte, error) { +func (p *Reader) readTmpBytesValue(line []byte) ([]byte, error) { if isNilReply(line) { return nil, internal.Nil } @@ -297,8 +306,8 @@ func ParseErrorReply(line []byte) error { return internal.RedisError(string(line[1:])) } -func parseStatusValue(line []byte) ([]byte, error) { - return line[1:], nil +func parseStatusValue(line []byte) []byte { + return line[1:] } func parseArrayLen(line []byte) (int64, error) { diff --git a/vendor/gopkg.in/redis.v5/internal/proto/scan.go b/vendor/gopkg.in/redis.v5/internal/proto/scan.go index 67ea521..f3c75d9 100644 --- a/vendor/gopkg.in/redis.v5/internal/proto/scan.go +++ b/vendor/gopkg.in/redis.v5/internal/proto/scan.go @@ -3,6 +3,7 @@ package proto import ( "encoding" "fmt" + "reflect" "gopkg.in/redis.v5/internal" ) @@ -105,3 +106,26 @@ func Scan(b []byte, v interface{}) error { "redis: can't unmarshal %T (consider implementing BinaryUnmarshaler)", v) } } + +func ScanSlice(data []string, slice interface{}) error { + v := reflect.ValueOf(slice) + if !v.IsValid() { + return fmt.Errorf("redis: ScanSlice(nil)") + } + if v.Kind() != reflect.Ptr { + return fmt.Errorf("redis: ScanSlice(non-pointer %T)", slice) + } + v = v.Elem() + if v.Kind() != reflect.Slice { + return fmt.Errorf("redis: ScanSlice(non-slice %T)", slice) + } + + for i, s := range data { + elem := internal.SliceNextElem(v) + if err := Scan([]byte(s), elem.Addr().Interface()); err != nil { + return fmt.Errorf("redis: ScanSlice(index=%d value=%q) failed: %s", i, s, err) + } + } + + return nil +} diff --git a/vendor/gopkg.in/redis.v5/internal/proto/writebuffer.go b/vendor/gopkg.in/redis.v5/internal/proto/write_buffer.go similarity index 96% rename from vendor/gopkg.in/redis.v5/internal/proto/writebuffer.go rename to vendor/gopkg.in/redis.v5/internal/proto/write_buffer.go index 1e0f8e6..019e64c 100644 --- a/vendor/gopkg.in/redis.v5/internal/proto/writebuffer.go +++ b/vendor/gopkg.in/redis.v5/internal/proto/write_buffer.go @@ -8,11 +8,13 @@ import ( const bufferSize = 4096 -type WriteBuffer struct{ b []byte } +type WriteBuffer struct { + b []byte +} func NewWriteBuffer() *WriteBuffer { return &WriteBuffer{ - b: make([]byte, 0, bufferSize), + b: make([]byte, 0, 4096), } } diff --git a/vendor/gopkg.in/redis.v5/internal/util.go b/vendor/gopkg.in/redis.v5/internal/util.go index 0662338..520596f 100644 --- a/vendor/gopkg.in/redis.v5/internal/util.go +++ b/vendor/gopkg.in/redis.v5/internal/util.go @@ -1,5 +1,7 @@ package internal +import "reflect" + func ToLower(s string) string { if isLower(s) { return s @@ -25,3 +27,21 @@ func isLower(s string) bool { } return true } + +func SliceNextElem(v reflect.Value) reflect.Value { + if v.Len() < v.Cap() { + v.Set(v.Slice(0, v.Len()+1)) + return v.Index(v.Len() - 1) + } + + elemType := v.Type().Elem() + + if elemType.Kind() == reflect.Ptr { + elem := reflect.New(elemType.Elem()) + v.Set(reflect.Append(v, elem)) + return elem.Elem() + } + + v.Set(reflect.Append(v, reflect.Zero(elemType))) + return v.Index(v.Len() - 1) +} diff --git a/vendor/gopkg.in/redis.v5/options.go b/vendor/gopkg.in/redis.v5/options.go index a7f7fd7..bab7d4d 100644 --- a/vendor/gopkg.in/redis.v5/options.go +++ b/vendor/gopkg.in/redis.v5/options.go @@ -3,6 +3,7 @@ package redis import ( "crypto/tls" "errors" + "fmt" "net" "net/url" "strconv" @@ -151,7 +152,7 @@ func ParseURL(redisURL string) (*Options, error) { o.DB = 0 case 1: if o.DB, err = strconv.Atoi(f[0]); err != nil { - return nil, errors.New("invalid redis database number: " + err.Error()) + return nil, fmt.Errorf("invalid redis database number: %q", f[0]) } default: return nil, errors.New("invalid redis URL path: " + u.Path) diff --git a/vendor/gopkg.in/redis.v5/pipeline.go b/vendor/gopkg.in/redis.v5/pipeline.go index a0a00e2..13b29e1 100644 --- a/vendor/gopkg.in/redis.v5/pipeline.go +++ b/vendor/gopkg.in/redis.v5/pipeline.go @@ -61,8 +61,8 @@ func (c *Pipeline) discard() error { // Exec always returns list of commands and error of the first failed // command if any. func (c *Pipeline) Exec() ([]Cmder, error) { - defer c.mu.Unlock() c.mu.Lock() + defer c.mu.Unlock() if c.closed { return nil, pool.ErrClosed diff --git a/vendor/gopkg.in/redis.v5/pubsub.go b/vendor/gopkg.in/redis.v5/pubsub.go index c9205a0..6c18229 100644 --- a/vendor/gopkg.in/redis.v5/pubsub.go +++ b/vendor/gopkg.in/redis.v5/pubsub.go @@ -3,6 +3,7 @@ package redis import ( "fmt" "net" + "sync" "time" "gopkg.in/redis.v5/internal" @@ -14,7 +15,9 @@ import ( // multiple goroutines. type PubSub struct { base baseClient + cmd *Cmd + mu sync.Mutex channels []string patterns []string } @@ -95,10 +98,10 @@ func (c *PubSub) Close() error { return c.base.Close() } -func (c *PubSub) Ping(payload string) error { +func (c *PubSub) Ping(payload ...string) error { args := []interface{}{"PING"} - if payload != "" { - args = append(args, payload) + if len(payload) == 1 { + args = append(args, payload[0]) } cmd := NewCmd(args...) @@ -150,31 +153,40 @@ func (p *Pong) String() string { return "Pong" } -func (c *PubSub) newMessage(reply []interface{}) (interface{}, error) { - switch kind := reply[0].(string); kind { - case "subscribe", "unsubscribe", "psubscribe", "punsubscribe": - return &Subscription{ - Kind: kind, - Channel: reply[1].(string), - Count: int(reply[2].(int64)), - }, nil - case "message": - return &Message{ - Channel: reply[1].(string), - Payload: reply[2].(string), - }, nil - case "pmessage": - return &Message{ - Pattern: reply[1].(string), - Channel: reply[2].(string), - Payload: reply[3].(string), - }, nil - case "pong": +func (c *PubSub) newMessage(reply interface{}) (interface{}, error) { + switch reply := reply.(type) { + case string: return &Pong{ - Payload: reply[1].(string), + Payload: reply, }, nil + case []interface{}: + switch kind := reply[0].(string); kind { + case "subscribe", "unsubscribe", "psubscribe", "punsubscribe": + return &Subscription{ + Kind: kind, + Channel: reply[1].(string), + Count: int(reply[2].(int64)), + }, nil + case "message": + return &Message{ + Channel: reply[1].(string), + Payload: reply[2].(string), + }, nil + case "pmessage": + return &Message{ + Pattern: reply[1].(string), + Channel: reply[2].(string), + Payload: reply[3].(string), + }, nil + case "pong": + return &Pong{ + Payload: reply[1].(string), + }, nil + default: + return nil, fmt.Errorf("redis: unsupported pubsub message: %q", kind) + } default: - return nil, fmt.Errorf("redis: unsupported pubsub notification: %q", kind) + return nil, fmt.Errorf("redis: unsupported pubsub message: %#v", reply) } } @@ -182,7 +194,9 @@ func (c *PubSub) newMessage(reply []interface{}) (interface{}, error) { // is not received in time. This is low-level API and most clients // should use ReceiveMessage. func (c *PubSub) ReceiveTimeout(timeout time.Duration) (interface{}, error) { - cmd := NewSliceCmd() + if c.cmd == nil { + c.cmd = NewCmd() + } cn, _, err := c.conn() if err != nil { @@ -190,13 +204,13 @@ func (c *PubSub) ReceiveTimeout(timeout time.Duration) (interface{}, error) { } cn.SetReadTimeout(timeout) - err = cmd.readReply(cn) + err = c.cmd.readReply(cn) c.putConn(cn, err) if err != nil { return nil, err } - return c.newMessage(cmd.Val()) + return c.newMessage(c.cmd.Val()) } // Receive returns a message as a Subscription, Message, Pong or error. @@ -225,14 +239,14 @@ func (c *PubSub) receiveMessage(timeout time.Duration) (*Message, error) { errNum++ if errNum < 3 { if netErr, ok := err.(net.Error); ok && netErr.Timeout() { - err := c.Ping("") + err := c.Ping() if err != nil { internal.Logf("PubSub.Ping failed: %s", err) } } } else { - // 3 consequent errors - connection is bad - // and/or Redis Server is down. + // 3 consequent errors - connection is broken or + // Redis Server is down. // Sleep to not exceed max number of open connections. time.Sleep(time.Second) } @@ -256,9 +270,6 @@ func (c *PubSub) receiveMessage(timeout time.Duration) (*Message, error) { } func (c *PubSub) resubscribe() { - if c.base.closed() { - return - } if len(c.channels) > 0 { if err := c.Subscribe(c.channels...); err != nil { internal.Logf("Subscribe failed: %s", err) diff --git a/vendor/gopkg.in/redis.v5/redis.go b/vendor/gopkg.in/redis.v5/redis.go index 894294d..1ddd754 100644 --- a/vendor/gopkg.in/redis.v5/redis.go +++ b/vendor/gopkg.in/redis.v5/redis.go @@ -17,14 +17,6 @@ func SetLogger(logger *log.Logger) { internal.Logger = logger } -type baseClient struct { - connPool pool.Pooler - opt *Options - - process func(Cmder) error - onClose func() error // hook called when client is closed -} - func (c *baseClient) String() string { return fmt.Sprintf("Redis<%s db:%d>", c.getAddr(), c.opt.DB) } @@ -134,10 +126,6 @@ func (c *baseClient) cmdTimeout(cmd Cmder) time.Duration { } } -func (c *baseClient) closed() bool { - return c.connPool.Closed() -} - // Close closes the client, releasing any open resources. // // It is rare to Close a Client, as the Client is meant to be @@ -309,6 +297,13 @@ func NewClient(opt *Options) *Client { return newClient(opt, newConnPool(opt)) } +func (c *Client) copy() *Client { + c2 := new(Client) + *c2 = *c + c2.cmdable.process = c2.Process + return c2 +} + // PoolStats returns connection pool stats. func (c *Client) PoolStats() *PoolStats { s := c.connPool.Stats() diff --git a/vendor/gopkg.in/redis.v5/redis_context.go b/vendor/gopkg.in/redis.v5/redis_context.go new file mode 100644 index 0000000..bfa62bc --- /dev/null +++ b/vendor/gopkg.in/redis.v5/redis_context.go @@ -0,0 +1,35 @@ +// +build go1.7 + +package redis + +import ( + "context" + + "gopkg.in/redis.v5/internal/pool" +) + +type baseClient struct { + connPool pool.Pooler + opt *Options + + process func(Cmder) error + onClose func() error // hook called when client is closed + + ctx context.Context +} + +func (c *Client) Context() context.Context { + if c.ctx != nil { + return c.ctx + } + return context.Background() +} + +func (c *Client) WithContext(ctx context.Context) *Client { + if ctx == nil { + panic("nil context") + } + c2 := c.copy() + c2.ctx = ctx + return c2 +} diff --git a/vendor/gopkg.in/redis.v5/redis_no_context.go b/vendor/gopkg.in/redis.v5/redis_no_context.go new file mode 100644 index 0000000..78a5a63 --- /dev/null +++ b/vendor/gopkg.in/redis.v5/redis_no_context.go @@ -0,0 +1,15 @@ +// +build !go1.7 + +package redis + +import ( + "gopkg.in/redis.v5/internal/pool" +) + +type baseClient struct { + connPool pool.Pooler + opt *Options + + process func(Cmder) error + onClose func() error // hook called when client is closed +} diff --git a/vendor/gopkg.in/redis.v5/ring.go b/vendor/gopkg.in/redis.v5/ring.go index 4eb57c1..6e5f62a 100644 --- a/vendor/gopkg.in/redis.v5/ring.go +++ b/vendor/gopkg.in/redis.v5/ring.go @@ -328,8 +328,8 @@ func (c *Ring) heartbeat() { // It is rare to Close a Ring, as the Ring is meant to be long-lived // and shared between many goroutines. func (c *Ring) Close() error { - defer c.mu.Unlock() c.mu.Lock() + defer c.mu.Unlock() if c.closed { return nil diff --git a/vendor/gopkg.in/redis.v5/sentinel.go b/vendor/gopkg.in/redis.v5/sentinel.go index 2a32647..b39d365 100644 --- a/vendor/gopkg.in/redis.v5/sentinel.go +++ b/vendor/gopkg.in/redis.v5/sentinel.go @@ -162,8 +162,8 @@ func (d *sentinelFailover) Pool() *pool.ConnPool { } func (d *sentinelFailover) MasterAddr() (string, error) { - defer d.mu.Unlock() d.mu.Lock() + defer d.mu.Unlock() // Try last working sentinel. if d.sentinel != nil { @@ -258,7 +258,7 @@ func (d *sentinelFailover) discoverSentinels(sentinel *sentinelClient) { // closeOldConns closes connections to the old master after failover switch. func (d *sentinelFailover) closeOldConns(newMaster string) { // Good connections that should be put back to the pool. They - // can't be put immediately, because pool.First will return them + // can't be put immediately, because pool.PopFree will return them // again on next iteration. cnsToPut := make([]*pool.Conn, 0) @@ -267,10 +267,10 @@ func (d *sentinelFailover) closeOldConns(newMaster string) { if cn == nil { break } - if cn.NetConn.RemoteAddr().String() != newMaster { + if cn.RemoteAddr().String() != newMaster { err := fmt.Errorf( "sentinel: closing connection to the old master %s", - cn.NetConn.RemoteAddr(), + cn.RemoteAddr(), ) internal.Logf(err.Error()) d.pool.Remove(cn, err) @@ -289,8 +289,10 @@ func (d *sentinelFailover) listen(sentinel *sentinelClient) { for { if pubsub == nil { pubsub = sentinel.PubSub() + if err := pubsub.Subscribe("+switch-master"); err != nil { internal.Logf("sentinel: Subscribe failed: %s", err) + pubsub.Close() d.resetSentinel() return } diff --git a/vendor/gopkg.in/thehowl/go-osuapi.v1/osubool.go b/vendor/gopkg.in/thehowl/go-osuapi.v1/osubool.go index 7e83b6e..9835c13 100644 --- a/vendor/gopkg.in/thehowl/go-osuapi.v1/osubool.go +++ b/vendor/gopkg.in/thehowl/go-osuapi.v1/osubool.go @@ -9,7 +9,7 @@ type OsuBool bool // UnmarshalJSON converts `"0"` to false and `"1"` to true. func (o *OsuBool) UnmarshalJSON(data []byte) error { - if string(data) == `"0"` { + if string(data) == `0` { *o = false return nil } diff --git a/vendor/vendor.json b/vendor/vendor.json index be64b14..b5881b7 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -99,10 +99,10 @@ "revisionTime": "2016-10-10T15:00:23Z" }, { - "checksumSHA1": "kUH66xItMsO3QDibGHCWZHa9B3o=", + "checksumSHA1": "9ujFdggUmv6hyAgJ+Bjugh0UZAc=", "path": "github.com/thehowl/go-osuapi", - "revision": "77ef7867f23cd52e80dcf97e62447d3b36b1d26a", - "revisionTime": "2016-10-17T20:25:41Z" + "revision": "23480db9e43c9a8080cbb681ceaed855e5fca7f3", + "revisionTime": "2017-03-12T09:17:38Z" }, { "checksumSHA1": "LTOa3BADhwvT0wFCknPueQALm8I=", @@ -141,46 +141,46 @@ "revisionTime": "2017-01-10T16:23:43Z" }, { - "checksumSHA1": "4+WlWTIczvywOonXZGH34YdCf6s=", + "checksumSHA1": "OU/wHTJqhyQfyRnXMVWx1Ox06kQ=", "path": "gopkg.in/redis.v5", - "revision": "6da05abbaa03e90e5878f0ab711478698609fe96", - "revisionTime": "2017-01-13T11:52:40Z" + "revision": "a16aeec10ff407b1e7be6dd35797ccf5426ef0f0", + "revisionTime": "2017-03-04T11:38:25Z" }, { - "checksumSHA1": "MQyhe1N+NO0+uyJiEc6M2WGfb3s=", + "checksumSHA1": "efyYmNqK7vcPhXW4KXfwbdA1wr4=", "path": "gopkg.in/redis.v5/internal", - "revision": "6da05abbaa03e90e5878f0ab711478698609fe96", - "revisionTime": "2017-01-13T11:52:40Z" + "revision": "a16aeec10ff407b1e7be6dd35797ccf5426ef0f0", + "revisionTime": "2017-03-04T11:38:25Z" }, { "checksumSHA1": "2Ek4SixeRSKOX3mUiBMs3Aw+Guc=", "path": "gopkg.in/redis.v5/internal/consistenthash", - "revision": "6da05abbaa03e90e5878f0ab711478698609fe96", - "revisionTime": "2017-01-13T11:52:40Z" + "revision": "a16aeec10ff407b1e7be6dd35797ccf5426ef0f0", + "revisionTime": "2017-03-04T11:38:25Z" }, { "checksumSHA1": "rJYVKcBrwYUGl7nuuusmZGrt8mY=", "path": "gopkg.in/redis.v5/internal/hashtag", - "revision": "6da05abbaa03e90e5878f0ab711478698609fe96", - "revisionTime": "2017-01-13T11:52:40Z" + "revision": "a16aeec10ff407b1e7be6dd35797ccf5426ef0f0", + "revisionTime": "2017-03-04T11:38:25Z" }, { - "checksumSHA1": "yLZQUKNxXzwGlzfXhWC0Mwme2nw=", + "checksumSHA1": "zsH5BF9qc31R7eEEVYLsjbIigDQ=", "path": "gopkg.in/redis.v5/internal/pool", - "revision": "6da05abbaa03e90e5878f0ab711478698609fe96", - "revisionTime": "2017-01-13T11:52:40Z" + "revision": "a16aeec10ff407b1e7be6dd35797ccf5426ef0f0", + "revisionTime": "2017-03-04T11:38:25Z" }, { - "checksumSHA1": "KoSfO3h/KmlaGphIM4KzBGm65O4=", + "checksumSHA1": "EqPdu5g8NhzxQOMCvzbreTQlzVE=", "path": "gopkg.in/redis.v5/internal/proto", - "revision": "6da05abbaa03e90e5878f0ab711478698609fe96", - "revisionTime": "2017-01-13T11:52:40Z" + "revision": "a16aeec10ff407b1e7be6dd35797ccf5426ef0f0", + "revisionTime": "2017-03-04T11:38:25Z" }, { - "checksumSHA1": "IVLVpxH6lCjsiVVIl/qf8ftjXbg=", + "checksumSHA1": "va1m3wm/nxA5IEC/3r4GQeT/+Ro=", "path": "gopkg.in/thehowl/go-osuapi.v1", - "revision": "77ef7867f23cd52e80dcf97e62447d3b36b1d26a", - "revisionTime": "2016-10-17T20:25:41Z" + "revision": "23480db9e43c9a8080cbb681ceaed855e5fca7f3", + "revisionTime": "2017-03-12T09:17:38Z" }, { "checksumSHA1": "SI9tgNMlnMhxP7t6cAGuDjvoAHg=",