Skip to content

Commit c17864f

Browse files
committed
Added read_timeout and write_timeout to driver settings
lib#450 lib#792
1 parent 2a217b9 commit c17864f

1 file changed

Lines changed: 68 additions & 0 deletions

File tree

conn.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,12 @@ type conn struct {
159159
// round-trip mode for non-prepared Query calls.
160160
binaryParameters bool
161161

162+
// Timeouts for read and write operations against the database server.
163+
// A duration of 0 indicates no timeout.
164+
// specified in milliseconds
165+
readTimeout time.Duration
166+
writeTimeout time.Duration
167+
162168
// If true this connection is in the middle of a COPY
163169
inCopy bool
164170

@@ -220,7 +226,28 @@ func (cn *conn) handleDriverSettings(o values) (err error) {
220226
}
221227
return nil
222228
}
229+
timeSetting := func(key string, val *time.Duration) error {
230+
if value := o[key]; value != "" {
231+
timeout, err := strconv.Atoi(value)
232+
if err != nil {
233+
return err
234+
}
235+
// timeout is specified in milliseconds.
236+
*val = time.Duration(timeout) * time.Millisecond
237+
} else {
238+
*val = time.Duration(0) * time.Millisecond
239+
}
240+
return nil
241+
}
223242

243+
err = timeSetting("read_timeout", &cn.readTimeout)
244+
if err != nil {
245+
return err
246+
}
247+
err = timeSetting("write_timeout", &cn.writeTimeout)
248+
if err != nil {
249+
return err
250+
}
224251
err = boolSetting("disable_prepared_binary_result", &cn.disablePreparedBinaryResult)
225252
if err != nil {
226253
return err
@@ -965,7 +992,37 @@ func (se *safeRetryError) Error() string {
965992
return se.Err.Error()
966993
}
967994

995+
// Set the write deadline if we have a write timeout set.
996+
func (cn *conn) setWriteTimeout() {
997+
if cn.writeTimeout != 0 {
998+
cn.c.SetWriteDeadline(time.Now().Add(cn.writeTimeout))
999+
}
1000+
}
1001+
1002+
// Clear the write deadline if we set one.
1003+
func (cn *conn) cleanWriteTimeout() {
1004+
if cn.writeTimeout != 0 {
1005+
cn.c.SetWriteDeadline(time.Time{})
1006+
}
1007+
}
1008+
1009+
// Set the read deadline if we have a read timeout set.
1010+
func (cn *conn) setReadTimeout() {
1011+
if cn.readTimeout != 0 {
1012+
cn.c.SetReadDeadline(time.Now().Add(cn.readTimeout))
1013+
}
1014+
}
1015+
1016+
// Clear the read deadline if we set one.
1017+
func (cn *conn) cleanReadTimeout() {
1018+
if cn.readTimeout != 0 {
1019+
cn.c.SetReadDeadline(time.Time{})
1020+
}
1021+
}
1022+
9681023
func (cn *conn) send(m *writeBuf) {
1024+
cn.setWriteTimeout()
1025+
defer cn.cleanWriteTimeout()
9691026
n, err := cn.c.Write(m.wrap())
9701027
if err != nil {
9711028
if n == 0 {
@@ -976,6 +1033,8 @@ func (cn *conn) send(m *writeBuf) {
9761033
}
9771034

9781035
func (cn *conn) sendStartupPacket(m *writeBuf) error {
1036+
cn.setWriteTimeout()
1037+
defer cn.cleanWriteTimeout()
9791038
_, err := cn.c.Write((m.wrap())[1:])
9801039
return err
9811040
}
@@ -984,6 +1043,8 @@ func (cn *conn) sendStartupPacket(m *writeBuf) error {
9841043
// message should have no payload. This method does not use the scratch
9851044
// buffer.
9861045
func (cn *conn) sendSimpleMessage(typ byte) (err error) {
1046+
cn.setWriteTimeout()
1047+
defer cn.cleanWriteTimeout()
9871048
_, err = cn.c.Write([]byte{typ, '\x00', '\x00', '\x00', '\x04'})
9881049
return err
9891050
}
@@ -1014,6 +1075,9 @@ func (cn *conn) recvMessage(r *readBuf) (byte, error) {
10141075
return t, nil
10151076
}
10161077

1078+
cn.setReadTimeout()
1079+
defer cn.cleanReadTimeout()
1080+
10171081
x := cn.scratch[:5]
10181082
_, err := io.ReadFull(cn.buf, x)
10191083
if err != nil {
@@ -1151,6 +1215,10 @@ func isDriverSetting(key string) bool {
11511215
return true
11521216
case "binary_parameters":
11531217
return true
1218+
case "read_timeout":
1219+
return true
1220+
case "write_timeout":
1221+
return true
11541222
case "krbsrvname":
11551223
return true
11561224
case "krbspn":

0 commit comments

Comments
 (0)