Skip to content

Commit

Permalink
Improve timeouts implementation
Browse files Browse the repository at this point in the history
- use local attributes for timeouts
- do not type assert to net.Conn each time
- DSN params are CamelCase
  • Loading branch information
julienschmidt committed Jan 12, 2016
1 parent 4613f32 commit b88f271
Show file tree
Hide file tree
Showing 7 changed files with 35 additions and 30 deletions.
12 changes: 5 additions & 7 deletions benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,16 +215,14 @@ func BenchmarkRoundtripBin(b *testing.B) {
}

func BenchmarkInterpolation(b *testing.B) {
cfg := &config{
interpolateParams: true,
loc: time.UTC,
}

mc := &mysqlConn{
cfg: cfg,
cfg: &config{
interpolateParams: true,
loc: time.UTC,
},
maxPacketAllowed: maxPacketSize,
maxWriteSize: maxPacketSize - 1,
buf: newBuffer(nil, cfg),
buf: newBuffer(nil),
}

args := []driver.Value{
Expand Down
29 changes: 15 additions & 14 deletions buffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@

package mysql

import "io"
import "net"
import "time"
import (
"io"
"net"
"time"
)

const defaultBufSize = 4096

Expand All @@ -20,19 +22,18 @@ const defaultBufSize = 4096
// The buffer is similar to bufio.Reader / Writer but zero-copy-ish
// Also highly optimized for this particular use case.
type buffer struct {
buf []byte
rd io.Reader
idx int
length int
cfg *config
buf []byte
nc net.Conn
idx int
length int
timeout time.Duration
}

func newBuffer(rd io.Reader, cfg *config) buffer {
func newBuffer(nc net.Conn) buffer {
var b [defaultBufSize]byte
return buffer{
buf: b[:],
rd: rd,
cfg: cfg,
nc: nc,
}
}

Expand All @@ -58,13 +59,13 @@ func (b *buffer) fill(need int) error {
b.idx = 0

for {
if conn, ok := b.rd.(net.Conn); ok && b.cfg.readTimeout > 0 {
if err := conn.SetReadDeadline(time.Now().Add(b.cfg.readTimeout)); err != nil {
if b.timeout > 0 {
if err := b.nc.SetReadDeadline(time.Now().Add(b.timeout)); err != nil {
return err
}
}

nn, err := b.rd.Read(b.buf[n:])
nn, err := b.nc.Read(b.buf[n:])
n += nn

switch err {
Expand Down
3 changes: 2 additions & 1 deletion connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type mysqlConn struct {
cfg *config
maxPacketAllowed int
maxWriteSize int
writeTimeout time.Duration
flags clientFlag
status statusFlag
sequence uint8
Expand Down Expand Up @@ -131,7 +132,7 @@ func (mc *mysqlConn) Close() (err error) {
}

mc.cfg = nil
mc.buf.rd = nil
mc.buf.nc = nil

return
}
Expand Down
6 changes: 5 additions & 1 deletion driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,11 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
}
}

mc.buf = newBuffer(mc.netConn, mc.cfg)
mc.buf = newBuffer(mc.netConn)

// Set I/O timeouts
mc.buf.timeout = mc.cfg.readTimeout
mc.writeTimeout = mc.cfg.writeTimeout

// Reading Handshake Initialization Packet
cipher, err := mc.readInitPacket()
Expand Down
6 changes: 3 additions & 3 deletions packets.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ func (mc *mysqlConn) writePacket(data []byte) error {
data[3] = mc.sequence

// Write packet
if mc.cfg.writeTimeout > 0 {
if err := mc.netConn.SetWriteDeadline(time.Now().Add(mc.cfg.writeTimeout)); err != nil {
if mc.writeTimeout > 0 {
if err := mc.netConn.SetWriteDeadline(time.Now().Add(mc.writeTimeout)); err != nil {
return err
}
}
Expand Down Expand Up @@ -284,7 +284,7 @@ func (mc *mysqlConn) writeAuthPacket(cipher []byte) error {
return err
}
mc.netConn = tlsConn
mc.buf.rd = tlsConn
mc.buf.nc = tlsConn
}

// Filler [23 bytes] (all 0x00)
Expand Down
7 changes: 4 additions & 3 deletions utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,14 +260,15 @@ func parseDSNParams(cfg *config, params string) (err error) {
return
}

// I/O Timeouts
case "read_timeout":
// I/O Read Timeout
case "readTimeout":
cfg.readTimeout, err = time.ParseDuration(value)
if err != nil {
return
}

case "write_timeout":
// I/O Write Timeout
case "writeTimeout":
cfg.writeTimeout, err = time.ParseDuration(value)
if err != nil {
return
Expand Down
2 changes: 1 addition & 1 deletion utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ var testDSNs = []struct {
{"user@unix(/path/to/socket)/dbname?charset=utf8", "&{user:user passwd: net:unix addr:/path/to/socket dbname:dbname params:map[charset:utf8] loc:%p tls:<nil> timeout:0 readTimeout:0 writeTimeout:0 collation:33 allowAllFiles:false allowOldPasswords:false allowCleartextPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
{"user:password@tcp(localhost:5555)/dbname?charset=utf8&tls=true", "&{user:user passwd:password net:tcp addr:localhost:5555 dbname:dbname params:map[charset:utf8] loc:%p tls:<nil> timeout:0 readTimeout:0 writeTimeout:0 collation:33 allowAllFiles:false allowOldPasswords:false allowCleartextPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
{"user:password@tcp(localhost:5555)/dbname?charset=utf8mb4,utf8&tls=skip-verify", "&{user:user passwd:password net:tcp addr:localhost:5555 dbname:dbname params:map[charset:utf8mb4,utf8] loc:%p tls:<nil> timeout:0 readTimeout:0 writeTimeout:0 collation:33 allowAllFiles:false allowOldPasswords:false allowCleartextPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
{"user:password@/dbname?loc=UTC&timeout=30s&read_timeout=1s&write_timeout=1s&allowAllFiles=1&clientFoundRows=true&allowOldPasswords=TRUE&collation=utf8mb4_unicode_ci", "&{user:user passwd:password net:tcp addr:127.0.0.1:3306 dbname:dbname params:map[] loc:%p tls:<nil> timeout:30000000000 readTimeout:1000000000 writeTimeout:1000000000 collation:224 allowAllFiles:true allowOldPasswords:true allowCleartextPasswords:false clientFoundRows:true columnsWithAlias:false interpolateParams:false}", time.UTC},
{"user:password@/dbname?loc=UTC&timeout=30s&readTimeout=1s&writeTimeout=1s&allowAllFiles=1&clientFoundRows=true&allowOldPasswords=TRUE&collation=utf8mb4_unicode_ci", "&{user:user passwd:password net:tcp addr:127.0.0.1:3306 dbname:dbname params:map[] loc:%p tls:<nil> timeout:30000000000 readTimeout:1000000000 writeTimeout:1000000000 collation:224 allowAllFiles:true allowOldPasswords:true allowCleartextPasswords:false clientFoundRows:true columnsWithAlias:false interpolateParams:false}", time.UTC},
{"user:p@ss(word)@tcp([de:ad:be:ef::ca:fe]:80)/dbname?loc=Local", "&{user:user passwd:p@ss(word) net:tcp addr:[de:ad:be:ef::ca:fe]:80 dbname:dbname params:map[] loc:%p tls:<nil> timeout:0 readTimeout:0 writeTimeout:0 collation:33 allowAllFiles:false allowOldPasswords:false allowCleartextPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.Local},
{"/dbname", "&{user: passwd: net:tcp addr:127.0.0.1:3306 dbname:dbname params:map[] loc:%p tls:<nil> timeout:0 readTimeout:0 writeTimeout:0 collation:33 allowAllFiles:false allowOldPasswords:false allowCleartextPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
{"@/", "&{user: passwd: net:tcp addr:127.0.0.1:3306 dbname: params:map[] loc:%p tls:<nil> timeout:0 readTimeout:0 writeTimeout:0 collation:33 allowAllFiles:false allowOldPasswords:false allowCleartextPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
Expand Down

0 comments on commit b88f271

Please sign in to comment.