From 6fb6f4e7f9eea8b724ddde592686d7e9dcdaa41c Mon Sep 17 00:00:00 2001 From: Alberto GarcĂ­a Hierro Date: Thu, 28 Aug 2014 08:49:56 -0700 Subject: database/sql: use slices rather than container/list Significantly reduces the number of allocations, while also simplifying the code and increasing performance by a 1-2%. benchmark old ns/op new ns/op delta BenchmarkConcurrentDBExec 13290567 13026236 -1.99% BenchmarkConcurrentStmtQuery 13249399 13008879 -1.82% BenchmarkConcurrentStmtExec 8806237 8680182 -1.43% BenchmarkConcurrentTxQuery 13628379 12756293 -6.40% BenchmarkConcurrentTxExec 4794800 4722440 -1.51% BenchmarkConcurrentTxStmtQuery 5040804 5200721 +3.17% BenchmarkConcurrentTxStmtExec 1366574 1336626 -2.19% BenchmarkConcurrentRandom 11119120 10926113 -1.74% benchmark old allocs new allocs delta BenchmarkConcurrentDBExec 14191 13684 -3.57% BenchmarkConcurrentStmtQuery 16020 15514 -3.16% BenchmarkConcurrentStmtExec 4179 3672 -12.13% BenchmarkConcurrentTxQuery 16025 15518 -3.16% BenchmarkConcurrentTxExec 12717 12709 -0.06% BenchmarkConcurrentTxStmtQuery 15532 15525 -0.05% BenchmarkConcurrentTxStmtExec 2175 2168 -0.32% BenchmarkConcurrentRandom 12320 11997 -2.62% benchmark old bytes new bytes delta BenchmarkConcurrentDBExec 2164827 2139760 -1.16% BenchmarkConcurrentStmtQuery 2418070 2394030 -0.99% BenchmarkConcurrentStmtExec 1728782 1704371 -1.41% BenchmarkConcurrentTxQuery 2477144 2452620 -0.99% BenchmarkConcurrentTxExec 588920 588343 -0.10% BenchmarkConcurrentTxStmtQuery 790866 796578 +0.72% BenchmarkConcurrentTxStmtExec 98502 98143 -0.36% BenchmarkConcurrentRandom 1725906 1710220 -0.91% LGTM=ruiu, dave, bradfitz R=golang-codereviews, ruiu, gobot, bradfitz, dave, minux CC=bradfitz, golang-codereviews https://golang.org/cl/107020044 --- src/pkg/database/sql/sql_test.go | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) (limited to 'src/pkg/database/sql/sql_test.go') diff --git a/src/pkg/database/sql/sql_test.go b/src/pkg/database/sql/sql_test.go index 71c81d6f76..8849c81c4b 100644 --- a/src/pkg/database/sql/sql_test.go +++ b/src/pkg/database/sql/sql_test.go @@ -24,7 +24,14 @@ func init() { } freedFrom := make(map[dbConn]string) putConnHook = func(db *DB, c *driverConn) { - if c.listElem != nil { + idx := -1 + for i, v := range db.freeConn { + if v == c { + idx = i + break + } + } + if idx >= 0 { // print before panic, as panic may get lost due to conflicting panic // (all goroutines asleep) elsewhere, since we might not unlock // the mutex in freeConn here. @@ -79,15 +86,14 @@ func closeDB(t testing.TB, db *DB) { t.Errorf("Error closing fakeConn: %v", err) } }) - for node, i := db.freeConn.Front(), 0; node != nil; node, i = node.Next(), i+1 { - dc := node.Value.(*driverConn) + for i, dc := range db.freeConn { if n := len(dc.openStmt); n > 0 { // Just a sanity check. This is legal in // general, but if we make the tests clean up // their statements first, then we can safely // verify this is always zero here, and any // other value is a leak. - t.Errorf("while closing db, freeConn %d/%d had %d open stmts; want 0", i, db.freeConn.Len(), n) + t.Errorf("while closing db, freeConn %d/%d had %d open stmts; want 0", i, len(db.freeConn), n) } } err := db.Close() @@ -105,10 +111,10 @@ func closeDB(t testing.TB, db *DB) { // numPrepares assumes that db has exactly 1 idle conn and returns // its count of calls to Prepare func numPrepares(t *testing.T, db *DB) int { - if n := db.freeConn.Len(); n != 1 { + if n := len(db.freeConn); n != 1 { t.Fatalf("free conns = %d; want 1", n) } - return (db.freeConn.Front().Value.(*driverConn)).ci.(*fakeConn).numPrepare + return db.freeConn[0].ci.(*fakeConn).numPrepare } func (db *DB) numDeps() int { @@ -133,7 +139,7 @@ func (db *DB) numDepsPollUntil(want int, d time.Duration) int { func (db *DB) numFreeConns() int { db.mu.Lock() defer db.mu.Unlock() - return db.freeConn.Len() + return len(db.freeConn) } func (db *DB) dumpDeps(t *testing.T) { @@ -650,10 +656,10 @@ func TestQueryRowClosingStmt(t *testing.T) { if err != nil { t.Fatal(err) } - if db.freeConn.Len() != 1 { + if len(db.freeConn) != 1 { t.Fatalf("expected 1 free conn") } - fakeConn := (db.freeConn.Front().Value.(*driverConn)).ci.(*fakeConn) + fakeConn := db.freeConn[0].ci.(*fakeConn) if made, closed := fakeConn.stmtsMade, fakeConn.stmtsClosed; made != closed { t.Errorf("statement close mismatch: made %d, closed %d", made, closed) } @@ -878,13 +884,13 @@ func TestMaxIdleConns(t *testing.T) { t.Fatal(err) } tx.Commit() - if got := db.freeConn.Len(); got != 1 { + if got := len(db.freeConn); got != 1 { t.Errorf("freeConns = %d; want 1", got) } db.SetMaxIdleConns(0) - if got := db.freeConn.Len(); got != 0 { + if got := len(db.freeConn); got != 0 { t.Errorf("freeConns after set to zero = %d; want 0", got) } @@ -893,7 +899,7 @@ func TestMaxIdleConns(t *testing.T) { t.Fatal(err) } tx.Commit() - if got := db.freeConn.Len(); got != 0 { + if got := len(db.freeConn); got != 0 { t.Errorf("freeConns = %d; want 0", got) } } @@ -1180,10 +1186,10 @@ func TestCloseConnBeforeStmts(t *testing.T) { t.Fatal(err) } - if db.freeConn.Len() != 1 { - t.Fatalf("expected 1 freeConn; got %d", db.freeConn.Len()) + if len(db.freeConn) != 1 { + t.Fatalf("expected 1 freeConn; got %d", len(db.freeConn)) } - dc := db.freeConn.Front().Value.(*driverConn) + dc := db.freeConn[0] if dc.closed { t.Errorf("conn shouldn't be closed") } -- cgit v1.3