Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(143)

Side by Side Diff: src/pkg/database/sql/sql_test.go

Issue 10726044: database/sql: add SetMaxOpenConns (Closed)
Patch Set: diff -r 6939fe74ea98 https://code.google.com/p/go Created 10 years, 7 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/pkg/database/sql/sql.go ('k') | src/pkg/go/build/deps_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2011 The Go Authors. All rights reserved. 1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 package sql 5 package sql
6 6
7 import ( 7 import (
8 "database/sql/driver" 8 "database/sql/driver"
9 "errors" 9 "errors"
10 "fmt" 10 "fmt"
11 "math/rand"
11 "reflect" 12 "reflect"
12 "runtime" 13 "runtime"
13 "strings" 14 "strings"
14 "sync" 15 "sync"
15 "testing" 16 "testing"
16 "time" 17 "time"
17 ) 18 )
18 19
19 func init() { 20 func init() {
20 type dbConn struct { 21 type dbConn struct {
21 db *DB 22 db *DB
22 c *driverConn 23 c *driverConn
23 } 24 }
24 freedFrom := make(map[dbConn]string) 25 freedFrom := make(map[dbConn]string)
25 putConnHook = func(db *DB, c *driverConn) { 26 putConnHook = func(db *DB, c *driverConn) {
26 » » for _, oc := range db.freeConn { 27 » » if c.listElem != nil {
27 » » » if oc == c { 28 » » » // print before panic, as panic may get lost due to conf licting panic
28 » » » » // print before panic, as panic may get lost due to conflicting panic 29 » » » // (all goroutines asleep) elsewhere, since we might not unlock
29 » » » » // (all goroutines asleep) elsewhere, since we m ight not unlock 30 » » » // the mutex in freeConn here.
30 » » » » // the mutex in freeConn here. 31 » » » println("double free of conn. conflicts are:\nA) " + fre edFrom[dbConn{db, c}] + "\n\nand\nB) " + stack())
31 » » » » println("double free of conn. conflicts are:\nA) " + freedFrom[dbConn{db, c}] + "\n\nand\nB) " + stack()) 32 » » » panic("double free of conn.")
32 » » » » panic("double free of conn.")
33 » » » }
34 } 33 }
35 freedFrom[dbConn{db, c}] = stack() 34 freedFrom[dbConn{db, c}] = stack()
36 } 35 }
37 } 36 }
38 37
39 const fakeDBName = "foo" 38 const fakeDBName = "foo"
40 39
41 var chrisBirthday = time.Unix(123456789, 0) 40 var chrisBirthday = time.Unix(123456789, 0)
42 41
43 func newTestDB(t testing.TB, name string) *DB { 42 func newTestDB(t testing.TB, name string) *DB {
(...skipping 29 matching lines...) Expand all
73 if e := recover(); e != nil { 72 if e := recover(); e != nil {
74 fmt.Printf("Panic: %v\n", e) 73 fmt.Printf("Panic: %v\n", e)
75 panic(e) 74 panic(e)
76 } 75 }
77 defer setHookpostCloseConn(nil) 76 defer setHookpostCloseConn(nil)
78 setHookpostCloseConn(func(_ *fakeConn, err error) { 77 setHookpostCloseConn(func(_ *fakeConn, err error) {
79 if err != nil { 78 if err != nil {
80 t.Errorf("Error closing fakeConn: %v", err) 79 t.Errorf("Error closing fakeConn: %v", err)
81 } 80 }
82 }) 81 })
83 » for i, dc := range db.freeConn { 82 » for node, i := db.freeConn.Front(), 0; node != nil; node, i = node.Next( ), i+1 {
83 » » dc := node.Value.(*driverConn)
84 if n := len(dc.openStmt); n > 0 { 84 if n := len(dc.openStmt); n > 0 {
85 // Just a sanity check. This is legal in 85 // Just a sanity check. This is legal in
86 // general, but if we make the tests clean up 86 // general, but if we make the tests clean up
87 // their statements first, then we can safely 87 // their statements first, then we can safely
88 // verify this is always zero here, and any 88 // verify this is always zero here, and any
89 // other value is a leak. 89 // other value is a leak.
90 » » » t.Errorf("while closing db, freeConn %d/%d had %d open s tmts; want 0", i, len(db.freeConn), n) 90 » » » t.Errorf("while closing db, freeConn %d/%d had %d open s tmts; want 0", i, db.freeConn.Len(), n)
91 } 91 }
92 } 92 }
93 err := db.Close() 93 err := db.Close()
94 if err != nil { 94 if err != nil {
95 t.Fatalf("error closing DB: %v", err) 95 t.Fatalf("error closing DB: %v", err)
96 } 96 }
97 } 97 }
98 98
99 // numPrepares assumes that db has exactly 1 idle conn and returns 99 // numPrepares assumes that db has exactly 1 idle conn and returns
100 // its count of calls to Prepare 100 // its count of calls to Prepare
101 func numPrepares(t *testing.T, db *DB) int { 101 func numPrepares(t *testing.T, db *DB) int {
102 » if n := len(db.freeConn); n != 1 { 102 » if n := db.freeConn.Len(); n != 1 {
103 t.Fatalf("free conns = %d; want 1", n) 103 t.Fatalf("free conns = %d; want 1", n)
104 } 104 }
105 » return db.freeConn[0].ci.(*fakeConn).numPrepare 105 » return (db.freeConn.Front().Value.(*driverConn)).ci.(*fakeConn).numPrepa re
106 } 106 }
107 107
108 func (db *DB) numDeps() int { 108 func (db *DB) numDeps() int {
109 db.mu.Lock() 109 db.mu.Lock()
110 defer db.mu.Unlock() 110 defer db.mu.Unlock()
111 return len(db.dep) 111 return len(db.dep)
112 } 112 }
113 113
114 // Dependencies are closed via a goroutine, so this polls waiting for 114 // Dependencies are closed via a goroutine, so this polls waiting for
115 // numDeps to fall to want, waiting up to d. 115 // numDeps to fall to want, waiting up to d.
116 func (db *DB) numDepsPollUntil(want int, d time.Duration) int { 116 func (db *DB) numDepsPollUntil(want int, d time.Duration) int {
117 deadline := time.Now().Add(d) 117 deadline := time.Now().Add(d)
118 for { 118 for {
119 n := db.numDeps() 119 n := db.numDeps()
120 if n <= want || time.Now().After(deadline) { 120 if n <= want || time.Now().After(deadline) {
121 return n 121 return n
122 } 122 }
123 time.Sleep(50 * time.Millisecond) 123 time.Sleep(50 * time.Millisecond)
124 } 124 }
125 } 125 }
126 126
127 func (db *DB) numFreeConns() int { 127 func (db *DB) numFreeConns() int {
128 db.mu.Lock() 128 db.mu.Lock()
129 defer db.mu.Unlock() 129 defer db.mu.Unlock()
130 » return len(db.freeConn) 130 » return db.freeConn.Len()
131 } 131 }
132 132
133 func (db *DB) dumpDeps(t *testing.T) { 133 func (db *DB) dumpDeps(t *testing.T) {
134 for fc := range db.dep { 134 for fc := range db.dep {
135 db.dumpDep(t, 0, fc, map[finalCloser]bool{}) 135 db.dumpDep(t, 0, fc, map[finalCloser]bool{})
136 } 136 }
137 } 137 }
138 138
139 func (db *DB) dumpDep(t *testing.T, depth int, dep finalCloser, seen map[finalCl oser]bool) { 139 func (db *DB) dumpDep(t *testing.T, depth int, dep finalCloser, seen map[finalCl oser]bool) {
140 seen[dep] = true 140 seen[dep] = true
(...skipping 494 matching lines...) Expand 10 before | Expand all | Expand 10 after
635 635
636 func TestQueryRowClosingStmt(t *testing.T) { 636 func TestQueryRowClosingStmt(t *testing.T) {
637 db := newTestDB(t, "people") 637 db := newTestDB(t, "people")
638 defer closeDB(t, db) 638 defer closeDB(t, db)
639 var name string 639 var name string
640 var age int 640 var age int
641 err := db.QueryRow("SELECT|people|age,name|age=?", 3).Scan(&age, &name) 641 err := db.QueryRow("SELECT|people|age,name|age=?", 3).Scan(&age, &name)
642 if err != nil { 642 if err != nil {
643 t.Fatal(err) 643 t.Fatal(err)
644 } 644 }
645 » if len(db.freeConn) != 1 { 645 » if db.freeConn.Len() != 1 {
646 t.Fatalf("expected 1 free conn") 646 t.Fatalf("expected 1 free conn")
647 } 647 }
648 » fakeConn := db.freeConn[0].ci.(*fakeConn) 648 » fakeConn := (db.freeConn.Front().Value.(*driverConn)).ci.(*fakeConn)
649 if made, closed := fakeConn.stmtsMade, fakeConn.stmtsClosed; made != clo sed { 649 if made, closed := fakeConn.stmtsMade, fakeConn.stmtsClosed; made != clo sed {
650 t.Errorf("statement close mismatch: made %d, closed %d", made, c losed) 650 t.Errorf("statement close mismatch: made %d, closed %d", made, c losed)
651 } 651 }
652 } 652 }
653 653
654 type nullTestRow struct { 654 type nullTestRow struct {
655 nullParam interface{} 655 nullParam interface{}
656 notNullParam interface{} 656 notNullParam interface{}
657 scanNullVal interface{} 657 scanNullVal interface{}
658 } 658 }
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
834 834
835 func TestMaxIdleConns(t *testing.T) { 835 func TestMaxIdleConns(t *testing.T) {
836 db := newTestDB(t, "people") 836 db := newTestDB(t, "people")
837 defer closeDB(t, db) 837 defer closeDB(t, db)
838 838
839 tx, err := db.Begin() 839 tx, err := db.Begin()
840 if err != nil { 840 if err != nil {
841 t.Fatal(err) 841 t.Fatal(err)
842 } 842 }
843 tx.Commit() 843 tx.Commit()
844 » if got := len(db.freeConn); got != 1 { 844 » if got := db.freeConn.Len(); got != 1 {
845 t.Errorf("freeConns = %d; want 1", got) 845 t.Errorf("freeConns = %d; want 1", got)
846 } 846 }
847 847
848 db.SetMaxIdleConns(0) 848 db.SetMaxIdleConns(0)
849 849
850 » if got := len(db.freeConn); got != 0 { 850 » if got := db.freeConn.Len(); got != 0 {
851 t.Errorf("freeConns after set to zero = %d; want 0", got) 851 t.Errorf("freeConns after set to zero = %d; want 0", got)
852 } 852 }
853 853
854 tx, err = db.Begin() 854 tx, err = db.Begin()
855 if err != nil { 855 if err != nil {
856 t.Fatal(err) 856 t.Fatal(err)
857 } 857 }
858 tx.Commit() 858 tx.Commit()
859 » if got := len(db.freeConn); got != 0 { 859 » if got := db.freeConn.Len(); got != 0 {
860 t.Errorf("freeConns = %d; want 0", got) 860 t.Errorf("freeConns = %d; want 0", got)
861 } 861 }
862 } 862 }
863 863
864 func TestMaxOpenConns(t *testing.T) {
865 if testing.Short() {
866 t.Skip("skipping in short mode")
867 }
868 defer setHookpostCloseConn(nil)
869 setHookpostCloseConn(func(_ *fakeConn, err error) {
870 if err != nil {
871 t.Errorf("Error closing fakeConn: %v", err)
872 }
873 })
874
875 db := newTestDB(t, "magicquery")
876 defer closeDB(t, db)
877
878 driver := db.driver.(*fakeDriver)
879
880 // Force the number of open connections to 0 so we can get an accurate
881 // count for the test
882 db.SetMaxIdleConns(0)
883
884 if g, w := db.numFreeConns(), 0; g != w {
885 t.Errorf("free conns = %d; want %d", g, w)
886 }
887
888 if n := db.numDepsPollUntil(0, time.Second); n > 0 {
889 t.Errorf("number of dependencies = %d; expected 0", n)
890 db.dumpDeps(t)
891 }
892
893 driver.mu.Lock()
894 opens0 := driver.openCount
895 closes0 := driver.closeCount
896 driver.mu.Unlock()
897
898 db.SetMaxIdleConns(10)
899 db.SetMaxOpenConns(10)
900
901 stmt, err := db.Prepare("SELECT|magicquery|op|op=?,millis=?")
902 if err != nil {
903 t.Fatal(err)
904 }
905
906 // Start 50 parallel slow queries.
907 const (
908 nquery = 50
909 sleepMillis = 25
910 nbatch = 2
911 )
912 var wg sync.WaitGroup
913 for batch := 0; batch < nbatch; batch++ {
914 for i := 0; i < nquery; i++ {
915 wg.Add(1)
916 go func() {
917 defer wg.Done()
918 var op string
919 if err := stmt.QueryRow("sleep", sleepMillis).Sc an(&op); err != nil && err != ErrNoRows {
920 t.Error(err)
921 }
922 }()
923 }
924 // Sleep for twice the expected length of time for the
925 // batch of 50 queries above to finish before starting
926 // the next round.
927 time.Sleep(2 * sleepMillis * time.Millisecond)
928 }
929 wg.Wait()
930
931 if g, w := db.numFreeConns(), 10; g != w {
932 t.Errorf("free conns = %d; want %d", g, w)
933 }
934
935 if n := db.numDepsPollUntil(20, time.Second); n > 20 {
936 t.Errorf("number of dependencies = %d; expected <= 20", n)
937 db.dumpDeps(t)
938 }
939
940 driver.mu.Lock()
941 opens := driver.openCount - opens0
942 closes := driver.closeCount - closes0
943 driver.mu.Unlock()
944
945 if opens > 10 {
946 t.Logf("open calls = %d", opens)
947 t.Logf("close calls = %d", closes)
948 t.Errorf("db connections opened = %d; want <= 10", opens)
949 db.dumpDeps(t)
950 }
951
952 if err := stmt.Close(); err != nil {
953 t.Fatal(err)
954 }
955
956 if g, w := db.numFreeConns(), 10; g != w {
957 t.Errorf("free conns = %d; want %d", g, w)
958 }
959
960 if n := db.numDepsPollUntil(10, time.Second); n > 10 {
961 t.Errorf("number of dependencies = %d; expected <= 10", n)
962 db.dumpDeps(t)
963 }
964
965 db.SetMaxOpenConns(5)
966
967 if g, w := db.numFreeConns(), 5; g != w {
968 t.Errorf("free conns = %d; want %d", g, w)
969 }
970
971 if n := db.numDepsPollUntil(5, time.Second); n > 5 {
972 t.Errorf("number of dependencies = %d; expected 0", n)
973 db.dumpDeps(t)
974 }
975
976 db.SetMaxOpenConns(0)
977
978 if g, w := db.numFreeConns(), 5; g != w {
979 t.Errorf("free conns = %d; want %d", g, w)
980 }
981
982 if n := db.numDepsPollUntil(5, time.Second); n > 5 {
983 t.Errorf("number of dependencies = %d; expected 0", n)
984 db.dumpDeps(t)
985 }
986
987 db.SetMaxIdleConns(0)
988
989 if g, w := db.numFreeConns(), 0; g != w {
990 t.Errorf("free conns = %d; want %d", g, w)
991 }
992
993 if n := db.numDepsPollUntil(0, time.Second); n > 0 {
994 t.Errorf("number of dependencies = %d; expected 0", n)
995 db.dumpDeps(t)
996 }
997 }
998
864 // golang.org/issue/5323 999 // golang.org/issue/5323
865 func TestStmtCloseDeps(t *testing.T) { 1000 func TestStmtCloseDeps(t *testing.T) {
866 if testing.Short() { 1001 if testing.Short() {
867 t.Skip("skipping in short mode") 1002 t.Skip("skipping in short mode")
868 } 1003 }
869 defer setHookpostCloseConn(nil) 1004 defer setHookpostCloseConn(nil)
870 setHookpostCloseConn(func(_ *fakeConn, err error) { 1005 setHookpostCloseConn(func(_ *fakeConn, err error) {
871 if err != nil { 1006 if err != nil {
872 t.Errorf("Error closing fakeConn: %v", err) 1007 t.Errorf("Error closing fakeConn: %v", err)
873 } 1008 }
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
919 } 1054 }
920 1055
921 if n := db.numDepsPollUntil(4, time.Second); n > 4 { 1056 if n := db.numDepsPollUntil(4, time.Second); n > 4 {
922 t.Errorf("number of dependencies = %d; expected <= 4", n) 1057 t.Errorf("number of dependencies = %d; expected <= 4", n)
923 db.dumpDeps(t) 1058 db.dumpDeps(t)
924 } 1059 }
925 1060
926 driver.mu.Lock() 1061 driver.mu.Lock()
927 opens := driver.openCount - opens0 1062 opens := driver.openCount - opens0
928 closes := driver.closeCount - closes0 1063 closes := driver.closeCount - closes0
1064 openDelta := (driver.openCount - driver.closeCount) - openDelta0
929 driver.mu.Unlock() 1065 driver.mu.Unlock()
930 openDelta := (driver.openCount - driver.closeCount) - openDelta0
931 1066
932 if openDelta > 2 { 1067 if openDelta > 2 {
933 t.Logf("open calls = %d", opens) 1068 t.Logf("open calls = %d", opens)
934 t.Logf("close calls = %d", closes) 1069 t.Logf("close calls = %d", closes)
935 t.Logf("open delta = %d", openDelta) 1070 t.Logf("open delta = %d", openDelta)
936 t.Errorf("db connections opened = %d; want <= 2", openDelta) 1071 t.Errorf("db connections opened = %d; want <= 2", openDelta)
937 db.dumpDeps(t) 1072 db.dumpDeps(t)
938 } 1073 }
939 1074
940 if len(stmt.css) > nquery { 1075 if len(stmt.css) > nquery {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
978 db.dumpDeps(t) 1113 db.dumpDeps(t)
979 t.Errorf("DB = %#v", db) 1114 t.Errorf("DB = %#v", db)
980 } 1115 }
981 }) 1116 })
982 1117
983 stmt, err := db.Prepare("SELECT|people|name|") 1118 stmt, err := db.Prepare("SELECT|people|name|")
984 if err != nil { 1119 if err != nil {
985 t.Fatal(err) 1120 t.Fatal(err)
986 } 1121 }
987 1122
988 » if len(db.freeConn) != 1 { 1123 » if db.freeConn.Len() != 1 {
989 » » t.Fatalf("expected 1 freeConn; got %d", len(db.freeConn)) 1124 » » t.Fatalf("expected 1 freeConn; got %d", db.freeConn.Len())
990 } 1125 }
991 » dc := db.freeConn[0] 1126 » dc := db.freeConn.Front().Value.(*driverConn)
992 if dc.closed { 1127 if dc.closed {
993 t.Errorf("conn shouldn't be closed") 1128 t.Errorf("conn shouldn't be closed")
994 } 1129 }
995 1130
996 if n := len(dc.openStmt); n != 1 { 1131 if n := len(dc.openStmt); n != 1 {
997 t.Errorf("driverConn num openStmt = %d; want 1", n) 1132 t.Errorf("driverConn num openStmt = %d; want 1", n)
998 } 1133 }
999 err = db.Close() 1134 err = db.Close()
1000 if err != nil { 1135 if err != nil {
1001 t.Errorf("db Close = %v", err) 1136 t.Errorf("db Close = %v", err)
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
1075 db.SetMaxIdleConns(0) 1210 db.SetMaxIdleConns(0)
1076 setStrictFakeConnClose(t) 1211 setStrictFakeConnClose(t)
1077 defer setStrictFakeConnClose(nil) 1212 defer setStrictFakeConnClose(nil)
1078 1213
1079 _, err := db.Query("SELECT|non_existent|name|") 1214 _, err := db.Query("SELECT|non_existent|name|")
1080 if err == nil { 1215 if err == nil {
1081 t.Fatal("Quering non-existent table should fail") 1216 t.Fatal("Quering non-existent table should fail")
1082 } 1217 }
1083 } 1218 }
1084 1219
1220 type concurrentTest interface {
1221 init(t testing.TB, db *DB)
1222 fini(t testing.TB)
bradfitz 2013/08/30 02:47:52 fini isn't a word or common abbreviation Could yo
Tad Glines 2013/08/30 03:37:55 Done
1223 test(t testing.TB) error
1224 }
1225
1226 type concurrentDBQueryTest struct {
1227 db *DB
1228 }
1229
1230 func (c *concurrentDBQueryTest) init(t testing.TB, db *DB) {
1231 c.db = db
1232 }
1233
1234 func (c *concurrentDBQueryTest) fini(t testing.TB) {
1235 c.db = nil
1236 }
1237
1238 func (c *concurrentDBQueryTest) test(t testing.TB) error {
1239 rows, err := c.db.Query("SELECT|people|name|")
1240 if err != nil {
1241 t.Error(err)
1242 return err
1243 }
1244 var name string
1245 for rows.Next() {
1246 rows.Scan(&name)
1247 }
1248 rows.Close()
1249 return nil
1250 }
1251
1252 type concurrentDBExecTest struct {
1253 db *DB
1254 }
1255
1256 func (c *concurrentDBExecTest) init(t testing.TB, db *DB) {
1257 c.db = db
1258 }
1259
1260 func (c *concurrentDBExecTest) fini(t testing.TB) {
1261 c.db = nil
1262 }
1263
1264 func (c *concurrentDBExecTest) test(t testing.TB) error {
1265 _, err := c.db.Exec("NOSERT|people|name=Chris,age=?,photo=CPHOTO,bdate=? ", 3, chrisBirthday)
1266 if err != nil {
1267 t.Error(err)
1268 return err
1269 }
1270 return nil
1271 }
1272
1273 type concurrentStmtQueryTest struct {
1274 db *DB
1275 stmt *Stmt
1276 }
1277
1278 func (c *concurrentStmtQueryTest) init(t testing.TB, db *DB) {
1279 c.db = db
1280 var err error
1281 c.stmt, err = db.Prepare("SELECT|people|name|")
1282 if err != nil {
1283 t.Fatal(err)
1284 }
1285 }
1286
1287 func (c *concurrentStmtQueryTest) fini(t testing.TB) {
1288 if c.stmt != nil {
1289 c.stmt.Close()
1290 c.stmt = nil
1291 }
1292 c.db = nil
1293 }
1294
1295 func (c *concurrentStmtQueryTest) test(t testing.TB) error {
1296 rows, err := c.stmt.Query()
1297 if err != nil {
1298 t.Errorf("error on query: %v", err)
1299 return err
1300 }
1301
1302 var name string
1303 for rows.Next() {
1304 rows.Scan(&name)
1305 }
1306 rows.Close()
1307 return nil
1308 }
1309
1310 type concurrentStmtExecTest struct {
1311 db *DB
1312 stmt *Stmt
1313 }
1314
1315 func (c *concurrentStmtExecTest) init(t testing.TB, db *DB) {
1316 c.db = db
1317 var err error
1318 c.stmt, err = db.Prepare("NOSERT|people|name=Chris,age=?,photo=CPHOTO,bd ate=?")
1319 if err != nil {
1320 t.Fatal(err)
1321 }
1322 }
1323
1324 func (c *concurrentStmtExecTest) fini(t testing.TB) {
1325 if c.stmt != nil {
1326 c.stmt.Close()
1327 c.stmt = nil
1328 }
1329 c.db = nil
1330 }
1331
1332 func (c *concurrentStmtExecTest) test(t testing.TB) error {
1333 _, err := c.stmt.Exec(3, chrisBirthday)
1334 if err != nil {
1335 t.Errorf("error on exec: %v", err)
1336 return err
1337 }
1338 return nil
1339 }
1340
1341 type concurrentTxQueryTest struct {
1342 db *DB
1343 tx *Tx
1344 }
1345
1346 func (c *concurrentTxQueryTest) init(t testing.TB, db *DB) {
1347 c.db = db
1348 var err error
1349 c.tx, err = c.db.Begin()
1350 if err != nil {
1351 t.Fatal(err)
1352 }
1353 }
1354
1355 func (c *concurrentTxQueryTest) fini(t testing.TB) {
1356 if c.tx != nil {
1357 c.tx.Rollback()
1358 c.tx = nil
1359 }
1360 c.db = nil
1361 }
1362
1363 func (c *concurrentTxQueryTest) test(t testing.TB) error {
1364 rows, err := c.db.Query("SELECT|people|name|")
1365 if err != nil {
1366 t.Error(err)
1367 return err
1368 }
1369 var name string
1370 for rows.Next() {
1371 rows.Scan(&name)
1372 }
1373 rows.Close()
1374 return nil
1375 }
1376
1377 type concurrentTxExecTest struct {
1378 db *DB
1379 tx *Tx
1380 }
1381
1382 func (c *concurrentTxExecTest) init(t testing.TB, db *DB) {
1383 c.db = db
1384 var err error
1385 c.tx, err = c.db.Begin()
1386 if err != nil {
1387 t.Fatal(err)
1388 }
1389 }
1390
1391 func (c *concurrentTxExecTest) fini(t testing.TB) {
1392 if c.tx != nil {
1393 c.tx.Rollback()
1394 c.tx = nil
1395 }
1396 c.db = nil
1397 }
1398
1399 func (c *concurrentTxExecTest) test(t testing.TB) error {
1400 _, err := c.tx.Exec("NOSERT|people|name=Chris,age=?,photo=CPHOTO,bdate=? ", 3, chrisBirthday)
1401 if err != nil {
1402 t.Error(err)
1403 return err
1404 }
1405 return nil
1406 }
1407
1408 type concurrentTxStmtQueryTest struct {
1409 db *DB
1410 tx *Tx
1411 stmt *Stmt
1412 }
1413
1414 func (c *concurrentTxStmtQueryTest) init(t testing.TB, db *DB) {
1415 c.db = db
1416 var err error
1417 c.tx, err = c.db.Begin()
1418 if err != nil {
1419 t.Fatal(err)
1420 }
1421 c.stmt, err = c.tx.Prepare("SELECT|people|name|")
1422 if err != nil {
1423 t.Fatal(err)
1424 }
1425 }
1426
1427 func (c *concurrentTxStmtQueryTest) fini(t testing.TB) {
1428 if c.stmt != nil {
1429 c.stmt.Close()
1430 c.stmt = nil
1431 }
1432 if c.tx != nil {
1433 c.tx.Rollback()
1434 c.tx = nil
1435 }
1436 c.db = nil
1437 }
1438
1439 func (c *concurrentTxStmtQueryTest) test(t testing.TB) error {
1440 rows, err := c.stmt.Query()
1441 if err != nil {
1442 t.Errorf("error on query: %v", err)
1443 return err
1444 }
1445
1446 var name string
1447 for rows.Next() {
1448 rows.Scan(&name)
1449 }
1450 rows.Close()
1451 return nil
1452 }
1453
1454 type concurrentTxStmtExecTest struct {
1455 db *DB
1456 tx *Tx
1457 stmt *Stmt
1458 }
1459
1460 func (c *concurrentTxStmtExecTest) init(t testing.TB, db *DB) {
1461 c.db = db
1462 var err error
1463 c.tx, err = c.db.Begin()
1464 if err != nil {
1465 t.Fatal(err)
1466 }
1467 c.stmt, err = c.tx.Prepare("NOSERT|people|name=Chris,age=?,photo=CPHOTO, bdate=?")
1468 if err != nil {
1469 t.Fatal(err)
1470 }
1471 }
1472
1473 func (c *concurrentTxStmtExecTest) fini(t testing.TB) {
1474 if c.stmt != nil {
1475 c.stmt.Close()
1476 c.stmt = nil
1477 }
1478 if c.tx != nil {
1479 c.tx.Rollback()
1480 c.tx = nil
1481 }
1482 c.db = nil
1483 }
1484
1485 func (c *concurrentTxStmtExecTest) test(t testing.TB) error {
1486 _, err := c.stmt.Exec(3, chrisBirthday)
1487 if err != nil {
1488 t.Errorf("error on exec: %v", err)
1489 return err
1490 }
1491 return nil
1492 }
1493
1494 type concurrentRandomTest struct {
1495 tests []concurrentTest
1496 }
1497
1498 func (c *concurrentRandomTest) init(t testing.TB, db *DB) {
1499 c.tests = []concurrentTest{
1500 new(concurrentDBQueryTest),
1501 new(concurrentDBExecTest),
1502 new(concurrentStmtQueryTest),
1503 new(concurrentStmtExecTest),
1504 new(concurrentTxQueryTest),
1505 new(concurrentTxExecTest),
1506 new(concurrentTxStmtQueryTest),
1507 new(concurrentTxStmtExecTest),
1508 }
1509 for _, ct := range c.tests {
1510 ct.init(t, db)
1511 }
1512 }
1513
1514 func (c *concurrentRandomTest) fini(t testing.TB) {
1515 for _, ct := range c.tests {
1516 ct.fini(t)
1517 }
1518 }
1519
1520 func (c *concurrentRandomTest) test(t testing.TB) error {
1521 ct := c.tests[rand.Intn(len(c.tests))]
1522 return ct.test(t)
1523 }
1524
1525 func doConcurrentTest(t testing.TB, ct concurrentTest) {
1526 maxProcs, numReqs := 1, 500
1527 if testing.Short() {
1528 maxProcs, numReqs = 4, 50
1529 }
1530 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs))
1531
1532 db := newTestDB(t, "people")
1533 defer closeDB(t, db)
1534
1535 ct.init(t, db)
1536 defer ct.fini(t)
1537
1538 var wg sync.WaitGroup
1539 wg.Add(numReqs)
1540
1541 reqs := make(chan bool)
1542 defer close(reqs)
1543
1544 for i := 0; i < maxProcs*2; i++ {
1545 go func() {
1546 for _ = range reqs {
1547 err := ct.test(t)
1548 if err != nil {
1549 wg.Done()
1550 continue
1551 }
1552 wg.Done()
1553 }
1554 }()
1555 }
1556
1557 for i := 0; i < numReqs; i++ {
1558 reqs <- true
1559 }
1560
1561 wg.Wait()
1562 }
1563
1085 func manyConcurrentQueries(t testing.TB) { 1564 func manyConcurrentQueries(t testing.TB) {
1086 maxProcs, numReqs := 16, 500 1565 maxProcs, numReqs := 16, 500
1087 if testing.Short() { 1566 if testing.Short() {
1088 maxProcs, numReqs = 4, 50 1567 maxProcs, numReqs = 4, 50
1089 } 1568 }
1090 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs)) 1569 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs))
1091 1570
1092 db := newTestDB(t, "people") 1571 db := newTestDB(t, "people")
1093 defer closeDB(t, db) 1572 defer closeDB(t, db)
1094 1573
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
1171 drv.mu.Unlock() 1650 drv.mu.Unlock()
1172 if opens < 9 { 1651 if opens < 9 {
1173 t.Errorf("opens = %d; want >= 9", opens) 1652 t.Errorf("opens = %d; want >= 9", opens)
1174 } 1653 }
1175 if closes < 9 { 1654 if closes < 9 {
1176 t.Errorf("closes = %d; want >= 9", closes) 1655 t.Errorf("closes = %d; want >= 9", closes)
1177 } 1656 }
1178 } 1657 }
1179 1658
1180 func TestConcurrency(t *testing.T) { 1659 func TestConcurrency(t *testing.T) {
1181 » manyConcurrentQueries(t) 1660 » doConcurrentTest(t, new(concurrentDBQueryTest))
1661 » doConcurrentTest(t, new(concurrentDBExecTest))
1662 » doConcurrentTest(t, new(concurrentStmtQueryTest))
1663 » doConcurrentTest(t, new(concurrentStmtExecTest))
1664 » doConcurrentTest(t, new(concurrentTxQueryTest))
1665 » doConcurrentTest(t, new(concurrentTxExecTest))
1666 » doConcurrentTest(t, new(concurrentTxStmtQueryTest))
1667 » doConcurrentTest(t, new(concurrentTxStmtExecTest))
1668 » doConcurrentTest(t, new(concurrentRandomTest))
1182 } 1669 }
1183 1670
1184 func BenchmarkConcurrency(b *testing.B) { 1671 func BenchmarkConcurrentDBExec(b *testing.B) {
1185 b.ReportAllocs() 1672 b.ReportAllocs()
1673 ct := new(concurrentDBExecTest)
1186 for i := 0; i < b.N; i++ { 1674 for i := 0; i < b.N; i++ {
1187 » » manyConcurrentQueries(b) 1675 » » doConcurrentTest(b, ct)
1188 } 1676 }
1189 } 1677 }
1678
1679 func BenchmarkConcurrentStmtQuery(b *testing.B) {
1680 b.ReportAllocs()
1681 ct := new(concurrentStmtQueryTest)
1682 for i := 0; i < b.N; i++ {
1683 doConcurrentTest(b, ct)
1684 }
1685 }
1686
1687 func BenchmarkConcurrentStmtExec(b *testing.B) {
1688 b.ReportAllocs()
1689 ct := new(concurrentStmtExecTest)
1690 for i := 0; i < b.N; i++ {
1691 doConcurrentTest(b, ct)
1692 }
1693 }
1694
1695 func BenchmarkConcurrentTxQuery(b *testing.B) {
1696 b.ReportAllocs()
1697 ct := new(concurrentTxQueryTest)
1698 for i := 0; i < b.N; i++ {
1699 doConcurrentTest(b, ct)
1700 }
1701 }
1702
1703 func BenchmarkConcurrentTxExec(b *testing.B) {
1704 b.ReportAllocs()
1705 ct := new(concurrentTxExecTest)
1706 for i := 0; i < b.N; i++ {
1707 doConcurrentTest(b, ct)
1708 }
1709 }
1710
1711 func BenchmarkConcurrentTxStmtQuery(b *testing.B) {
1712 b.ReportAllocs()
1713 ct := new(concurrentTxStmtQueryTest)
1714 for i := 0; i < b.N; i++ {
1715 doConcurrentTest(b, ct)
1716 }
1717 }
1718
1719 func BenchmarkConcurrentTxStmtExec(b *testing.B) {
1720 b.ReportAllocs()
1721 ct := new(concurrentTxStmtExecTest)
1722 for i := 0; i < b.N; i++ {
1723 doConcurrentTest(b, ct)
1724 }
1725 }
1726
1727 func BenchmarkConcurrentRandom(b *testing.B) {
1728 b.ReportAllocs()
1729 ct := new(concurrentRandomTest)
1730 for i := 0; i < b.N; i++ {
1731 doConcurrentTest(b, ct)
1732 }
1733 }
OLDNEW
« no previous file with comments | « src/pkg/database/sql/sql.go ('k') | src/pkg/go/build/deps_test.go » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b