mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
database/sql: reduce lock contention in Stmt.connStmt
Previouslly, Stmt.connStmt calls DB.connIfFree on each Stmt.css. Since Stmt.connStmt locks Stmt.mu, a concurrent use of Stmt causes lock contention on Stmt.mu. Additionally, DB.connIfFree locks DB.mu which is shared by DB.addDep and DB.removeDep. This change removes DB.connIfFree and makes use of a first unused connection in idle connection pool to reduce lock contention without making it complicated. Fixes #9484 On EC2 c3.8xlarge (E5-2680 v2 @ 2.80GHz * 32 vCPU): benchmark old ns/op new ns/op delta BenchmarkManyConcurrentQuery-8 40249 34721 -13.73% BenchmarkManyConcurrentQuery-16 45610 40176 -11.91% BenchmarkManyConcurrentQuery-32 109831 43179 -60.69% benchmark old allocs new allocs delta BenchmarkManyConcurrentQuery-8 25 25 +0.00% BenchmarkManyConcurrentQuery-16 25 25 +0.00% BenchmarkManyConcurrentQuery-32 25 25 +0.00% benchmark old bytes new bytes delta BenchmarkManyConcurrentQuery-8 3980 3969 -0.28% BenchmarkManyConcurrentQuery-16 3980 3982 +0.05% BenchmarkManyConcurrentQuery-32 3993 3990 -0.08% Change-Id: Ic96296922c465bac38a260018c58324dae1531d9 Reviewed-on: https://go-review.googlesource.com/2207 Reviewed-by: Mikio Hara <mikioh.mikioh@gmail.com>
This commit is contained in:
parent
3acb9fd98e
commit
1b61a97811
2 changed files with 70 additions and 111 deletions
|
|
@ -1764,56 +1764,6 @@ func doConcurrentTest(t testing.TB, ct concurrentTest) {
|
|||
wg.Wait()
|
||||
}
|
||||
|
||||
func manyConcurrentQueries(t testing.TB) {
|
||||
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)
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
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 TestIssue6081(t *testing.T) {
|
||||
db := newTestDB(t, "people")
|
||||
defer closeDB(t, db)
|
||||
|
|
@ -1985,3 +1935,31 @@ func BenchmarkConcurrentRandom(b *testing.B) {
|
|||
doConcurrentTest(b, ct)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkManyConcurrentQueries(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
// To see lock contention in Go 1.4, 16~ cores and 128~ goroutines are required.
|
||||
const parallelism = 16
|
||||
|
||||
db := newTestDB(b, "magicquery")
|
||||
defer closeDB(b, db)
|
||||
db.SetMaxIdleConns(runtime.GOMAXPROCS(0) * parallelism)
|
||||
|
||||
stmt, err := db.Prepare("SELECT|magicquery|op|op=?,millis=?")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
b.SetParallelism(parallelism)
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
rows, err := stmt.Query("sleep", 1)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
return
|
||||
}
|
||||
rows.Close()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue