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

Delta Between Two Patch Sets: src/pkg/database/sql/sql_test.go

Issue 13252046: code review 13252046: undo CL 10726044 / c9bea548fb6f (Closed)
Left Patch Set: Created 10 years, 7 months ago
Right Patch Set: diff -r c9bea548fb6f https://go.googlecode.com/hg/ 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:
Right: Side by side diff | Download
« no previous file with change/comment | « src/pkg/database/sql/sql.go ('k') | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
(no file at all)
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"
12 "reflect" 11 "reflect"
13 "runtime" 12 "runtime"
14 "strings" 13 "strings"
15 "sync" 14 "sync"
16 "testing" 15 "testing"
17 "time" 16 "time"
18 ) 17 )
19 18
20 func init() { 19 func init() {
21 type dbConn struct { 20 type dbConn struct {
22 db *DB 21 db *DB
23 c *driverConn 22 c *driverConn
24 } 23 }
25 freedFrom := make(map[dbConn]string) 24 freedFrom := make(map[dbConn]string)
26 putConnHook = func(db *DB, c *driverConn) { 25 putConnHook = func(db *DB, c *driverConn) {
27 » » if c.listElem != nil { 26 » » for _, oc := range db.freeConn {
28 » » » // print before panic, as panic may get lost due to conf licting panic 27 » » » if oc == c {
29 » » » // (all goroutines asleep) elsewhere, since we might not unlock 28 » » » » // print before panic, as panic may get lost due to conflicting panic
30 » » » // the mutex in freeConn here. 29 » » » » // (all goroutines asleep) elsewhere, since we m ight not unlock
31 » » » println("double free of conn. conflicts are:\nA) " + fre edFrom[dbConn{db, c}] + "\n\nand\nB) " + stack()) 30 » » » » // the mutex in freeConn here.
32 » » » panic("double free of conn.") 31 » » » » println("double free of conn. conflicts are:\nA) " + freedFrom[dbConn{db, c}] + "\n\nand\nB) " + stack())
32 » » » » panic("double free of conn.")
33 » » » }
33 } 34 }
34 freedFrom[dbConn{db, c}] = stack() 35 freedFrom[dbConn{db, c}] = stack()
35 } 36 }
36 } 37 }
37 38
38 const fakeDBName = "foo" 39 const fakeDBName = "foo"
39 40
40 var chrisBirthday = time.Unix(123456789, 0) 41 var chrisBirthday = time.Unix(123456789, 0)
41 42
42 func newTestDB(t testing.TB, name string) *DB { 43 func newTestDB(t testing.TB, name string) *DB {
(...skipping 29 matching lines...) Expand all
72 if e := recover(); e != nil { 73 if e := recover(); e != nil {
73 fmt.Printf("Panic: %v\n", e) 74 fmt.Printf("Panic: %v\n", e)
74 panic(e) 75 panic(e)
75 } 76 }
76 defer setHookpostCloseConn(nil) 77 defer setHookpostCloseConn(nil)
77 setHookpostCloseConn(func(_ *fakeConn, err error) { 78 setHookpostCloseConn(func(_ *fakeConn, err error) {
78 if err != nil { 79 if err != nil {
79 t.Errorf("Error closing fakeConn: %v", err) 80 t.Errorf("Error closing fakeConn: %v", err)
80 } 81 }
81 }) 82 })
82 » for node, i := db.freeConn.Front(), 0; node != nil; node, i = node.Next( ), i+1 { 83 » for i, dc := range db.freeConn {
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, db.freeConn.Len(), n) 90 » » » t.Errorf("while closing db, freeConn %d/%d had %d open s tmts; want 0", i, len(db.freeConn), 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 := db.freeConn.Len(); n != 1 { 102 » if n := len(db.freeConn); 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.Front().Value.(*driverConn)).ci.(*fakeConn).numPrepa re 105 » return db.freeConn[0].ci.(*fakeConn).numPrepare
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 db.freeConn.Len() 130 » return len(db.freeConn)
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 db.freeConn.Len() != 1 { 645 » if len(db.freeConn) != 1 {
646 t.Fatalf("expected 1 free conn") 646 t.Fatalf("expected 1 free conn")
647 } 647 }
648 » fakeConn := (db.freeConn.Front().Value.(*driverConn)).ci.(*fakeConn) 648 » fakeConn := db.freeConn[0].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 := db.freeConn.Len(); got != 1 { 844 » if got := len(db.freeConn); 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 := db.freeConn.Len(); got != 0 { 850 » if got := len(db.freeConn); 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 := db.freeConn.Len(); got != 0 { 859 » if got := len(db.freeConn); 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) { 864 // golang.org/issue/5323
865 func TestStmtCloseDeps(t *testing.T) {
865 if testing.Short() { 866 if testing.Short() {
866 t.Skip("skipping in short mode") 867 t.Skip("skipping in short mode")
867 } 868 }
868 defer setHookpostCloseConn(nil) 869 defer setHookpostCloseConn(nil)
869 setHookpostCloseConn(func(_ *fakeConn, err error) { 870 setHookpostCloseConn(func(_ *fakeConn, err error) {
870 if err != nil { 871 if err != nil {
871 t.Errorf("Error closing fakeConn: %v", err) 872 t.Errorf("Error closing fakeConn: %v", err)
872 } 873 }
873 }) 874 })
874 875
875 db := newTestDB(t, "magicquery") 876 db := newTestDB(t, "magicquery")
876 defer closeDB(t, db) 877 defer closeDB(t, db)
877 878
878 driver := db.driver.(*fakeDriver) 879 driver := db.driver.(*fakeDriver)
879 880
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() 881 driver.mu.Lock()
894 opens0 := driver.openCount 882 opens0 := driver.openCount
895 closes0 := driver.closeCount 883 closes0 := driver.closeCount
896 driver.mu.Unlock() 884 driver.mu.Unlock()
897 885 » openDelta0 := opens0 - closes0
898 » db.SetMaxIdleConns(10)
899 » db.SetMaxOpenConns(10)
900 886
901 stmt, err := db.Prepare("SELECT|magicquery|op|op=?,millis=?") 887 stmt, err := db.Prepare("SELECT|magicquery|op|op=?,millis=?")
902 if err != nil { 888 if err != nil {
903 t.Fatal(err) 889 t.Fatal(err)
904 } 890 }
905 891
906 // Start 50 parallel slow queries. 892 // Start 50 parallel slow queries.
907 const ( 893 const (
908 nquery = 50 894 nquery = 50
909 sleepMillis = 25 895 sleepMillis = 25
(...skipping 11 matching lines...) Expand all
921 } 907 }
922 }() 908 }()
923 } 909 }
924 // Sleep for twice the expected length of time for the 910 // Sleep for twice the expected length of time for the
925 // batch of 50 queries above to finish before starting 911 // batch of 50 queries above to finish before starting
926 // the next round. 912 // the next round.
927 time.Sleep(2 * sleepMillis * time.Millisecond) 913 time.Sleep(2 * sleepMillis * time.Millisecond)
928 } 914 }
929 wg.Wait() 915 wg.Wait()
930 916
931 » if g, w := db.numFreeConns(), 10; g != w { 917 » if g, w := db.numFreeConns(), 2; g != w {
932 t.Errorf("free conns = %d; want %d", g, w) 918 t.Errorf("free conns = %d; want %d", g, w)
933 } 919 }
934 920
935 » if n := db.numDepsPollUntil(20, time.Second); n > 20 { 921 » if n := db.numDepsPollUntil(4, time.Second); n > 4 {
936 » » t.Errorf("number of dependencies = %d; expected <= 20", n) 922 » » t.Errorf("number of dependencies = %d; expected <= 4", n)
937 db.dumpDeps(t) 923 db.dumpDeps(t)
938 } 924 }
939 925
940 driver.mu.Lock() 926 driver.mu.Lock()
941 opens := driver.openCount - opens0 927 opens := driver.openCount - opens0
942 closes := driver.closeCount - closes0 928 closes := driver.closeCount - closes0
943 driver.mu.Unlock() 929 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
999 // golang.org/issue/5323
1000 func TestStmtCloseDeps(t *testing.T) {
1001 if testing.Short() {
1002 t.Skip("skipping in short mode")
1003 }
1004 defer setHookpostCloseConn(nil)
1005 setHookpostCloseConn(func(_ *fakeConn, err error) {
1006 if err != nil {
1007 t.Errorf("Error closing fakeConn: %v", err)
1008 }
1009 })
1010
1011 db := newTestDB(t, "magicquery")
1012 defer closeDB(t, db)
1013
1014 driver := db.driver.(*fakeDriver)
1015
1016 driver.mu.Lock()
1017 opens0 := driver.openCount
1018 closes0 := driver.closeCount
1019 driver.mu.Unlock()
1020 openDelta0 := opens0 - closes0
1021
1022 stmt, err := db.Prepare("SELECT|magicquery|op|op=?,millis=?")
1023 if err != nil {
1024 t.Fatal(err)
1025 }
1026
1027 // Start 50 parallel slow queries.
1028 const (
1029 nquery = 50
1030 sleepMillis = 25
1031 nbatch = 2
1032 )
1033 var wg sync.WaitGroup
1034 for batch := 0; batch < nbatch; batch++ {
1035 for i := 0; i < nquery; i++ {
1036 wg.Add(1)
1037 go func() {
1038 defer wg.Done()
1039 var op string
1040 if err := stmt.QueryRow("sleep", sleepMillis).Sc an(&op); err != nil && err != ErrNoRows {
1041 t.Error(err)
1042 }
1043 }()
1044 }
1045 // Sleep for twice the expected length of time for the
1046 // batch of 50 queries above to finish before starting
1047 // the next round.
1048 time.Sleep(2 * sleepMillis * time.Millisecond)
1049 }
1050 wg.Wait()
1051
1052 if g, w := db.numFreeConns(), 2; g != w {
1053 t.Errorf("free conns = %d; want %d", g, w)
1054 }
1055
1056 if n := db.numDepsPollUntil(4, time.Second); n > 4 {
1057 t.Errorf("number of dependencies = %d; expected <= 4", n)
1058 db.dumpDeps(t)
1059 }
1060
1061 driver.mu.Lock()
1062 opens := driver.openCount - opens0
1063 closes := driver.closeCount - closes0
1064 openDelta := (driver.openCount - driver.closeCount) - openDelta0 930 openDelta := (driver.openCount - driver.closeCount) - openDelta0
1065 driver.mu.Unlock()
1066 931
1067 if openDelta > 2 { 932 if openDelta > 2 {
1068 t.Logf("open calls = %d", opens) 933 t.Logf("open calls = %d", opens)
1069 t.Logf("close calls = %d", closes) 934 t.Logf("close calls = %d", closes)
1070 t.Logf("open delta = %d", openDelta) 935 t.Logf("open delta = %d", openDelta)
1071 t.Errorf("db connections opened = %d; want <= 2", openDelta) 936 t.Errorf("db connections opened = %d; want <= 2", openDelta)
1072 db.dumpDeps(t) 937 db.dumpDeps(t)
1073 } 938 }
1074 939
1075 if len(stmt.css) > nquery { 940 if len(stmt.css) > nquery {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1113 db.dumpDeps(t) 978 db.dumpDeps(t)
1114 t.Errorf("DB = %#v", db) 979 t.Errorf("DB = %#v", db)
1115 } 980 }
1116 }) 981 })
1117 982
1118 stmt, err := db.Prepare("SELECT|people|name|") 983 stmt, err := db.Prepare("SELECT|people|name|")
1119 if err != nil { 984 if err != nil {
1120 t.Fatal(err) 985 t.Fatal(err)
1121 } 986 }
1122 987
1123 » if db.freeConn.Len() != 1 { 988 » if len(db.freeConn) != 1 {
1124 » » t.Fatalf("expected 1 freeConn; got %d", db.freeConn.Len()) 989 » » t.Fatalf("expected 1 freeConn; got %d", len(db.freeConn))
1125 » } 990 » }
1126 » dc := db.freeConn.Front().Value.(*driverConn) 991 » dc := db.freeConn[0]
1127 if dc.closed { 992 if dc.closed {
1128 t.Errorf("conn shouldn't be closed") 993 t.Errorf("conn shouldn't be closed")
1129 } 994 }
1130 995
1131 if n := len(dc.openStmt); n != 1 { 996 if n := len(dc.openStmt); n != 1 {
1132 t.Errorf("driverConn num openStmt = %d; want 1", n) 997 t.Errorf("driverConn num openStmt = %d; want 1", n)
1133 } 998 }
1134 err = db.Close() 999 err = db.Close()
1135 if err != nil { 1000 if err != nil {
1136 t.Errorf("db Close = %v", err) 1001 t.Errorf("db Close = %v", err)
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
1208 defer closeDB(t, db) 1073 defer closeDB(t, db)
1209 1074
1210 db.SetMaxIdleConns(0) 1075 db.SetMaxIdleConns(0)
1211 setStrictFakeConnClose(t) 1076 setStrictFakeConnClose(t)
1212 defer setStrictFakeConnClose(nil) 1077 defer setStrictFakeConnClose(nil)
1213 1078
1214 _, err := db.Query("SELECT|non_existent|name|") 1079 _, err := db.Query("SELECT|non_existent|name|")
1215 if err == nil { 1080 if err == nil {
1216 t.Fatal("Quering non-existent table should fail") 1081 t.Fatal("Quering non-existent table should fail")
1217 } 1082 }
1218 }
1219
1220 type concurrentTest interface {
1221 init(t testing.TB, db *DB)
1222 finish(t testing.TB)
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) finish(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) finish(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) finish(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) finish(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) finish(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) finish(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) finish(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) finish(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) finish(t testing.TB) {
1515 for _, ct := range c.tests {
1516 ct.finish(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.finish(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 } 1083 }
1563 1084
1564 func manyConcurrentQueries(t testing.TB) { 1085 func manyConcurrentQueries(t testing.TB) {
1565 maxProcs, numReqs := 16, 500 1086 maxProcs, numReqs := 16, 500
1566 if testing.Short() { 1087 if testing.Short() {
1567 maxProcs, numReqs = 4, 50 1088 maxProcs, numReqs = 4, 50
1568 } 1089 }
1569 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs)) 1090 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs))
1570 1091
1571 db := newTestDB(t, "people") 1092 db := newTestDB(t, "people")
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
1650 drv.mu.Unlock() 1171 drv.mu.Unlock()
1651 if opens < 9 { 1172 if opens < 9 {
1652 t.Errorf("opens = %d; want >= 9", opens) 1173 t.Errorf("opens = %d; want >= 9", opens)
1653 } 1174 }
1654 if closes < 9 { 1175 if closes < 9 {
1655 t.Errorf("closes = %d; want >= 9", closes) 1176 t.Errorf("closes = %d; want >= 9", closes)
1656 } 1177 }
1657 } 1178 }
1658 1179
1659 func TestConcurrency(t *testing.T) { 1180 func TestConcurrency(t *testing.T) {
1660 » doConcurrentTest(t, new(concurrentDBQueryTest)) 1181 » manyConcurrentQueries(t)
1661 » doConcurrentTest(t, new(concurrentDBExecTest)) 1182 }
1662 » doConcurrentTest(t, new(concurrentStmtQueryTest)) 1183
1663 » doConcurrentTest(t, new(concurrentStmtExecTest)) 1184 func BenchmarkConcurrency(b *testing.B) {
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))
1669 }
1670
1671 func BenchmarkConcurrentDBExec(b *testing.B) {
1672 b.ReportAllocs() 1185 b.ReportAllocs()
1673 ct := new(concurrentDBExecTest)
1674 for i := 0; i < b.N; i++ { 1186 for i := 0; i < b.N; i++ {
1675 » » doConcurrentTest(b, ct) 1187 » » manyConcurrentQueries(b)
1676 » } 1188 » }
1677 } 1189 }
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 }
LEFTRIGHT

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