Skip to content

Commit 769c8b4

Browse files
committed
Added read_timeout and write_timeout to driver settings
lib#450 lib#792
1 parent 072e83d commit 769c8b4

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
@@ -153,6 +153,12 @@ type conn struct {
153153
// round-trip mode for non-prepared Query calls.
154154
binaryParameters bool
155155

156+
// Timeouts for read and write operations against the database server.
157+
// A duration of 0 indicates no timeout.
158+
// specified in milliseconds
159+
readTimeout time.Duration
160+
writeTimeout time.Duration
161+
156162
// If true this connection is in the middle of a COPY
157163
inCopy bool
158164

@@ -180,7 +186,28 @@ func (cn *conn) handleDriverSettings(o values) (err error) {
180186
}
181187
return nil
182188
}
189+
timeSetting := func(key string, val *time.Duration) error {
190+
if value := o[key]; value != "" {
191+
timeout, err := strconv.Atoi(value)
192+
if err != nil {
193+
return err
194+
}
195+
// timeout is specified in milliseconds.
196+
*val = time.Duration(timeout) * time.Millisecond
197+
} else {
198+
*val = time.Duration(0) * time.Millisecond
199+
}
200+
return nil
201+
}
183202

203+
err = timeSetting("read_timeout", &cn.readTimeout)
204+
if err != nil {
205+
return err
206+
}
207+
err = timeSetting("write_timeout", &cn.writeTimeout)
208+
if err != nil {
209+
return err
210+
}
184211
err = boolSetting("disable_prepared_binary_result", &cn.disablePreparedBinaryResult)
185212
if err != nil {
186213
return err
@@ -924,7 +951,37 @@ func (se *safeRetryError) Error() string {
924951
return se.Err.Error()
925952
}
926953

954+
// Set the write deadline if we have a write timeout set.
955+
func (cn *conn) setWriteTimeout() {
956+
if cn.writeTimeout != 0 {
957+
cn.c.SetWriteDeadline(time.Now().Add(cn.writeTimeout))
958+
}
959+
}
960+
961+
// Clear the write deadline if we set one.
962+
func (cn *conn) cleanWriteTimeout() {
963+
if cn.writeTimeout != 0 {
964+
cn.c.SetWriteDeadline(time.Time{})
965+
}
966+
}
967+
968+
// Set the read deadline if we have a read timeout set.
969+
func (cn *conn) setReadTimeout() {
970+
if cn.readTimeout != 0 {
971+
cn.c.SetReadDeadline(time.Now().Add(cn.readTimeout))
972+
}
973+
}
974+
975+
// Clear the read deadline if we set one.
976+
func (cn *conn) cleanReadTimeout() {
977+
if cn.readTimeout != 0 {
978+
cn.c.SetReadDeadline(time.Time{})
979+
}
980+
}
981+
927982
func (cn *conn) send(m *writeBuf) {
983+
cn.setWriteTimeout()
984+
defer cn.cleanWriteTimeout()
928985
n, err := cn.c.Write(m.wrap())
929986
if err != nil {
930987
if n == 0 {
@@ -935,6 +992,8 @@ func (cn *conn) send(m *writeBuf) {
935992
}
936993

937994
func (cn *conn) sendStartupPacket(m *writeBuf) error {
995+
cn.setWriteTimeout()
996+
defer cn.cleanWriteTimeout()
938997
_, err := cn.c.Write((m.wrap())[1:])
939998
return err
940999
}
@@ -943,6 +1002,8 @@ func (cn *conn) sendStartupPacket(m *writeBuf) error {
9431002
// message should have no payload. This method does not use the scratch
9441003
// buffer.
9451004
func (cn *conn) sendSimpleMessage(typ byte) (err error) {
1005+
cn.setWriteTimeout()
1006+
defer cn.cleanWriteTimeout()
9461007
_, err = cn.c.Write([]byte{typ, '\x00', '\x00', '\x00', '\x04'})
9471008
return err
9481009
}
@@ -973,6 +1034,9 @@ func (cn *conn) recvMessage(r *readBuf) (byte, error) {
9731034
return t, nil
9741035
}
9751036

1037+
cn.setReadTimeout()
1038+
defer cn.cleanReadTimeout()
1039+
9761040
x := cn.scratch[:5]
9771041
_, err := io.ReadFull(cn.buf, x)
9781042
if err != nil {
@@ -1110,6 +1174,10 @@ func isDriverSetting(key string) bool {
11101174
return true
11111175
case "binary_parameters":
11121176
return true
1177+
case "read_timeout":
1178+
return true
1179+
case "write_timeout":
1180+
return true
11131181
case "krbsrvname":
11141182
return true
11151183
case "krbspn":

0 commit comments

Comments
 (0)