// connection is returned to DB's idle connection pool. The pool size
// can be controlled with SetMaxIdleConns.
type DB struct {
+ // Atomic access only. At top of struct to prevent mis-alignment
+ // on 32-bit platforms. Of type time.Duration.
+ waitDuration int64 // Total time waited for new connections.
+
connector driver.Connector
// numClosed is an atomic counter which represents a total number of
// closed connections. Stmt.openStmt checks it before cleaning closed
// maybeOpenNewConnections sends on the chan (one send per needed connection)
// It is closed during db.Close(). The close tells the connectionOpener
// goroutine to exit.
- openerCh chan struct{}
- resetterCh chan *driverConn
- closed bool
- dep map[finalCloser]depSet
- lastPut map[*driverConn]string // stacktrace of last conn's put; debug only
- maxIdle int // zero means defaultMaxIdleConns; negative means 0
- maxOpen int // <= 0 means unlimited
- maxLifetime time.Duration // maximum amount of time a connection may be reused
- cleanerCh chan struct{}
+ openerCh chan struct{}
+ resetterCh chan *driverConn
+ closed bool
+ dep map[finalCloser]depSet
+ lastPut map[*driverConn]string // stacktrace of last conn's put; debug only
+ maxIdle int // zero means defaultMaxIdleConns; negative means 0
+ maxOpen int // <= 0 means unlimited
+ maxLifetime time.Duration // maximum amount of time a connection may be reused
+ cleanerCh chan struct{}
+ waitCount int64 // Total number of connections waited for.
+ maxIdleClosed int64 // Total number of connections closed due to idle.
+ maxLifetimeClosed int64 // Total number of connections closed due to max free limit.
stop func() // stop cancels the connection opener and the session resetter.
}
// then the new MaxIdleConns will be reduced to match the MaxOpenConns limit.
//
// If n <= 0, no idle connections are retained.
+//
+// The default max idle connections is currently 2. This may change in
+// a future release.
func (db *DB) SetMaxIdleConns(n int) {
db.mu.Lock()
if n > 0 {
closing = db.freeConn[maxIdle:]
db.freeConn = db.freeConn[:maxIdle]
}
+ db.maxIdleClosed += int64(len(closing))
db.mu.Unlock()
for _, c := range closing {
c.Close()
i--
}
}
+ db.maxLifetimeClosed += int64(len(closing))
db.mu.Unlock()
for _, c := range closing {
// DBStats contains database statistics.
type DBStats struct {
- // OpenConnections is the number of open connections to the database.
- OpenConnections int
+ MaxOpenConnections int // Maximum number of open connections to the database.
+
+ // Pool Status
+ OpenConnections int // The number of established connections both in use and idle.
+ InUse int // The number of connections currently in use.
+ Idle int // The number of idle connections.
+
+ // Counters
+ WaitCount int64 // The total number of connections waited for.
+ WaitDuration time.Duration // The total time blocked waiting for a new connection.
+ MaxIdleClosed int64 // The total number of connections closed due to SetMaxIdleConns.
+ MaxLifetimeClosed int64 // The total number of connections closed due to SetConnMaxLifetime.
}
// Stats returns database statistics.
func (db *DB) Stats() DBStats {
+ wait := atomic.LoadInt64(&db.waitDuration)
+
db.mu.Lock()
+ defer db.mu.Unlock()
+
stats := DBStats{
+ MaxOpenConnections: db.maxOpen,
+
+ Idle: len(db.freeConn),
OpenConnections: db.numOpen,
+ InUse: db.numOpen - len(db.freeConn),
+
+ WaitCount: db.waitCount,
+ WaitDuration: time.Duration(wait),
+ MaxIdleClosed: db.maxIdleClosed,
+ MaxLifetimeClosed: db.maxLifetimeClosed,
}
- db.mu.Unlock()
return stats
}
req := make(chan connRequest, 1)
reqKey := db.nextRequestKeyLocked()
db.connRequests[reqKey] = req
+ db.waitCount++
db.mu.Unlock()
+ waitStart := time.Now()
+
// Timeout the connection request with the context.
select {
case <-ctx.Done():
db.mu.Lock()
delete(db.connRequests, reqKey)
db.mu.Unlock()
+
+ atomic.AddInt64(&db.waitDuration, int64(time.Since(waitStart)))
+
select {
default:
case ret, ok := <-req:
}
return nil, ctx.Err()
case ret, ok := <-req:
+ atomic.AddInt64(&db.waitDuration, int64(time.Since(waitStart)))
+
if !ok {
return nil, errDBClosed
}
return true
} else if err == nil && !db.closed && db.maxIdleConnsLocked() > len(db.freeConn) {
db.freeConn = append(db.freeConn, dc)
+ db.maxIdleClosed++
db.startCleanerLocked()
return true
}