mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
database/sql: add Pinger interface to driver Conn
Change-Id: If6eb3a7c9ad48a517e584567b1003479c1df6cca Reviewed-on: https://go-review.googlesource.com/32136 Reviewed-by: Daniel Theophanes <kardianos@gmail.com> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
398e861d97
commit
4b90b7a28a
3 changed files with 73 additions and 6 deletions
|
|
@ -69,6 +69,17 @@ var ErrSkip = errors.New("driver: skip fast-path; continue as if unimplemented")
|
||||||
// you shouldn't return ErrBadConn.
|
// you shouldn't return ErrBadConn.
|
||||||
var ErrBadConn = errors.New("driver: bad connection")
|
var ErrBadConn = errors.New("driver: bad connection")
|
||||||
|
|
||||||
|
// Pinger is an optional interface that may be implemented by a Conn.
|
||||||
|
//
|
||||||
|
// If a Conn does not implement Pinger, the sql package's DB.Ping and
|
||||||
|
// DB.PingContext will check if there is at least one Conn available.
|
||||||
|
//
|
||||||
|
// If Conn.Ping returns ErrBadConn, DB.Ping and DB.PingContext will remove
|
||||||
|
// the Conn from pool.
|
||||||
|
type Pinger interface {
|
||||||
|
Ping(ctx context.Context) error
|
||||||
|
}
|
||||||
|
|
||||||
// Execer is an optional interface that may be implemented by a Conn.
|
// Execer is an optional interface that may be implemented by a Conn.
|
||||||
//
|
//
|
||||||
// If a Conn does not implement Execer, the sql package's DB.Exec will
|
// If a Conn does not implement Execer, the sql package's DB.Exec will
|
||||||
|
|
|
||||||
|
|
@ -553,15 +553,27 @@ func Open(driverName, dataSourceName string) (*DB, error) {
|
||||||
// PingContext verifies a connection to the database is still alive,
|
// PingContext verifies a connection to the database is still alive,
|
||||||
// establishing a connection if necessary.
|
// establishing a connection if necessary.
|
||||||
func (db *DB) PingContext(ctx context.Context) error {
|
func (db *DB) PingContext(ctx context.Context) error {
|
||||||
// TODO(bradfitz): give drivers an optional hook to implement
|
var dc *driverConn
|
||||||
// this in a more efficient or more reliable way, if they
|
var err error
|
||||||
// have one.
|
|
||||||
dc, err := db.conn(ctx, cachedOrNewConn)
|
for i := 0; i < maxBadConnRetries; i++ {
|
||||||
|
dc, err = db.conn(ctx, cachedOrNewConn)
|
||||||
|
if err != driver.ErrBadConn {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err == driver.ErrBadConn {
|
||||||
|
dc, err = db.conn(ctx, alwaysNewConn)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
db.putConn(dc, nil)
|
|
||||||
return nil
|
if pinger, ok := dc.ci.(driver.Pinger); ok {
|
||||||
|
err = pinger.Ping(ctx)
|
||||||
|
}
|
||||||
|
db.putConn(dc, err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ping verifies a connection to the database is still alive,
|
// Ping verifies a connection to the database is still alive,
|
||||||
|
|
|
||||||
|
|
@ -2581,6 +2581,50 @@ func TestBadDriver(t *testing.T) {
|
||||||
db.Exec("ignored")
|
db.Exec("ignored")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type pingDriver struct {
|
||||||
|
fails bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type pingConn struct {
|
||||||
|
badConn
|
||||||
|
driver *pingDriver
|
||||||
|
}
|
||||||
|
|
||||||
|
var pingError = errors.New("Ping failed")
|
||||||
|
|
||||||
|
func (pc pingConn) Ping(ctx context.Context) error {
|
||||||
|
if pc.driver.fails {
|
||||||
|
return pingError
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ driver.Pinger = pingConn{}
|
||||||
|
|
||||||
|
func (pd *pingDriver) Open(name string) (driver.Conn, error) {
|
||||||
|
return pingConn{driver: pd}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPing(t *testing.T) {
|
||||||
|
driver := &pingDriver{}
|
||||||
|
Register("ping", driver)
|
||||||
|
|
||||||
|
db, err := Open("ping", "ignored")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Ping(); err != nil {
|
||||||
|
t.Errorf("err was %#v, expected nil", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
driver.fails = true
|
||||||
|
if err := db.Ping(); err != pingError {
|
||||||
|
t.Errorf("err was %#v, expected pingError", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkConcurrentDBExec(b *testing.B) {
|
func BenchmarkConcurrentDBExec(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
ct := new(concurrentDBExecTest)
|
ct := new(concurrentDBExecTest)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue