Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

254 lines (224 sloc) 5.075 kb
// Auto reconnect interface for MyMySQL
package autorc
import (
"github.com/ziutek/mymysql/mysql"
"io"
"log"
"net"
"time"
)
// Return true if error is network error or UnexpectedEOF.
func IsNetErr(err error) bool {
if err == io.ErrUnexpectedEOF {
return true
} else if _, ok := err.(net.Error); ok {
return true
}
return false
}
type Conn struct {
Raw mysql.Conn
// Maximum reconnect retries.
// Default is 7 which means 1+2+3+4+5+6+7 = 28 seconds before return error.
MaxRetries int
// Debug logging. You may change it at any time.
Debug bool
}
func New(proto, laddr, raddr, user, passwd string, db ...string) *Conn {
return &Conn{
Raw: mysql.New(proto, laddr, raddr, user, passwd, db...),
MaxRetries: 7,
}
}
func NewFromCF(cfgFile string) (*Conn, map[string]string, error) {
raw, unk, err := mysql.NewFromCF(cfgFile)
if err != nil {
return nil, nil, err
}
return &Conn{raw, 7, false}, unk, nil
}
func (c *Conn) Clone() *Conn {
return &Conn{
Raw: c.Raw.Clone(),
MaxRetries: c.MaxRetries,
Debug: c.Debug,
}
}
func (c *Conn) reconnectIfNetErr(nn *int, err *error) {
for *err != nil && IsNetErr(*err) && *nn <= c.MaxRetries {
if c.Debug {
log.Printf("Error: '%s' - reconnecting...", *err)
}
time.Sleep(1e9 * time.Duration(*nn))
*err = c.Raw.Reconnect()
if c.Debug && *err != nil {
log.Println("Can't reconnect:", *err)
}
*nn++
}
}
func (c *Conn) connectIfNotConnected() (err error) {
if c.Raw.IsConnected() {
return
}
err = c.Raw.Connect()
nn := 0
c.reconnectIfNetErr(&nn, &err)
return
}
func (c *Conn) Reconnect() (err error) {
err = c.Raw.Reconnect()
nn := 0
c.reconnectIfNetErr(&nn, &err)
return
}
func (c *Conn) Register(sql string) {
c.Raw.Register(sql)
}
func (c *Conn) SetMaxPktSize(new_size int) int {
return c.Raw.SetMaxPktSize(new_size)
}
// Automatic connect/reconnect/repeat version of Use
func (c *Conn) Use(dbname string) (err error) {
if err = c.connectIfNotConnected(); err != nil {
return
}
nn := 0
for {
if err = c.Raw.Use(dbname); err == nil {
return
}
if c.reconnectIfNetErr(&nn, &err); err != nil {
return
}
}
panic(nil)
}
// Automatic connect/reconnect/repeat version of Query
func (c *Conn) Query(sql string, params ...interface{}) (rows []mysql.Row, res mysql.Result, err error) {
if err = c.connectIfNotConnected(); err != nil {
return
}
nn := 0
for {
if rows, res, err = c.Raw.Query(sql, params...); err == nil {
return
}
if c.reconnectIfNetErr(&nn, &err); err != nil {
return
}
}
panic(nil)
}
func (c *Conn) QueryFirst(sql string, params ...interface{}) (row mysql.Row, res mysql.Result, err error) {
if err = c.connectIfNotConnected(); err != nil {
return
}
nn := 0
for {
if row, res, err = c.Raw.QueryFirst(sql, params...); err == nil {
return
}
if c.reconnectIfNetErr(&nn, &err); err != nil {
return
}
}
panic(nil)
}
func (c *Conn) QueryLast(sql string, params ...interface{}) (row mysql.Row, res mysql.Result, err error) {
if err = c.connectIfNotConnected(); err != nil {
return
}
nn := 0
for {
if row, res, err = c.Raw.QueryLast(sql, params...); err == nil {
return
}
if c.reconnectIfNetErr(&nn, &err); err != nil {
return
}
}
panic(nil)
}
type Stmt struct {
Raw mysql.Stmt
con *Conn
}
// Prepares statement if it wasn't prepared before
func (c *Conn) PrepareOnce(s *Stmt, sql string) error {
if s.Raw != nil {
return nil
}
if err := c.connectIfNotConnected(); err != nil {
return err
}
nn := 0
for {
var err error
if s.Raw, err = c.Raw.Prepare(sql); err == nil {
s.con = c
return nil
}
if c.reconnectIfNetErr(&nn, &err); err != nil {
return err
}
}
panic(nil)
}
// Automatic connect/reconnect/repeat version of Prepare
func (c *Conn) Prepare(sql string) (*Stmt, error) {
var s Stmt
if err := c.PrepareOnce(&s, sql); err != nil {
return nil, err
}
return &s, nil
}
func (s *Stmt) Bind(params ...interface{}) {
s.Raw.Bind(params...)
}
// Automatic connect/reconnect/repeat version of Exec
func (s *Stmt) Exec(params ...interface{}) (rows []mysql.Row, res mysql.Result, err error) {
if err = s.con.connectIfNotConnected(); err != nil {
return
}
nn := 0
for {
if rows, res, err = s.Raw.Exec(params...); err == nil {
return
}
if s.con.reconnectIfNetErr(&nn, &err); err != nil {
return
}
}
panic(nil)
}
func (s *Stmt) ExecFirst(params ...interface{}) (row mysql.Row, res mysql.Result, err error) {
if err = s.con.connectIfNotConnected(); err != nil {
return
}
nn := 0
for {
if row, res, err = s.Raw.ExecFirst(params...); err == nil {
return
}
if s.con.reconnectIfNetErr(&nn, &err); err != nil {
return
}
}
panic(nil)
}
func (s *Stmt) ExecLast(params ...interface{}) (row mysql.Row, res mysql.Result, err error) {
if err = s.con.connectIfNotConnected(); err != nil {
return
}
nn := 0
for {
if row, res, err = s.Raw.ExecLast(params...); err == nil {
return
}
if s.con.reconnectIfNetErr(&nn, &err); err != nil {
return
}
}
panic(nil)
}
Jump to Line
Something went wrong with that request. Please try again.