diff options
| author | James Tucker <raggi@google.com> | 2013-04-03 11:13:40 -0700 |
|---|---|---|
| committer | Brad Fitzpatrick <bradfitz@golang.org> | 2013-04-03 11:13:40 -0700 |
| commit | 4f1ef563cc7fa110937516be2fe847a48e700135 (patch) | |
| tree | 085b27e4c8945ca0396cd326d9c11055678b51f7 /src/pkg/database/sql/sql_test.go | |
| parent | b6f798f35bb441b328ed53f32b865d0cbdf0ad91 (diff) | |
| download | go-4f1ef563cc7fa110937516be2fe847a48e700135.tar.xz | |
database/sql: improve standard deviation response time under high concurrency
See https://github.com/raggi/go-and-java for runtime benchmark.
The patch reduces the amount of map key search, moving connection oriented
variables onto the connection structs.
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/8092045
Diffstat (limited to 'src/pkg/database/sql/sql_test.go')
| -rw-r--r-- | src/pkg/database/sql/sql_test.go | 75 |
1 files changed, 72 insertions, 3 deletions
diff --git a/src/pkg/database/sql/sql_test.go b/src/pkg/database/sql/sql_test.go index 54aad3a5d0..6b91783784 100644 --- a/src/pkg/database/sql/sql_test.go +++ b/src/pkg/database/sql/sql_test.go @@ -7,7 +7,9 @@ package sql import ( "fmt" "reflect" + "runtime" "strings" + "sync" "testing" "time" ) @@ -36,7 +38,14 @@ const fakeDBName = "foo" var chrisBirthday = time.Unix(123456789, 0) -func newTestDB(t *testing.T, name string) *DB { +type testOrBench interface { + Fatalf(string, ...interface{}) + Errorf(string, ...interface{}) + Fatal(...interface{}) + Error(...interface{}) +} + +func newTestDB(t testOrBench, name string) *DB { db, err := Open("test", fakeDBName) if err != nil { t.Fatalf("Open: %v", err) @@ -53,14 +62,14 @@ func newTestDB(t *testing.T, name string) *DB { return db } -func exec(t *testing.T, db *DB, query string, args ...interface{}) { +func exec(t testOrBench, db *DB, query string, args ...interface{}) { _, err := db.Exec(query, args...) if err != nil { t.Fatalf("Exec of %q: %v", query, err) } } -func closeDB(t *testing.T, db *DB) { +func closeDB(t testOrBench, db *DB) { if e := recover(); e != nil { fmt.Printf("Panic: %v\n", e) panic(e) @@ -844,3 +853,63 @@ func TestCloseConnBeforeStmts(t *testing.T) { t.Errorf("after Stmt Close, driverConn's Conn interface should be nil") } } + +func manyConcurrentQueries(t testOrBench) { + maxProcs, numReqs := 16, 500 + if testing.Short() { + maxProcs, numReqs = 4, 50 + } + defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs)) + + db := newTestDB(t, "people") + defer closeDB(t, db) + + stmt, err := db.Prepare("SELECT|people|name|") + if err != nil { + t.Fatal(err) + } + + var wg sync.WaitGroup + wg.Add(numReqs) + + reqs := make(chan bool) + defer close(reqs) + + for i := 0; i < maxProcs*2; i++ { + go func() { + for _ = range reqs { + rows, err := stmt.Query() + if err != nil { + t.Errorf("error on query: %v", err) + wg.Done() + continue + } + + var name string + for rows.Next() { + rows.Scan(&name) + } + rows.Close() + + wg.Done() + } + }() + } + + for i := 0; i < numReqs; i++ { + reqs <- true + } + + wg.Wait() +} + +func TestConcurrency(t *testing.T) { + manyConcurrentQueries(t) +} + +func BenchmarkConcurrency(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + manyConcurrentQueries(b) + } +} |
