release v1.20

This commit is contained in:
deepzz0
2017-06-14 21:25:18 +08:00
parent 1634418a13
commit 54f5289d6b
134 changed files with 26141 additions and 18531 deletions

View File

@@ -181,7 +181,7 @@ func (p *Pool) Get() Conn {
return &pooledConnection{p: p, c: c}
}
// ActiveCount returns the number of active connections in the pool.
// ActiveCount returns the number of connections in the pool. The count includes idle connections and connections in use.
func (p *Pool) ActiveCount() int {
p.mu.Lock()
active := p.active
@@ -189,6 +189,14 @@ func (p *Pool) ActiveCount() int {
return active
}
// IdleCount returns the number of idle connections in the pool.
func (p *Pool) IdleCount() int {
p.mu.Lock()
idle := p.idle.Len()
p.mu.Unlock()
return idle
}
// Close releases the resources used by the pool.
func (p *Pool) Close() error {
p.mu.Lock()

View File

@@ -83,7 +83,7 @@ func (d *poolDialer) dial() (redis.Conn, error) {
return &poolTestConn{d: d, Conn: c}, nil
}
func (d *poolDialer) check(message string, p *redis.Pool, dialed, open int) {
func (d *poolDialer) check(message string, p *redis.Pool, dialed, open, inuse int) {
d.mu.Lock()
if d.dialed != dialed {
d.t.Errorf("%s: dialed=%d, want %d", message, d.dialed, dialed)
@@ -91,9 +91,13 @@ func (d *poolDialer) check(message string, p *redis.Pool, dialed, open int) {
if d.open != open {
d.t.Errorf("%s: open=%d, want %d", message, d.open, open)
}
if active := p.ActiveCount(); active != open {
d.t.Errorf("%s: active=%d, want %d", message, active, open)
}
if idle := p.IdleCount(); idle != open-inuse {
d.t.Errorf("%s: idle=%d, want %d", message, idle, open-inuse)
}
d.mu.Unlock()
}
@@ -113,9 +117,9 @@ func TestPoolReuse(t *testing.T) {
c2.Close()
}
d.check("before close", p, 2, 2)
d.check("before close", p, 2, 2, 0)
p.Close()
d.check("after close", p, 2, 0)
d.check("after close", p, 2, 0, 0)
}
func TestPoolMaxIdle(t *testing.T) {
@@ -137,9 +141,9 @@ func TestPoolMaxIdle(t *testing.T) {
c2.Close()
c3.Close()
}
d.check("before close", p, 12, 2)
d.check("before close", p, 12, 2, 0)
p.Close()
d.check("after close", p, 12, 0)
d.check("after close", p, 12, 0, 0)
}
func TestPoolError(t *testing.T) {
@@ -161,7 +165,7 @@ func TestPoolError(t *testing.T) {
c.Do("ERR", io.EOF)
c.Close()
d.check(".", p, 2, 0)
d.check(".", p, 2, 0, 0)
}
func TestPoolClose(t *testing.T) {
@@ -189,7 +193,7 @@ func TestPoolClose(t *testing.T) {
p.Close()
d.check("after pool close", p, 3, 1)
d.check("after pool close", p, 3, 1, 1)
if _, err := c1.Do("PING"); err == nil {
t.Errorf("expected error after connection and pool closed")
@@ -197,7 +201,7 @@ func TestPoolClose(t *testing.T) {
c3.Close()
d.check("after conn close", p, 3, 0)
d.check("after conn close", p, 3, 0, 0)
c1 = p.Get()
if _, err := c1.Do("PING"); err == nil {
@@ -222,7 +226,7 @@ func TestPoolTimeout(t *testing.T) {
c.Do("PING")
c.Close()
d.check("1", p, 1, 1)
d.check("1", p, 1, 1, 0)
now = now.Add(p.IdleTimeout)
@@ -230,7 +234,7 @@ func TestPoolTimeout(t *testing.T) {
c.Do("PING")
c.Close()
d.check("2", p, 2, 1)
d.check("2", p, 2, 1, 0)
}
func TestPoolConcurrenSendReceive(t *testing.T) {
@@ -272,7 +276,7 @@ func TestPoolBorrowCheck(t *testing.T) {
c.Do("PING")
c.Close()
}
d.check("1", p, 10, 1)
d.check("1", p, 10, 1, 0)
}
func TestPoolMaxActive(t *testing.T) {
@@ -289,7 +293,7 @@ func TestPoolMaxActive(t *testing.T) {
c2 := p.Get()
c2.Do("PING")
d.check("1", p, 2, 2)
d.check("1", p, 2, 2, 2)
c3 := p.Get()
if _, err := c3.Do("PING"); err != redis.ErrPoolExhausted {
@@ -297,9 +301,9 @@ func TestPoolMaxActive(t *testing.T) {
}
c3.Close()
d.check("2", p, 2, 2)
d.check("2", p, 2, 2, 2)
c2.Close()
d.check("3", p, 2, 2)
d.check("3", p, 2, 2, 1)
c3 = p.Get()
if _, err := c3.Do("PING"); err != nil {
@@ -307,7 +311,7 @@ func TestPoolMaxActive(t *testing.T) {
}
c3.Close()
d.check("4", p, 2, 2)
d.check("4", p, 2, 2, 1)
}
func TestPoolMonitorCleanup(t *testing.T) {
@@ -323,7 +327,7 @@ func TestPoolMonitorCleanup(t *testing.T) {
c.Send("MONITOR")
c.Close()
d.check("", p, 1, 0)
d.check("", p, 1, 0, 0)
}
func TestPoolPubSubCleanup(t *testing.T) {
@@ -456,7 +460,7 @@ func TestWaitPool(t *testing.T) {
c := p.Get()
errs := startGoroutines(p, "PING")
d.check("before close", p, 1, 1)
d.check("before close", p, 1, 1, 1)
c.Close()
timeout := time.After(2 * time.Second)
for i := 0; i < cap(errs); i++ {
@@ -469,7 +473,7 @@ func TestWaitPool(t *testing.T) {
t.Fatalf("timeout waiting for blocked goroutine %d", i)
}
}
d.check("done", p, 1, 1)
d.check("done", p, 1, 1, 0)
}
func TestWaitPoolClose(t *testing.T) {
@@ -487,7 +491,7 @@ func TestWaitPoolClose(t *testing.T) {
t.Fatal(err)
}
errs := startGoroutines(p, "PING")
d.check("before close", p, 1, 1)
d.check("before close", p, 1, 1, 1)
p.Close()
timeout := time.After(2 * time.Second)
for i := 0; i < cap(errs); i++ {
@@ -504,7 +508,7 @@ func TestWaitPoolClose(t *testing.T) {
}
}
c.Close()
d.check("done", p, 1, 0)
d.check("done", p, 1, 0, 0)
}
func TestWaitPoolCommandError(t *testing.T) {
@@ -520,7 +524,7 @@ func TestWaitPoolCommandError(t *testing.T) {
c := p.Get()
errs := startGoroutines(p, "ERR", testErr)
d.check("before close", p, 1, 1)
d.check("before close", p, 1, 1, 1)
c.Close()
timeout := time.After(2 * time.Second)
for i := 0; i < cap(errs); i++ {
@@ -533,7 +537,7 @@ func TestWaitPoolCommandError(t *testing.T) {
t.Fatalf("timeout waiting for blocked goroutine %d", i)
}
}
d.check("done", p, cap(errs), 0)
d.check("done", p, cap(errs), 0, 0)
}
func TestWaitPoolDialError(t *testing.T) {
@@ -549,7 +553,7 @@ func TestWaitPoolDialError(t *testing.T) {
c := p.Get()
errs := startGoroutines(p, "ERR", testErr)
d.check("before close", p, 1, 1)
d.check("before close", p, 1, 1, 1)
d.dialErr = errors.New("dial")
c.Close()
@@ -578,7 +582,7 @@ func TestWaitPoolDialError(t *testing.T) {
if errCount != cap(errs)-1 {
t.Errorf("expected %d dial errors, got %d", cap(errs)-1, errCount)
}
d.check("done", p, cap(errs), 0)
d.check("done", p, cap(errs), 0, 0)
}
// Borrowing requires us to iterate over the idle connections, unlock the pool,

View File

@@ -391,3 +391,35 @@ func Int64Map(result interface{}, err error) (map[string]int64, error) {
}
return m, nil
}
// Positions is a helper that converts an array of positions (lat, long)
// into a [][2]float64. The GEOPOS command returns replies in this format.
func Positions(result interface{}, err error) ([]*[2]float64, error) {
values, err := Values(result, err)
if err != nil {
return nil, err
}
positions := make([]*[2]float64, len(values))
for i := range values {
if values[i] == nil {
continue
}
p, ok := values[i].([]interface{})
if !ok {
return nil, fmt.Errorf("redigo: unexpected element type for interface slice, got type %T", values[i])
}
if len(p) != 2 {
return nil, fmt.Errorf("redigo: unexpected number of values for a member position, got %d", len(p))
}
lat, err := Float64(p[0], nil)
if err != nil {
return nil, err
}
long, err := Float64(p[1], nil)
if err != nil {
return nil, err
}
positions[i] = &[2]float64{lat, long}
}
return positions, nil
}

View File

@@ -96,6 +96,11 @@ var replyTests = []struct {
ve(redis.Uint64(int64(-1), nil)),
ve(uint64(0), redis.ErrNegativeInt),
},
{
"positions([[1, 2], nil, [3, 4]])",
ve(redis.Positions([]interface{}{[]interface{}{[]byte("1"), []byte("2")}, nil, []interface{}{[]byte("3"), []byte("4")}}, nil)),
ve([]*[2]float64{{1.0, 2.0}, nil, {3.0, 4.0}}, nil),
},
}
func TestReply(t *testing.T) {

View File

@@ -186,7 +186,11 @@ func convertAssign(d interface{}, s interface{}) (err error) {
case string:
switch d := d.(type) {
case *string:
*d = string(s)
*d = s
case *interface{}:
*d = s
case nil:
// skip value
default:
err = cannotConvert(reflect.ValueOf(d), s)
}

View File

@@ -55,6 +55,11 @@ func (s *Script) args(spec string, keysAndArgs []interface{}) []interface{} {
return args
}
// Hash returns the script hash.
func (s *Script) Hash() string {
return s.hash
}
// Do evaluates the script. Under the covers, Do optimistically evaluates the
// script using the EVALSHA command. If the command fails because the script is
// not loaded, then Do evaluates the script using the EVAL command (thus

View File

@@ -16,6 +16,7 @@ package redis_test
import (
"fmt"
"github.com/garyburd/redigo/redis"
)