|
|
@@ -0,0 +1,259 @@
|
|
|
+// Copyright 2014 Gary Burd
|
|
|
+//
|
|
|
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
|
|
+// not use this file except in compliance with the License. You may obtain
|
|
|
+// a copy of the License at
|
|
|
+//
|
|
|
+// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
+//
|
|
|
+// Unless required by applicable law or agreed to in writing, software
|
|
|
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
|
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
|
+// License for the specific language governing permissions and limitations
|
|
|
+// under the License.
|
|
|
+
|
|
|
+package redisx_test
|
|
|
+
|
|
|
+import (
|
|
|
+ "net/textproto"
|
|
|
+ "sync"
|
|
|
+ "testing"
|
|
|
+
|
|
|
+ "github.com/garyburd/redigo/internal/redistest"
|
|
|
+ "github.com/garyburd/redigo/redis"
|
|
|
+ "github.com/garyburd/redigo/redisx"
|
|
|
+)
|
|
|
+
|
|
|
+func TestConnMux(t *testing.T) {
|
|
|
+ c, err := redistest.Dial()
|
|
|
+ if err != nil {
|
|
|
+ t.Fatalf("error connection to database, %v", err)
|
|
|
+ }
|
|
|
+ m := redisx.NewConnMux(c)
|
|
|
+ defer m.Close()
|
|
|
+
|
|
|
+ c1 := m.Get()
|
|
|
+ c2 := m.Get()
|
|
|
+ c1.Send("ECHO", "hello")
|
|
|
+ c2.Send("ECHO", "world")
|
|
|
+ c1.Flush()
|
|
|
+ c2.Flush()
|
|
|
+ s, err := redis.String(c1.Receive())
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+ if s != "hello" {
|
|
|
+ t.Fatalf("echo returned %q, want %q", s, "hello")
|
|
|
+ }
|
|
|
+ s, err = redis.String(c2.Receive())
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+ if s != "world" {
|
|
|
+ t.Fatalf("echo returned %q, want %q", s, "world")
|
|
|
+ }
|
|
|
+ c1.Close()
|
|
|
+ c2.Close()
|
|
|
+}
|
|
|
+
|
|
|
+func TestConnMuxClose(t *testing.T) {
|
|
|
+ c, err := redistest.Dial()
|
|
|
+ if err != nil {
|
|
|
+ t.Fatalf("error connection to database, %v", err)
|
|
|
+ }
|
|
|
+ m := redisx.NewConnMux(c)
|
|
|
+ defer m.Close()
|
|
|
+
|
|
|
+ c1 := m.Get()
|
|
|
+ c2 := m.Get()
|
|
|
+
|
|
|
+ if err := c1.Send("ECHO", "hello"); err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+ if err := c1.Close(); err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := c2.Send("ECHO", "world"); err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+ if err := c2.Flush(); err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+
|
|
|
+ s, err := redis.String(c2.Receive())
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+ if s != "world" {
|
|
|
+ t.Fatalf("echo returned %q, want %q", s, "world")
|
|
|
+ }
|
|
|
+ c2.Close()
|
|
|
+}
|
|
|
+
|
|
|
+func BenchmarkConn(b *testing.B) {
|
|
|
+ b.StopTimer()
|
|
|
+ c, err := redistest.Dial()
|
|
|
+ if err != nil {
|
|
|
+ b.Fatalf("error connection to database, %v", err)
|
|
|
+ }
|
|
|
+ defer c.Close()
|
|
|
+ b.StartTimer()
|
|
|
+
|
|
|
+ for i := 0; i < b.N; i++ {
|
|
|
+ if _, err := c.Do("PING"); err != nil {
|
|
|
+ b.Fatal(err)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func BenchmarkConnMux(b *testing.B) {
|
|
|
+ b.StopTimer()
|
|
|
+ c, err := redistest.Dial()
|
|
|
+ if err != nil {
|
|
|
+ b.Fatalf("error connection to database, %v", err)
|
|
|
+ }
|
|
|
+ m := redisx.NewConnMux(c)
|
|
|
+ defer m.Close()
|
|
|
+
|
|
|
+ b.StartTimer()
|
|
|
+
|
|
|
+ for i := 0; i < b.N; i++ {
|
|
|
+ c := m.Get()
|
|
|
+ if _, err := c.Do("PING"); err != nil {
|
|
|
+ b.Fatal(err)
|
|
|
+ }
|
|
|
+ c.Close()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func BenchmarkPool(b *testing.B) {
|
|
|
+ b.StopTimer()
|
|
|
+
|
|
|
+ p := redis.Pool{Dial: redistest.Dial, MaxIdle: 1}
|
|
|
+ defer p.Close()
|
|
|
+
|
|
|
+ // Fill the pool.
|
|
|
+ c := p.Get()
|
|
|
+ if err := c.Err(); err != nil {
|
|
|
+ b.Fatal(err)
|
|
|
+ }
|
|
|
+ c.Close()
|
|
|
+
|
|
|
+ b.StartTimer()
|
|
|
+
|
|
|
+ for i := 0; i < b.N; i++ {
|
|
|
+ c := p.Get()
|
|
|
+ if _, err := c.Do("PING"); err != nil {
|
|
|
+ b.Fatal(err)
|
|
|
+ }
|
|
|
+ c.Close()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const numConcurrent = 10
|
|
|
+
|
|
|
+func BenchmarkConnMuxConcurrent(b *testing.B) {
|
|
|
+ b.StopTimer()
|
|
|
+ c, err := redistest.Dial()
|
|
|
+ if err != nil {
|
|
|
+ b.Fatalf("error connection to database, %v", err)
|
|
|
+ }
|
|
|
+ defer c.Close()
|
|
|
+
|
|
|
+ m := redisx.NewConnMux(c)
|
|
|
+
|
|
|
+ var wg sync.WaitGroup
|
|
|
+ wg.Add(numConcurrent)
|
|
|
+
|
|
|
+ b.StartTimer()
|
|
|
+
|
|
|
+ for i := 0; i < numConcurrent; i++ {
|
|
|
+ go func() {
|
|
|
+ defer wg.Done()
|
|
|
+ for i := 0; i < b.N; i++ {
|
|
|
+ c := m.Get()
|
|
|
+ if _, err := c.Do("PING"); err != nil {
|
|
|
+ b.Fatal(err)
|
|
|
+ }
|
|
|
+ c.Close()
|
|
|
+ }
|
|
|
+ }()
|
|
|
+ }
|
|
|
+ wg.Wait()
|
|
|
+}
|
|
|
+
|
|
|
+func BenchmarkPoolConcurrent(b *testing.B) {
|
|
|
+ b.StopTimer()
|
|
|
+
|
|
|
+ p := redis.Pool{Dial: redistest.Dial, MaxIdle: numConcurrent}
|
|
|
+ defer p.Close()
|
|
|
+
|
|
|
+ // Fill the pool.
|
|
|
+ conns := make([]redis.Conn, numConcurrent)
|
|
|
+ for i := range conns {
|
|
|
+ c := p.Get()
|
|
|
+ if err := c.Err(); err != nil {
|
|
|
+ b.Fatal(err)
|
|
|
+ }
|
|
|
+ conns[i] = c
|
|
|
+ }
|
|
|
+ for _, c := range conns {
|
|
|
+ c.Close()
|
|
|
+ }
|
|
|
+
|
|
|
+ var wg sync.WaitGroup
|
|
|
+ wg.Add(numConcurrent)
|
|
|
+
|
|
|
+ b.StartTimer()
|
|
|
+
|
|
|
+ for i := 0; i < numConcurrent; i++ {
|
|
|
+ go func() {
|
|
|
+ defer wg.Done()
|
|
|
+ for i := 0; i < b.N; i++ {
|
|
|
+ c := p.Get()
|
|
|
+ if _, err := c.Do("PING"); err != nil {
|
|
|
+ b.Fatal(err)
|
|
|
+ }
|
|
|
+ c.Close()
|
|
|
+ }
|
|
|
+ }()
|
|
|
+ }
|
|
|
+ wg.Wait()
|
|
|
+}
|
|
|
+
|
|
|
+func BenchmarkPipelineConcurrency(b *testing.B) {
|
|
|
+ b.StopTimer()
|
|
|
+ c, err := redistest.Dial()
|
|
|
+ if err != nil {
|
|
|
+ b.Fatalf("error connection to database, %v", err)
|
|
|
+ }
|
|
|
+ defer c.Close()
|
|
|
+
|
|
|
+ var wg sync.WaitGroup
|
|
|
+ wg.Add(numConcurrent)
|
|
|
+
|
|
|
+ var pipeline textproto.Pipeline
|
|
|
+
|
|
|
+ b.StartTimer()
|
|
|
+
|
|
|
+ for i := 0; i < numConcurrent; i++ {
|
|
|
+ go func() {
|
|
|
+ defer wg.Done()
|
|
|
+ for i := 0; i < b.N; i++ {
|
|
|
+ id := pipeline.Next()
|
|
|
+ pipeline.StartRequest(id)
|
|
|
+ c.Send("PING")
|
|
|
+ c.Flush()
|
|
|
+ pipeline.EndRequest(id)
|
|
|
+ pipeline.StartResponse(id)
|
|
|
+ _, err := c.Receive()
|
|
|
+ if err != nil {
|
|
|
+ b.Fatal(err)
|
|
|
+ }
|
|
|
+ pipeline.EndResponse(id)
|
|
|
+ }
|
|
|
+ }()
|
|
|
+ }
|
|
|
+ wg.Wait()
|
|
|
+}
|