OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |