Bläddra i källkod

Expose current number of idle connections in the pool

Mat Byczkowski 8 år sedan
förälder
incheckning
b2e86792d3
3 ändrade filer med 37 tillägg och 24 borttagningar
  1. 8 0
      redis/pool.go
  2. 28 24
      redis/pool_test.go
  3. 1 0
      redis/zpop_example_test.go

+ 8 - 0
redis/pool.go

@@ -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()

+ 28 - 24
redis/pool_test.go

@@ -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,

+ 1 - 0
redis/zpop_example_test.go

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