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

Side by Side Diff: src/pkg/database/sql/sql.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/fakedb_test.go ('k') | src/pkg/database/sql/sql_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 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
11 11
12 import ( 12 import (
13 "container/list"
13 "database/sql/driver" 14 "database/sql/driver"
14 "errors" 15 "errors"
15 "fmt" 16 "fmt"
16 "io" 17 "io"
17 "runtime" 18 "runtime"
18 "sync" 19 "sync"
19 ) 20 )
20 21
21 var drivers = make(map[string]driver.Driver) 22 var drivers = make(map[string]driver.Driver)
22 23
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
185 // a concept of per-connection state, such state can only be reliably 186 // a concept of per-connection state, such state can only be reliably
186 // observed within a transaction. Once DB.Begin is called, the 187 // observed within a transaction. Once DB.Begin is called, the
187 // returned Tx is bound to a single connection. Once Commit or 188 // returned Tx is bound to a single connection. Once Commit or
188 // Rollback is called on the transaction, that transaction's 189 // Rollback is called on the transaction, that transaction's
189 // connection is returned to DB's idle connection pool. The pool size 190 // connection is returned to DB's idle connection pool. The pool size
190 // can be controlled with SetMaxIdleConns. 191 // can be controlled with SetMaxIdleConns.
191 type DB struct { 192 type DB struct {
192 driver driver.Driver 193 driver driver.Driver
193 dsn string 194 dsn string
194 195
195 » mu sync.Mutex // protects following fields 196 » mu sync.Mutex // protects following fields
196 » freeConn []*driverConn 197 » freeConn *list.List // of *driverConn
198 » connRequests *list.List // of connRequest
199 » numOpen int
200 » pendingOpens int
201 » // Used to sygnal the need for new connections
202 » // a goroutine running connectionOpener() reads on this chan and
203 » // maybeOpenNewConnections sends on the chan (one send per needed connec tion)
204 » // It is closed during db.Close(). The close tells the connectionOpener
205 » // goroutine to exit.
206 » openerCh chan struct{}
197 closed bool 207 closed bool
198 dep map[finalCloser]depSet 208 dep map[finalCloser]depSet
199 lastPut map[*driverConn]string // stacktrace of last conn's put; debug only 209 lastPut map[*driverConn]string // stacktrace of last conn's put; debug only
200 maxIdle int // zero means defaultMaxIdleConns; negat ive means 0 210 maxIdle int // zero means defaultMaxIdleConns; negat ive means 0
211 maxOpen int // <= 0 means unlimited
201 } 212 }
202 213
203 // driverConn wraps a driver.Conn with a mutex, to 214 // driverConn wraps a driver.Conn with a mutex, to
204 // be held during all calls into the Conn. (including any calls onto 215 // be held during all calls into the Conn. (including any calls onto
205 // interfaces returned via that Conn, such as calls on Tx, Stmt, 216 // interfaces returned via that Conn, such as calls on Tx, Stmt,
206 // Result, Rows) 217 // Result, Rows)
207 type driverConn struct { 218 type driverConn struct {
208 db *DB 219 db *DB
209 220
210 sync.Mutex // guards following 221 sync.Mutex // guards following
211 ci driver.Conn 222 ci driver.Conn
212 closed bool 223 closed bool
213 finalClosed bool // ci.Close has been called 224 finalClosed bool // ci.Close has been called
214 openStmt map[driver.Stmt]bool 225 openStmt map[driver.Stmt]bool
215 226
216 // guarded by db.mu 227 // guarded by db.mu
217 inUse bool 228 inUse bool
218 onPut []func() // code (with db.mu held) run when conn is next retu rned 229 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 230 dbmuClosed bool // same as closed, but guarded by db.mu, for connIfF ree
231 // This is the Element returned by db.freeConn.PushFront(conn).
232 // It's used by connIfFree to remove the conn from the freeConn list.
233 listElem *list.Element
220 } 234 }
221 235
222 func (dc *driverConn) releaseConn(err error) { 236 func (dc *driverConn) releaseConn(err error) {
223 dc.db.putConn(dc, err) 237 dc.db.putConn(dc, err)
224 } 238 }
225 239
226 func (dc *driverConn) removeOpenStmt(si driver.Stmt) { 240 func (dc *driverConn) removeOpenStmt(si driver.Stmt) {
227 dc.Lock() 241 dc.Lock()
228 defer dc.Unlock() 242 defer dc.Unlock()
229 delete(dc.openStmt, si) 243 delete(dc.openStmt, si)
(...skipping 17 matching lines...) Expand all
247 // everywhere, and making it a finalCloser. 261 // everywhere, and making it a finalCloser.
248 if dc.openStmt == nil { 262 if dc.openStmt == nil {
249 dc.openStmt = make(map[driver.Stmt]bool) 263 dc.openStmt = make(map[driver.Stmt]bool)
250 } 264 }
251 dc.openStmt[si] = true 265 dc.openStmt[si] = true
252 } 266 }
253 return si, err 267 return si, err
254 } 268 }
255 269
256 // the dc.db's Mutex is held. 270 // the dc.db's Mutex is held.
257 func (dc *driverConn) closeDBLocked() error { 271 func (dc *driverConn) closeDBLocked() func() error {
258 dc.Lock() 272 dc.Lock()
273 defer dc.Unlock()
259 if dc.closed { 274 if dc.closed {
260 » » dc.Unlock() 275 » » return func() error { return errors.New("sql: duplicate driverCo nn close") }
261 » » return errors.New("sql: duplicate driverConn close")
262 } 276 }
263 dc.closed = true 277 dc.closed = true
264 » dc.Unlock() // not defer; removeDep finalClose calls may need to lock 278 » return dc.db.removeDepLocked(dc, dc)
265 » return dc.db.removeDepLocked(dc, dc)()
266 } 279 }
267 280
268 func (dc *driverConn) Close() error { 281 func (dc *driverConn) Close() error {
269 dc.Lock() 282 dc.Lock()
270 if dc.closed { 283 if dc.closed {
271 dc.Unlock() 284 dc.Unlock()
272 return errors.New("sql: duplicate driverConn close") 285 return errors.New("sql: duplicate driverConn close")
273 } 286 }
274 dc.closed = true 287 dc.closed = true
275 dc.Unlock() // not defer; removeDep finalClose calls may need to lock 288 dc.Unlock() // not defer; removeDep finalClose calls may need to lock
(...skipping 10 matching lines...) Expand all
286 dc.Lock() 299 dc.Lock()
287 300
288 for si := range dc.openStmt { 301 for si := range dc.openStmt {
289 si.Close() 302 si.Close()
290 } 303 }
291 dc.openStmt = nil 304 dc.openStmt = nil
292 305
293 err := dc.ci.Close() 306 err := dc.ci.Close()
294 dc.ci = nil 307 dc.ci = nil
295 dc.finalClosed = true 308 dc.finalClosed = true
309 dc.Unlock()
296 310
297 » dc.Unlock() 311 » dc.db.mu.Lock()
312 » dc.db.numOpen--
313 » dc.db.maybeOpenNewConnections()
314 » dc.db.mu.Unlock()
315
298 return err 316 return err
299 } 317 }
300 318
301 // driverStmt associates a driver.Stmt with the 319 // driverStmt associates a driver.Stmt with the
302 // *driverConn from which it came, so the driverConn's lock can be 320 // *driverConn from which it came, so the driverConn's lock can be
303 // held during calls. 321 // held during calls.
304 type driverStmt struct { 322 type driverStmt struct {
305 sync.Locker // the *driverConn 323 sync.Locker // the *driverConn
306 si driver.Stmt 324 si driver.Stmt
307 } 325 }
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
373 case 0: 391 case 0:
374 // No more dependencies. 392 // No more dependencies.
375 delete(db.dep, x) 393 delete(db.dep, x)
376 return x.finalClose 394 return x.finalClose
377 default: 395 default:
378 // Dependencies remain. 396 // Dependencies remain.
379 return func() error { return nil } 397 return func() error { return nil }
380 } 398 }
381 } 399 }
382 400
401 // This is the size of the connectionOpener request chan (dn.openerCh).
402 // This value should be larger than the maximum typical value
403 // used for db.maxOpen. If maxOpen is significantly larger than
404 // connectionRequestQueueSize then it is possible for ALL calls into the *DB
405 // to block until the connectionOpener can satify the backlog of requests.
406 var connectionRequestQueueSize = 1000000
407
383 // Open opens a database specified by its database driver name and a 408 // Open opens a database specified by its database driver name and a
384 // driver-specific data source name, usually consisting of at least a 409 // driver-specific data source name, usually consisting of at least a
385 // database name and connection information. 410 // database name and connection information.
386 // 411 //
387 // Most users will open a database via a driver-specific connection 412 // Most users will open a database via a driver-specific connection
388 // helper function that returns a *DB. No database drivers are included 413 // helper function that returns a *DB. No database drivers are included
389 // in the Go standard library. See http://golang.org/s/sqldrivers for 414 // in the Go standard library. See http://golang.org/s/sqldrivers for
390 // a list of third-party drivers. 415 // a list of third-party drivers.
391 // 416 //
392 // Open may just validate its arguments without creating a connection 417 // Open may just validate its arguments without creating a connection
393 // to the database. To verify that the data source name is valid, call 418 // to the database. To verify that the data source name is valid, call
394 // Ping. 419 // Ping.
395 func Open(driverName, dataSourceName string) (*DB, error) { 420 func Open(driverName, dataSourceName string) (*DB, error) {
396 driveri, ok := drivers[driverName] 421 driveri, ok := drivers[driverName]
397 if !ok { 422 if !ok {
398 return nil, fmt.Errorf("sql: unknown driver %q (forgotten import ?)", driverName) 423 return nil, fmt.Errorf("sql: unknown driver %q (forgotten import ?)", driverName)
399 } 424 }
400 db := &DB{ 425 db := &DB{
401 » » driver: driveri, 426 » » driver: driveri,
402 » » dsn: dataSourceName, 427 » » dsn: dataSourceName,
403 » » lastPut: make(map[*driverConn]string), 428 » » openerCh: make(chan struct{}, connectionRequestQueueSize),
429 » » lastPut: make(map[*driverConn]string),
404 } 430 }
431 db.freeConn = list.New()
432 db.connRequests = list.New()
433 go db.connectionOpener()
405 return db, nil 434 return db, nil
406 } 435 }
407 436
408 // Ping verifies a connection to the database is still alive, 437 // Ping verifies a connection to the database is still alive,
409 // establishing a connection if necessary. 438 // establishing a connection if necessary.
410 func (db *DB) Ping() error { 439 func (db *DB) Ping() error {
411 // TODO(bradfitz): give drivers an optional hook to implement 440 // TODO(bradfitz): give drivers an optional hook to implement
412 // this in a more efficient or more reliable way, if they 441 // this in a more efficient or more reliable way, if they
413 // have one. 442 // have one.
414 dc, err := db.conn() 443 dc, err := db.conn()
415 if err != nil { 444 if err != nil {
416 return err 445 return err
417 } 446 }
418 db.putConn(dc, nil) 447 db.putConn(dc, nil)
419 return nil 448 return nil
420 } 449 }
421 450
422 // Close closes the database, releasing any open resources. 451 // Close closes the database, releasing any open resources.
423 func (db *DB) Close() error { 452 func (db *DB) Close() error {
424 db.mu.Lock() 453 db.mu.Lock()
425 » defer db.mu.Unlock() 454 » if db.closed { // Make DB.Close idempotent
455 » » db.mu.Unlock()
456 » » return nil
457 » }
458 » close(db.openerCh)
426 var err error 459 var err error
427 » for _, dc := range db.freeConn { 460 » fns := make([]func() error, 0, db.freeConn.Len())
428 » » err1 := dc.closeDBLocked() 461 » for db.freeConn.Front() != nil {
462 » » dc := db.freeConn.Front().Value.(*driverConn)
463 » » dc.listElem = nil
464 » » fns = append(fns, dc.closeDBLocked())
465 » » db.freeConn.Remove(db.freeConn.Front())
466 » }
467 » db.closed = true
468 » for db.connRequests.Front() != nil {
469 » » req := db.connRequests.Front().Value.(connRequest)
470 » » db.connRequests.Remove(db.connRequests.Front())
471 » » close(req)
472 » }
473 » db.mu.Unlock()
474 » for _, fn := range fns {
475 » » err1 := fn()
429 if err1 != nil { 476 if err1 != nil {
430 err = err1 477 err = err1
431 } 478 }
432 } 479 }
433 db.freeConn = nil
434 db.closed = true
435 return err 480 return err
436 } 481 }
437 482
438 const defaultMaxIdleConns = 2 483 const defaultMaxIdleConns = 2
439 484
440 func (db *DB) maxIdleConnsLocked() int { 485 func (db *DB) maxIdleConnsLocked() int {
441 n := db.maxIdle 486 n := db.maxIdle
442 switch { 487 switch {
443 case n == 0: 488 case n == 0:
444 // TODO(bradfitz): ask driver, if supported, for its default pre ference 489 // TODO(bradfitz): ask driver, if supported, for its default pre ference
445 return defaultMaxIdleConns 490 return defaultMaxIdleConns
446 case n < 0: 491 case n < 0:
447 return 0 492 return 0
448 default: 493 default:
449 return n 494 return n
450 } 495 }
451 } 496 }
452 497
453 // SetMaxIdleConns sets the maximum number of connections in the idle 498 // SetMaxIdleConns sets the maximum number of connections in the idle
454 // connection pool. 499 // connection pool.
455 // 500 //
501 // If MaxOpenConns is greater than 0 but less than the new MaxIdleConns
502 // then the new MaxIdleConns will be reduced to match the MaxOpenConns limit
503 //
456 // If n <= 0, no idle connections are retained. 504 // If n <= 0, no idle connections are retained.
457 func (db *DB) SetMaxIdleConns(n int) { 505 func (db *DB) SetMaxIdleConns(n int) {
458 db.mu.Lock() 506 db.mu.Lock()
459 defer db.mu.Unlock() 507 defer db.mu.Unlock()
460 if n > 0 { 508 if n > 0 {
461 db.maxIdle = n 509 db.maxIdle = n
462 } else { 510 } else {
463 // No idle connections. 511 // No idle connections.
464 db.maxIdle = -1 512 db.maxIdle = -1
465 } 513 }
466 » for len(db.freeConn) > 0 && len(db.freeConn) > n { 514 » // Make sure maxIdle doesn't exceed maxOpen
467 » » nfree := len(db.freeConn) 515 » if db.maxOpen > 0 && db.maxIdleConnsLocked() > db.maxOpen {
468 » » dc := db.freeConn[nfree-1] 516 » » db.maxIdle = db.maxOpen
469 » » db.freeConn[nfree-1] = nil 517 » }
470 » » db.freeConn = db.freeConn[:nfree-1] 518 » for db.freeConn.Len() > db.maxIdleConnsLocked() {
519 » » dc := db.freeConn.Back().Value.(*driverConn)
520 » » dc.listElem = nil
521 » » db.freeConn.Remove(db.freeConn.Back())
471 go dc.Close() 522 go dc.Close()
472 } 523 }
473 } 524 }
474 525
526 // SetMaxOpenConns sets the maximum number of open connections to the database.
527 //
528 // If MaxIdleConns is greater than 0 and the new MaxOpenConns is less than
529 // MaxIdleConns, then MaxIdleConns will be reduced to match the new
530 // MaxOpenConns limit
531 //
532 // If n <= 0, then there is no limit on the number of open connections.
533 // The default is 0 (unlimited).
534 func (db *DB) SetMaxOpenConns(n int) {
535 db.mu.Lock()
536 db.maxOpen = n
537 if n < 0 {
538 db.maxOpen = 0
539 }
540 syncMaxIdle := db.maxOpen > 0 && db.maxIdleConnsLocked() > db.maxOpen
541 db.mu.Unlock()
542 if syncMaxIdle {
543 db.SetMaxIdleConns(n)
544 }
545 }
546
547 // Assumes db.mu is locked.
548 // If there are connRequests and the connection limit hasn't been reached,
549 // then tell the connectionOpener to open new connections.
550 func (db *DB) maybeOpenNewConnections() {
551 numRequests := db.connRequests.Len() - db.pendingOpens
552 if db.maxOpen > 0 {
553 numCanOpen := db.maxOpen - (db.numOpen + db.pendingOpens)
554 if numRequests > numCanOpen {
555 numRequests = numCanOpen
556 }
557 }
558 for numRequests > 0 {
559 db.pendingOpens++
560 numRequests--
561 db.openerCh <- struct{}{}
562 }
563 }
564
565 // Runs in a seperate goroutine, opens new connections when requested.
566 func (db *DB) connectionOpener() {
567 for _ = range db.openerCh {
568 db.openNewConnection()
569 }
570 }
571
572 // Open one new connection
573 func (db *DB) openNewConnection() {
574 ci, err := db.driver.Open(db.dsn)
575 db.mu.Lock()
576 defer db.mu.Unlock()
577 if db.closed {
578 if err == nil {
579 ci.Close()
580 }
581 return
582 }
583 db.pendingOpens--
584 if err != nil {
585 db.putConnDBLocked(nil, err)
586 return
587 }
588 dc := &driverConn{
589 db: db,
590 ci: ci,
591 }
592 db.addDepLocked(dc, dc)
593 db.numOpen++
594 db.putConnDBLocked(dc, err)
595 }
596
597 // connRequest represents one request for a new connection
598 // When there are no idle connections available, DB.conn will create
599 // a new connRequest and put it on the db.connRequests list.
600 type connRequest chan<- interface{} // takes either a *driverConn or an error
601
602 var errDBClosed = errors.New("sql: database is closed")
603
475 // conn returns a newly-opened or cached *driverConn 604 // conn returns a newly-opened or cached *driverConn
476 func (db *DB) conn() (*driverConn, error) { 605 func (db *DB) conn() (*driverConn, error) {
477 db.mu.Lock() 606 db.mu.Lock()
478 if db.closed { 607 if db.closed {
479 db.mu.Unlock() 608 db.mu.Unlock()
480 » » return nil, errors.New("sql: database is closed") 609 » » return nil, errDBClosed
481 } 610 }
482 » if n := len(db.freeConn); n > 0 { 611
483 » » conn := db.freeConn[n-1] 612 » // If db.maxOpen > 0 and the number of open connections is over the limi t
484 » » db.freeConn = db.freeConn[:n-1] 613 » // or there are no free connection, then make a request and wait.
614 » if db.maxOpen > 0 && (db.numOpen >= db.maxOpen || db.freeConn.Len() == 0 ) {
615 » » // Make the connRequest channel. It's buffered so that the
616 » » // connectionOpener doesn't block while waiting for the req to b e read.
617 » » ch := make(chan interface{}, 1)
618 » » req := connRequest(ch)
619 » » db.connRequests.PushBack(req)
620 » » db.maybeOpenNewConnections()
621 » » db.mu.Unlock()
622 » » ret, ok := <-ch
623 » » if !ok {
624 » » » return nil, errDBClosed
625 » » }
626 » » switch ret.(type) {
627 » » case *driverConn:
628 » » » return ret.(*driverConn), nil
629 » » case error:
630 » » » return nil, ret.(error)
631 » » default:
632 » » » panic("sql: Unexpected type passed through connRequest.c h")
633 » » }
634 » }
635
636 » if f := db.freeConn.Front(); f != nil {
637 » » conn := f.Value.(*driverConn)
638 » » conn.listElem = nil
639 » » db.freeConn.Remove(f)
485 conn.inUse = true 640 conn.inUse = true
486 db.mu.Unlock() 641 db.mu.Unlock()
487 return conn, nil 642 return conn, nil
488 } 643 }
644
489 db.mu.Unlock() 645 db.mu.Unlock()
490
491 ci, err := db.driver.Open(db.dsn) 646 ci, err := db.driver.Open(db.dsn)
492 if err != nil { 647 if err != nil {
493 return nil, err 648 return nil, err
494 } 649 }
650 db.mu.Lock()
651 db.numOpen++
495 dc := &driverConn{ 652 dc := &driverConn{
496 db: db, 653 db: db,
497 ci: ci, 654 ci: ci,
498 } 655 }
499 db.mu.Lock()
500 db.addDepLocked(dc, dc) 656 db.addDepLocked(dc, dc)
501 dc.inUse = true 657 dc.inUse = true
502 db.mu.Unlock() 658 db.mu.Unlock()
503 return dc, nil 659 return dc, nil
504 } 660 }
505 661
506 var ( 662 var (
507 errConnClosed = errors.New("database/sql: internal sentinel error: conn is closed") 663 errConnClosed = errors.New("database/sql: internal sentinel error: conn is closed")
508 errConnBusy = errors.New("database/sql: internal sentinel error: conn is busy") 664 errConnBusy = errors.New("database/sql: internal sentinel error: conn is busy")
509 ) 665 )
510 666
511 // connIfFree returns (wanted, nil) if wanted is still a valid conn and 667 // connIfFree returns (wanted, nil) if wanted is still a valid conn and
512 // isn't in use. 668 // isn't in use.
513 // 669 //
514 // The error is errConnClosed if the connection if the requested connection 670 // The error is errConnClosed if the connection if the requested connection
515 // is invalid because it's been closed. 671 // is invalid because it's been closed.
516 // 672 //
517 // The error is errConnBusy if the connection is in use. 673 // The error is errConnBusy if the connection is in use.
518 func (db *DB) connIfFree(wanted *driverConn) (*driverConn, error) { 674 func (db *DB) connIfFree(wanted *driverConn) (*driverConn, error) {
519 db.mu.Lock() 675 db.mu.Lock()
520 defer db.mu.Unlock() 676 defer db.mu.Unlock()
521 if wanted.dbmuClosed { 677 if wanted.dbmuClosed {
522 return nil, errConnClosed 678 return nil, errConnClosed
523 } 679 }
524 if wanted.inUse { 680 if wanted.inUse {
525 return nil, errConnBusy 681 return nil, errConnBusy
526 } 682 }
527 » for i, conn := range db.freeConn { 683 » if wanted.listElem != nil {
528 » » if conn != wanted { 684 » » db.freeConn.Remove(wanted.listElem)
529 » » » continue 685 » » wanted.listElem = nil
530 » » }
531 » » db.freeConn[i] = db.freeConn[len(db.freeConn)-1]
532 » » db.freeConn = db.freeConn[:len(db.freeConn)-1]
533 wanted.inUse = true 686 wanted.inUse = true
534 return wanted, nil 687 return wanted, nil
535 } 688 }
536 // TODO(bradfitz): shouldn't get here. After Go 1.1, change this to: 689 // TODO(bradfitz): shouldn't get here. After Go 1.1, change this to:
537 // panic("connIfFree call requested a non-closed, non-busy, non-free con n") 690 // panic("connIfFree call requested a non-closed, non-busy, non-free con n")
538 // Which passes all the tests, but I'm too paranoid to include this 691 // Which passes all the tests, but I'm too paranoid to include this
539 // late in Go 1.1. 692 // late in Go 1.1.
540 // Instead, treat it like a busy connection: 693 // Instead, treat it like a busy connection:
541 return nil, errConnBusy 694 return nil, errConnBusy
542 } 695 }
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
582 } 735 }
583 dc.inUse = false 736 dc.inUse = false
584 737
585 for _, fn := range dc.onPut { 738 for _, fn := range dc.onPut {
586 fn() 739 fn()
587 } 740 }
588 dc.onPut = nil 741 dc.onPut = nil
589 742
590 if err == driver.ErrBadConn { 743 if err == driver.ErrBadConn {
591 // Don't reuse bad connections. 744 // Don't reuse bad connections.
745 // Since the conn is considered bad and is being discarded, trea t it
746 // as closed. Decrement the open count.
747 db.numOpen--
748 db.maybeOpenNewConnections()
592 db.mu.Unlock() 749 db.mu.Unlock()
593 dc.Close() 750 dc.Close()
594 return 751 return
595 } 752 }
596 if putConnHook != nil { 753 if putConnHook != nil {
597 putConnHook(db, dc) 754 putConnHook(db, dc)
598 } 755 }
599 » if n := len(db.freeConn); !db.closed && n < db.maxIdleConnsLocked() { 756 » added := db.putConnDBLocked(dc, nil)
600 » » db.freeConn = append(db.freeConn, dc)
601 » » db.mu.Unlock()
602 » » return
603 » }
604 db.mu.Unlock() 757 db.mu.Unlock()
605 758
606 » dc.Close() 759 » if !added {
760 » » dc.Close()
761 » }
762 }
763
764 // Satisfy a connRequest or put the driverConn in the idle pool and return true
765 // or return false.
766 // putConnDBLocked will satisfy a connRequest if there is one, or it will
767 // return the *driverConn to the freeConn list if err != nil and the idle
768 // connection limit would not be reached.
769 // If err != nil, the value of dc is ignored.
770 // If err == nil, then dc must not equal nil.
771 // If a connRequest was fullfilled or the *driverConn was placed in the
772 // freeConn list, then true is returned, otherwise false is returned.
773 func (db *DB) putConnDBLocked(dc *driverConn, err error) bool {
774 » if db.connRequests.Len() > 0 {
775 » » req := db.connRequests.Front().Value.(connRequest)
776 » » db.connRequests.Remove(db.connRequests.Front())
777 » » if err != nil {
778 » » » req <- err
779 » » } else {
780 » » » dc.inUse = true
781 » » » req <- dc
782 » » }
783 » » return true
784 » } else if err == nil && !db.closed && db.maxIdleConnsLocked() > 0 && db. maxIdleConnsLocked() > db.freeConn.Len() {
785 » » dc.listElem = db.freeConn.PushFront(dc)
786 » » return true
787 » }
788 » return false
607 } 789 }
608 790
609 // Prepare creates a prepared statement for later queries or executions. 791 // Prepare creates a prepared statement for later queries or executions.
610 // Multiple queries or executions may be run concurrently from the 792 // Multiple queries or executions may be run concurrently from the
611 // returned statement. 793 // returned statement.
612 func (db *DB) Prepare(query string) (*Stmt, error) { 794 func (db *DB) Prepare(query string) (*Stmt, error) {
613 var stmt *Stmt 795 var stmt *Stmt
614 var err error 796 var err error
615 for i := 0; i < 10; i++ { 797 for i := 0; i < 10; i++ {
616 stmt, err = db.prepare(query) 798 stmt, err = db.prepare(query)
(...skipping 626 matching lines...) Expand 10 before | Expand all | Expand 10 after
1243 1425
1244 // Close closes the statement. 1426 // Close closes the statement.
1245 func (s *Stmt) Close() error { 1427 func (s *Stmt) Close() error {
1246 s.closemu.Lock() 1428 s.closemu.Lock()
1247 defer s.closemu.Unlock() 1429 defer s.closemu.Unlock()
1248 1430
1249 if s.stickyErr != nil { 1431 if s.stickyErr != nil {
1250 return s.stickyErr 1432 return s.stickyErr
1251 } 1433 }
1252 s.mu.Lock() 1434 s.mu.Lock()
1253 defer s.mu.Unlock()
1254 if s.closed { 1435 if s.closed {
1436 s.mu.Unlock()
1255 return nil 1437 return nil
1256 } 1438 }
1257 s.closed = true 1439 s.closed = true
1258 1440
1259 if s.tx != nil { 1441 if s.tx != nil {
1260 s.txsi.Close() 1442 s.txsi.Close()
1443 s.mu.Unlock()
1261 return nil 1444 return nil
1262 } 1445 }
1446 s.mu.Unlock()
1263 1447
1264 return s.db.removeDep(s, s) 1448 return s.db.removeDep(s, s)
1265 } 1449 }
1266 1450
1267 func (s *Stmt) finalClose() error { 1451 func (s *Stmt) finalClose() error {
1268 » for _, v := range s.css { 1452 » s.mu.Lock()
1269 » » s.db.noteUnusedDriverStatement(v.dc, v.si) 1453 » defer s.mu.Unlock()
1270 » » v.dc.removeOpenStmt(v.si) 1454 » if s.css != nil {
1455 » » for _, v := range s.css {
1456 » » » s.db.noteUnusedDriverStatement(v.dc, v.si)
1457 » » » v.dc.removeOpenStmt(v.si)
1458 » » }
1459 » » s.css = nil
1271 } 1460 }
1272 s.css = nil
1273 return nil 1461 return nil
1274 } 1462 }
1275 1463
1276 // Rows is the result of a query. Its cursor starts before the first row 1464 // Rows is the result of a query. Its cursor starts before the first row
1277 // of the result set. Use Next to advance through the rows: 1465 // of the result set. Use Next to advance through the rows:
1278 // 1466 //
1279 // rows, err := db.Query("SELECT ...") 1467 // rows, err := db.Query("SELECT ...")
1280 // ... 1468 // ...
1281 // for rows.Next() { 1469 // for rows.Next() {
1282 // var id int 1470 // var id int
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
1464 var buf [2 << 10]byte 1652 var buf [2 << 10]byte
1465 return string(buf[:runtime.Stack(buf[:], false)]) 1653 return string(buf[:runtime.Stack(buf[:], false)])
1466 } 1654 }
1467 1655
1468 // withLock runs while holding lk. 1656 // withLock runs while holding lk.
1469 func withLock(lk sync.Locker, fn func()) { 1657 func withLock(lk sync.Locker, fn func()) {
1470 lk.Lock() 1658 lk.Lock()
1471 fn() 1659 fn()
1472 lk.Unlock() 1660 lk.Unlock()
1473 } 1661 }
OLDNEW
« no previous file with comments | « src/pkg/database/sql/fakedb_test.go ('k') | src/pkg/database/sql/sql_test.go » ('j') | no next file with comments »

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