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

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

Issue 8836045: code review 8836045: database/sql: fix driver Conn refcounting with prepared... (Closed)
Patch Set: diff -r 0c16e97c7587 https://go.googlecode.com/hg/ Created 11 years, 11 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
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 provides a generic interface around SQL (or SQL-like) 5 // Package sql provides a generic interface around SQL (or SQL-like)
6 // databases. 6 // databases.
7 // 7 //
8 // The sql package must be used in conjunction with a database driver. 8 // The sql package must be used in conjunction with a database driver.
9 // See http://golang.org/s/sqldrivers for a list of drivers. 9 // See http://golang.org/s/sqldrivers for a list of drivers.
10 package sql 10 package sql
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
200 maxIdle int // zero means defaultMaxIdleConns; negat ive means 0 200 maxIdle int // zero means defaultMaxIdleConns; negat ive means 0
201 } 201 }
202 202
203 // driverConn wraps a driver.Conn with a mutex, to 203 // driverConn wraps a driver.Conn with a mutex, to
204 // be held during all calls into the Conn. (including any calls onto 204 // be held during all calls into the Conn. (including any calls onto
205 // interfaces returned via that Conn, such as calls on Tx, Stmt, 205 // interfaces returned via that Conn, such as calls on Tx, Stmt,
206 // Result, Rows) 206 // Result, Rows)
207 type driverConn struct { 207 type driverConn struct {
208 db *DB 208 db *DB
209 209
210 » sync.Mutex // guards following 210 » sync.Mutex // guards following
211 » ci driver.Conn 211 » ci driver.Conn
212 » closed bool 212 » closed bool
213 » finalClosed bool // ci.Close has been called
214 » openStmt map[driver.Stmt]bool
213 215
214 // guarded by db.mu 216 // guarded by db.mu
215 » inUse bool 217 » inUse bool
216 » onPut []func() // code (with db.mu held) run when conn is next returned 218 » onPut []func() // code (with db.mu held) run when conn is next retu rned
219 » dbmuClosed bool // same as closed, but guarded by db.mu, for connIfF ree
220 }
221
222 func (dc *driverConn) removeOpenStmt(si driver.Stmt) {
223 » dc.Lock()
224 » defer dc.Unlock()
225 » delete(dc.openStmt, si)
226 }
227
228 func (dc *driverConn) prepareLocked(query string) (driver.Stmt, error) {
229 » si, err := dc.ci.Prepare(query)
230 » if err == nil {
231 » » // Track each driverConn's open statements, so we can close them
232 » » // before closing the conn.
233 » » //
234 » » // TODO(bradfitz): let drivers opt-out of caring about
r 2013/04/25 20:09:17 s/-/ / (it's a verb not an adjective)
bradfitz 2013/04/25 21:46:10 Done.
235 » » // stmt closes if the conn is about to close anyway? For now
236 » » // do the safe thing, in case stmts need to be closed.
237 » » //
238 » » // TODO(bradfitz): after Go 1.1, closing driver.Stmts
239 » » // should be moved to driverStmt, using unique
240 » » // *driverStmts everywhere (including from
241 » » // *Stmt.connStmt, instead of returning a
242 » » // driver.Stmt), using driverStmt as a pointer
243 » » // everywhere, and making it a finalCloser.
244 » » if dc.openStmt == nil {
245 » » » dc.openStmt = make(map[driver.Stmt]bool)
246 » » }
247 » » dc.openStmt[si] = true
248 » }
249 » return si, err
217 } 250 }
218 251
219 // the dc.db's Mutex is held. 252 // the dc.db's Mutex is held.
220 func (dc *driverConn) closeDBLocked() error { 253 func (dc *driverConn) closeDBLocked() error {
221 dc.Lock() 254 dc.Lock()
222 if dc.closed { 255 if dc.closed {
223 dc.Unlock() 256 dc.Unlock()
224 return errors.New("sql: duplicate driverConn close") 257 return errors.New("sql: duplicate driverConn close")
225 } 258 }
226 dc.closed = true 259 dc.closed = true
227 dc.Unlock() // not defer; removeDep finalClose calls may need to lock 260 dc.Unlock() // not defer; removeDep finalClose calls may need to lock
228 return dc.db.removeDepLocked(dc, dc)() 261 return dc.db.removeDepLocked(dc, dc)()
229 } 262 }
230 263
231 func (dc *driverConn) Close() error { 264 func (dc *driverConn) Close() error {
232 dc.Lock() 265 dc.Lock()
233 if dc.closed { 266 if dc.closed {
234 dc.Unlock() 267 dc.Unlock()
235 return errors.New("sql: duplicate driverConn close") 268 return errors.New("sql: duplicate driverConn close")
236 } 269 }
237 dc.closed = true 270 dc.closed = true
238 dc.Unlock() // not defer; removeDep finalClose calls may need to lock 271 dc.Unlock() // not defer; removeDep finalClose calls may need to lock
239 » return dc.db.removeDep(dc, dc) 272
273 » // And now updates that require holding dc.mu.Lock()
274 » dc.db.mu.Lock()
275 » dc.dbmuClosed = true
276 » fn := dc.db.removeDepLocked(dc, dc)
277 » dc.db.mu.Unlock()
278 » return fn()
240 } 279 }
241 280
242 func (dc *driverConn) finalClose() error { 281 func (dc *driverConn) finalClose() error {
243 dc.Lock() 282 dc.Lock()
283
284 for si := range dc.openStmt {
285 si.Close()
286 }
287 dc.openStmt = nil
288
244 err := dc.ci.Close() 289 err := dc.ci.Close()
245 dc.ci = nil 290 dc.ci = nil
291 dc.finalClosed = true
292
246 dc.Unlock() 293 dc.Unlock()
247 return err 294 return err
248 } 295 }
249 296
250 // driverStmt associates a driver.Stmt with the 297 // driverStmt associates a driver.Stmt with the
251 // *driverConn from which it came, so the driverConn's lock can be 298 // *driverConn from which it came, so the driverConn's lock can be
252 // held during calls. 299 // held during calls.
253 type driverStmt struct { 300 type driverStmt struct {
254 sync.Locker // the *driverConn 301 sync.Locker // the *driverConn
255 si driver.Stmt 302 si driver.Stmt
256 } 303 }
257 304
258 func (ds *driverStmt) Close() error { 305 func (ds *driverStmt) Close() error {
259 ds.Lock() 306 ds.Lock()
260 defer ds.Unlock() 307 defer ds.Unlock()
261 return ds.si.Close() 308 return ds.si.Close()
262 } 309 }
263 310
264 // depSet is a finalCloser's outstanding dependencies 311 // depSet is a finalCloser's outstanding dependencies
265 type depSet map[interface{}]bool // set of true bools 312 type depSet map[interface{}]bool // set of true bools
266 313
267 // The finalCloser interface is used by (*DB).addDep and (*DB).get 314 // The finalCloser interface is used by (*DB).addDep and related
315 // dependency reference counting.
268 type finalCloser interface { 316 type finalCloser interface {
269 // finalClose is called when the reference count of an object 317 // finalClose is called when the reference count of an object
270 // goes to zero. (*DB).mu is not held while calling it. 318 // goes to zero. (*DB).mu is not held while calling it.
271 finalClose() error 319 finalClose() error
272 } 320 }
273 321
274 // addDep notes that x now depends on dep, and x's finalClose won't be 322 // addDep notes that x now depends on dep, and x's finalClose won't be
275 // called until all of x's dependencies are removed with removeDep. 323 // called until all of x's dependencies are removed with removeDep.
276 func (db *DB) addDep(x finalCloser, dep interface{}) { 324 func (db *DB) addDep(x finalCloser, dep interface{}) {
277 //println(fmt.Sprintf("addDep(%T %p, %T %p)", x, x, dep, dep)) 325 //println(fmt.Sprintf("addDep(%T %p, %T %p)", x, x, dep, dep))
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
441 db: db, 489 db: db,
442 ci: ci, 490 ci: ci,
443 } 491 }
444 db.mu.Lock() 492 db.mu.Lock()
445 db.addDepLocked(dc, dc) 493 db.addDepLocked(dc, dc)
446 dc.inUse = true 494 dc.inUse = true
447 db.mu.Unlock() 495 db.mu.Unlock()
448 return dc, nil 496 return dc, nil
449 } 497 }
450 498
451 // connIfFree returns (wanted, true) if wanted is still a valid conn and 499 var (
500 » errConnClosed = errors.New("database/sql: internal sentinel error: conn is closed")
501 » errConnBusy = errors.New("database/sql: internal sentinel error: conn is busy")
502 )
503
504 // connIfFree returns (wanted, nil) if wanted is still a valid conn and
452 // isn't in use. 505 // isn't in use.
453 // 506 //
454 // If wanted is valid but in use, connIfFree returns (wanted, false). 507 // The error is errConnClosed if the connection if the requested connection
455 // If wanted is invalid, connIfFre returns (nil, false). 508 // is invalid because it's been closed.
456 func (db *DB) connIfFree(wanted *driverConn) (conn *driverConn, ok bool) { 509 //
510 // The error is errConnBusy if the connection is in use.
511 func (db *DB) connIfFree(wanted *driverConn) (*driverConn, error) {
457 db.mu.Lock() 512 db.mu.Lock()
458 defer db.mu.Unlock() 513 defer db.mu.Unlock()
459 if wanted.inUse { 514 if wanted.inUse {
460 » » return conn, false 515 » » return nil, errConnBusy
516 » }
517 » if wanted.dbmuClosed {
518 » » return nil, errConnClosed
461 } 519 }
462 for i, conn := range db.freeConn { 520 for i, conn := range db.freeConn {
463 if conn != wanted { 521 if conn != wanted {
464 continue 522 continue
465 } 523 }
466 db.freeConn[i] = db.freeConn[len(db.freeConn)-1] 524 db.freeConn[i] = db.freeConn[len(db.freeConn)-1]
467 db.freeConn = db.freeConn[:len(db.freeConn)-1] 525 db.freeConn = db.freeConn[:len(db.freeConn)-1]
468 wanted.inUse = true 526 wanted.inUse = true
469 » » return wanted, true 527 » » return wanted, nil
470 } 528 }
471 » return nil, false 529 » // TODO(bradfitz): shouldn't get here. After Go 1.1, change this to:
530 » // panic("connIfFree call requested a non-closed, non-busy, non-free con n")
531 » // Which passes all the tests, but I'm too paranoid to include this
532 » // late in Go 1.1.
533 » // Instead, treat it like a busy connection:
534 » return nil, errConnBusy
472 } 535 }
473 536
474 // putConnHook is a hook for testing. 537 // putConnHook is a hook for testing.
475 var putConnHook func(*DB, *driverConn) 538 var putConnHook func(*DB, *driverConn)
476 539
477 // noteUnusedDriverStatement notes that si is no longer used and should 540 // noteUnusedDriverStatement notes that si is no longer used and should
478 // be closed whenever possible (when c is next not in use), unless c is 541 // be closed whenever possible (when c is next not in use), unless c is
479 // already closed. 542 // already closed.
480 func (db *DB) noteUnusedDriverStatement(c *driverConn, si driver.Stmt) { 543 func (db *DB) noteUnusedDriverStatement(c *driverConn, si driver.Stmt) {
481 db.mu.Lock() 544 db.mu.Lock()
482 defer db.mu.Unlock() 545 defer db.mu.Unlock()
483 if c.inUse { 546 if c.inUse {
484 c.onPut = append(c.onPut, func() { 547 c.onPut = append(c.onPut, func() {
485 si.Close() 548 si.Close()
486 }) 549 })
487 } else { 550 } else {
488 » » si.Close() 551 » » c.Lock()
552 » » defer c.Unlock()
553 » » if !c.finalClosed {
554 » » » si.Close()
555 » » }
489 } 556 }
490 } 557 }
491 558
492 // debugGetPut determines whether getConn & putConn calls' stack traces 559 // debugGetPut determines whether getConn & putConn calls' stack traces
493 // are returned for more verbose crashes. 560 // are returned for more verbose crashes.
494 const debugGetPut = false 561 const debugGetPut = false
495 562
496 // putConn adds a connection to the db's free pool. 563 // putConn adds a connection to the db's free pool.
497 // err is optionally the last error that occurred on this connection. 564 // err is optionally the last error that occurred on this connection.
498 func (db *DB) putConn(dc *driverConn, err error) { 565 func (db *DB) putConn(dc *driverConn, err error) {
(...skipping 20 matching lines...) Expand all
519 return 586 return
520 } 587 }
521 if putConnHook != nil { 588 if putConnHook != nil {
522 putConnHook(db, dc) 589 putConnHook(db, dc)
523 } 590 }
524 if n := len(db.freeConn); !db.closed && n < db.maxIdleConnsLocked() { 591 if n := len(db.freeConn); !db.closed && n < db.maxIdleConnsLocked() {
525 db.freeConn = append(db.freeConn, dc) 592 db.freeConn = append(db.freeConn, dc)
526 db.mu.Unlock() 593 db.mu.Unlock()
527 return 594 return
528 } 595 }
529 // TODO: check to see if we need this Conn for any prepared
530 // statements which are still active?
531 db.mu.Unlock() 596 db.mu.Unlock()
532 597
533 dc.Close() 598 dc.Close()
534 } 599 }
535 600
536 // Prepare creates a prepared statement for later queries or executions. 601 // Prepare creates a prepared statement for later queries or executions.
537 // Multiple queries or executions may be run concurrently from the 602 // Multiple queries or executions may be run concurrently from the
538 // returned statement. 603 // returned statement.
539 func (db *DB) Prepare(query string) (*Stmt, error) { 604 func (db *DB) Prepare(query string) (*Stmt, error) {
540 var stmt *Stmt 605 var stmt *Stmt
(...skipping 12 matching lines...) Expand all
553 // driver.Preparer interface and call that instead, if so, 618 // driver.Preparer interface and call that instead, if so,
554 // otherwise we make a prepared statement that's bound 619 // otherwise we make a prepared statement that's bound
555 // to a connection, and to execute this prepared statement 620 // to a connection, and to execute this prepared statement
556 // we either need to use this connection (if it's free), else 621 // we either need to use this connection (if it's free), else
557 // get a new connection + re-prepare + execute on that one. 622 // get a new connection + re-prepare + execute on that one.
558 dc, err := db.conn() 623 dc, err := db.conn()
559 if err != nil { 624 if err != nil {
560 return nil, err 625 return nil, err
561 } 626 }
562 dc.Lock() 627 dc.Lock()
563 » si, err := dc.ci.Prepare(query) 628 » si, err := dc.prepareLocked(query)
564 dc.Unlock() 629 dc.Unlock()
565 if err != nil { 630 if err != nil {
566 db.putConn(dc, err) 631 db.putConn(dc, err)
567 return nil, err 632 return nil, err
568 } 633 }
569 stmt := &Stmt{ 634 stmt := &Stmt{
570 db: db, 635 db: db,
571 query: query, 636 query: query,
572 css: []connStmt{{dc, si}}, 637 css: []connStmt{{dc, si}},
573 } 638 }
574 db.addDep(stmt, stmt) 639 db.addDep(stmt, stmt)
575 db.addDep(dc, stmt)
576 db.putConn(dc, nil) 640 db.putConn(dc, nil)
577 return stmt, nil 641 return stmt, nil
578 } 642 }
579 643
580 // Exec executes a query without returning any rows. 644 // Exec executes a query without returning any rows.
581 // The args are for any placeholder parameters in the query. 645 // The args are for any placeholder parameters in the query.
582 func (db *DB) Exec(query string, args ...interface{}) (Result, error) { 646 func (db *DB) Exec(query string, args ...interface{}) (Result, error) {
583 var res Result 647 var res Result
584 var err error 648 var err error
585 for i := 0; i < 10; i++ { 649 for i := 0; i < 10; i++ {
(...skipping 30 matching lines...) Expand all
616 } 680 }
617 } 681 }
618 682
619 dc.Lock() 683 dc.Lock()
620 si, err := dc.ci.Prepare(query) 684 si, err := dc.ci.Prepare(query)
621 dc.Unlock() 685 dc.Unlock()
622 if err != nil { 686 if err != nil {
623 return nil, err 687 return nil, err
624 } 688 }
625 defer withLock(dc, func() { si.Close() }) 689 defer withLock(dc, func() { si.Close() })
626
627 return resultFromStatement(driverStmt{dc, si}, args...) 690 return resultFromStatement(driverStmt{dc, si}, args...)
628 } 691 }
629 692
630 // Query executes a query that returns rows, typically a SELECT. 693 // Query executes a query that returns rows, typically a SELECT.
631 // The args are for any placeholder parameters in the query. 694 // The args are for any placeholder parameters in the query.
632 func (db *DB) Query(query string, args ...interface{}) (*Rows, error) { 695 func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
633 var rows *Rows 696 var rows *Rows
634 var err error 697 var err error
635 for i := 0; i < 10; i++ { 698 for i := 0; i < 10; i++ {
636 rows, err = db.query(query, args) 699 rows, err = db.query(query, args)
(...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after
1042 ci, err = s.tx.grabConn() // blocks, waiting for the connection. 1105 ci, err = s.tx.grabConn() // blocks, waiting for the connection.
1043 if err != nil { 1106 if err != nil {
1044 return 1107 return
1045 } 1108 }
1046 releaseConn = func(error) {} 1109 releaseConn = func(error) {}
1047 return ci, releaseConn, s.txsi.si, nil 1110 return ci, releaseConn, s.txsi.si, nil
1048 } 1111 }
1049 1112
1050 var cs connStmt 1113 var cs connStmt
1051 match := false 1114 match := false
1052 » for _, v := range s.css { 1115 » for i := 0; i < len(s.css); i++ {
1053 » » // TODO(bradfitz): lazily clean up entries in this 1116 » » v := s.css[i]
1054 » » // list with dead conns while enumerating 1117 » » _, err := s.db.connIfFree(v.dc)
1055 » » if _, match = s.db.connIfFree(v.dc); match { 1118 » » if err == nil {
1119 » » » match = true
1056 cs = v 1120 cs = v
1057 break 1121 break
1058 } 1122 }
1123 if err == errConnClosed {
1124 // Lazily remove dead conn from our freelist.
1125 s.css[i] = s.css[len(s.css)-1]
1126 s.css = s.css[:len(s.css)-1]
1127 i--
1128 }
1129
1059 } 1130 }
1060 s.mu.Unlock() 1131 s.mu.Unlock()
1061 1132
1062 // Make a new conn if all are busy. 1133 // Make a new conn if all are busy.
1063 // TODO(bradfitz): or wait for one? make configurable later? 1134 // TODO(bradfitz): or wait for one? make configurable later?
1064 if !match { 1135 if !match {
1065 for i := 0; ; i++ { 1136 for i := 0; ; i++ {
1066 dc, err := s.db.conn() 1137 dc, err := s.db.conn()
1067 if err != nil { 1138 if err != nil {
1068 return nil, nil, nil, err 1139 return nil, nil, nil, err
1069 } 1140 }
1070 dc.Lock() 1141 dc.Lock()
1071 » » » si, err := dc.ci.Prepare(s.query) 1142 » » » si, err := dc.prepareLocked(s.query)
1072 dc.Unlock() 1143 dc.Unlock()
1073 if err == driver.ErrBadConn && i < 10 { 1144 if err == driver.ErrBadConn && i < 10 {
1074 continue 1145 continue
1075 } 1146 }
1076 if err != nil { 1147 if err != nil {
1077 return nil, nil, nil, err 1148 return nil, nil, nil, err
1078 } 1149 }
1079 s.db.addDep(dc, s)
1080 s.mu.Lock() 1150 s.mu.Lock()
1081 cs = connStmt{dc, si} 1151 cs = connStmt{dc, si}
1082 s.css = append(s.css, cs) 1152 s.css = append(s.css, cs)
1083 s.mu.Unlock() 1153 s.mu.Unlock()
1084 break 1154 break
1085 } 1155 }
1086 } 1156 }
1087 1157
1088 conn := cs.dc 1158 conn := cs.dc
1089 releaseConn = func(err error) { s.db.putConn(conn, err) } 1159 releaseConn = func(err error) { s.db.putConn(conn, err) }
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
1188 s.txsi.Close() 1258 s.txsi.Close()
1189 return nil 1259 return nil
1190 } 1260 }
1191 1261
1192 return s.db.removeDep(s, s) 1262 return s.db.removeDep(s, s)
1193 } 1263 }
1194 1264
1195 func (s *Stmt) finalClose() error { 1265 func (s *Stmt) finalClose() error {
1196 for _, v := range s.css { 1266 for _, v := range s.css {
1197 s.db.noteUnusedDriverStatement(v.dc, v.si) 1267 s.db.noteUnusedDriverStatement(v.dc, v.si)
1268 v.dc.removeOpenStmt(v.si)
1198 s.db.removeDep(v.dc, s) 1269 s.db.removeDep(v.dc, s)
1199 } 1270 }
1200 s.css = nil 1271 s.css = nil
1201 return nil 1272 return nil
1202 } 1273 }
1203 1274
1204 // Rows is the result of a query. Its cursor starts before the first row 1275 // Rows is the result of a query. Its cursor starts before the first row
1205 // of the result set. Use Next to advance through the rows: 1276 // of the result set. Use Next to advance through the rows:
1206 // 1277 //
1207 // rows, err := db.Query("SELECT ...") 1278 // rows, err := db.Query("SELECT ...")
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after
1382 return dr.resi.LastInsertId() 1453 return dr.resi.LastInsertId()
1383 } 1454 }
1384 1455
1385 func (dr driverResult) RowsAffected() (int64, error) { 1456 func (dr driverResult) RowsAffected() (int64, error) {
1386 dr.Lock() 1457 dr.Lock()
1387 defer dr.Unlock() 1458 defer dr.Unlock()
1388 return dr.resi.RowsAffected() 1459 return dr.resi.RowsAffected()
1389 } 1460 }
1390 1461
1391 func stack() string { 1462 func stack() string {
1392 » var buf [1024]byte 1463 » var buf [2 << 10]byte
1393 return string(buf[:runtime.Stack(buf[:], false)]) 1464 return string(buf[:runtime.Stack(buf[:], false)])
1394 } 1465 }
1395 1466
1396 // withLock runs while holding lk. 1467 // withLock runs while holding lk.
1397 func withLock(lk sync.Locker, fn func()) { 1468 func withLock(lk sync.Locker, fn func()) {
1398 lk.Lock() 1469 lk.Lock()
1399 fn() 1470 fn()
1400 lk.Unlock() 1471 lk.Unlock()
1401 } 1472 }
OLDNEW

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