You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@thrift.apache.org by dc...@apache.org on 2020/06/09 20:07:55 UTC
[thrift] branch master updated: THRIFT-5214: Reset read deadline in
socketConn
This is an automated email from the ASF dual-hosted git repository.
dcelasun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/thrift.git
The following commit(s) were added to refs/heads/master by this push:
new cfbb905 THRIFT-5214: Reset read deadline in socketConn
cfbb905 is described below
commit cfbb905034c928f073639af00b30d74951744b61
Author: Yuxuan 'fishy' Wang <yu...@reddit.com>
AuthorDate: Tue Jun 9 13:07:38 2020 -0700
THRIFT-5214: Reset read deadline in socketConn
Client: go
This is a slightly different, and less error-prone approach from the
fix in e382275b.
The previous approach relies on passing the set socket timeout into the
underlying socketConn from TSocket and TSSLSocket. But since we have so
many different constructors for TSocket and TSSLSocket, some makes the
initial connection in the constructor and some does not, there are so
many different places we would need to remember to pass socketTimeout
into socketConn. In the future, when we add another constructor to them,
we could either forget to pass the socket timeout into socketConn, or
try to pass it while we haven't constructed socketConn yet (which will
cause panic), both are bad.
In this approach we just clear the read deadline in the connectivity
check read. Because that's a non-blocking read, it would work just fine
without a read deadline.
---
lib/go/thrift/socket.go | 11 ++++-------
lib/go/thrift/socket_conn.go | 10 ++++++----
lib/go/thrift/socket_unix_conn.go | 15 +++++++++------
lib/go/thrift/ssl_socket.go | 12 ++++--------
4 files changed, 23 insertions(+), 25 deletions(-)
diff --git a/lib/go/thrift/socket.go b/lib/go/thrift/socket.go
index 5080894..eb94faf 100644
--- a/lib/go/thrift/socket.go
+++ b/lib/go/thrift/socket.go
@@ -58,9 +58,7 @@ func NewTSocketFromAddrTimeout(addr net.Addr, connTimeout time.Duration, soTimeo
// Creates a TSocket from an existing net.Conn
func NewTSocketFromConnTimeout(conn net.Conn, connTimeout time.Duration) *TSocket {
- sock := &TSocket{conn: wrapSocketConn(conn), addr: conn.RemoteAddr(), connectTimeout: connTimeout, socketTimeout: connTimeout}
- sock.conn.socketTimeout = connTimeout
- return sock
+ return &TSocket{conn: wrapSocketConn(conn), addr: conn.RemoteAddr(), connectTimeout: connTimeout, socketTimeout: connTimeout}
}
// Sets the connect timeout
@@ -72,9 +70,6 @@ func (p *TSocket) SetConnTimeout(timeout time.Duration) error {
// Sets the socket timeout
func (p *TSocket) SetSocketTimeout(timeout time.Duration) error {
p.socketTimeout = timeout
- if p.conn != nil {
- p.conn.socketTimeout = timeout
- }
return nil
}
@@ -114,7 +109,6 @@ func (p *TSocket) Open() error {
)); err != nil {
return NewTTransportException(NOT_OPEN, err.Error())
}
- p.conn.socketTimeout = p.socketTimeout
return nil
}
@@ -151,6 +145,9 @@ func (p *TSocket) Read(buf []byte) (int, error) {
return 0, NewTTransportException(NOT_OPEN, "Connection not open")
}
p.pushDeadline(true, false)
+ // NOTE: Calling any of p.IsOpen, p.conn.read0, or p.conn.IsOpen between
+ // p.pushDeadline and p.conn.Read could cause the deadline set inside
+ // p.pushDeadline being reset, thus need to be avoided.
n, err := p.conn.Read(buf)
return n, NewTTransportExceptionFromError(err)
}
diff --git a/lib/go/thrift/socket_conn.go b/lib/go/thrift/socket_conn.go
index 5ed598e..40aea61 100644
--- a/lib/go/thrift/socket_conn.go
+++ b/lib/go/thrift/socket_conn.go
@@ -23,16 +23,14 @@ import (
"bytes"
"io"
"net"
- "time"
)
// socketConn is a wrapped net.Conn that tries to do connectivity check.
type socketConn struct {
net.Conn
- socketTimeout time.Duration
- buf bytes.Buffer
- buffer [1]byte
+ buf bytes.Buffer
+ buffer [1]byte
}
var _ net.Conn = (*socketConn)(nil)
@@ -78,6 +76,10 @@ func (sc *socketConn) isValid() bool {
// connection is nil.
//
// Otherwise, it tries to do a connectivity check and returns the result.
+//
+// It also has the side effect of resetting the previously set read deadline on
+// the socket. As a result, it shouldn't be called between setting read deadline
+// and doing actual read.
func (sc *socketConn) IsOpen() bool {
if !sc.isValid() {
return false
diff --git a/lib/go/thrift/socket_unix_conn.go b/lib/go/thrift/socket_unix_conn.go
index 789b4fa..4535e75 100644
--- a/lib/go/thrift/socket_unix_conn.go
+++ b/lib/go/thrift/socket_unix_conn.go
@@ -27,6 +27,11 @@ import (
"time"
)
+// We rely on this variable to be the zero time,
+// but define it as global variable to avoid repetitive allocations.
+// Please DO NOT mutate this variable in any way.
+var zeroTime time.Time
+
func (sc *socketConn) read0() error {
return sc.checkConn()
}
@@ -38,12 +43,10 @@ func (sc *socketConn) checkConn() error {
return nil
}
- // Push read deadline
- var t time.Time
- if sc.socketTimeout > 0 {
- t = time.Now().Add(sc.socketTimeout)
- }
- sc.Conn.SetReadDeadline(t)
+ // The reading about to be done here is non-blocking so we don't really
+ // need a read deadline. We just need to clear the previously set read
+ // deadline, if any.
+ sc.Conn.SetReadDeadline(zeroTime)
rc, err := syscallConn.SyscallConn()
if err != nil {
diff --git a/lib/go/thrift/ssl_socket.go b/lib/go/thrift/ssl_socket.go
index 6e90438..31ef3a0 100644
--- a/lib/go/thrift/ssl_socket.go
+++ b/lib/go/thrift/ssl_socket.go
@@ -62,17 +62,12 @@ func NewTSSLSocketFromAddrTimeout(addr net.Addr, cfg *tls.Config, timeout time.D
// Creates a TSSLSocket from an existing net.Conn
func NewTSSLSocketFromConnTimeout(conn net.Conn, cfg *tls.Config, timeout time.Duration) *TSSLSocket {
- sock := &TSSLSocket{conn: wrapSocketConn(conn), addr: conn.RemoteAddr(), timeout: timeout, cfg: cfg}
- sock.conn.socketTimeout = timeout
- return sock
+ return &TSSLSocket{conn: wrapSocketConn(conn), addr: conn.RemoteAddr(), timeout: timeout, cfg: cfg}
}
// Sets the socket timeout
func (p *TSSLSocket) SetTimeout(timeout time.Duration) error {
p.timeout = timeout
- if p.conn != nil {
- p.conn.socketTimeout = timeout
- }
return nil
}
@@ -106,7 +101,6 @@ func (p *TSSLSocket) Open() error {
)); err != nil {
return NewTTransportException(NOT_OPEN, err.Error())
}
- p.conn.socketTimeout = p.timeout
} else {
if p.conn.isValid() {
return NewTTransportException(ALREADY_OPEN, "Socket already connected.")
@@ -130,7 +124,6 @@ func (p *TSSLSocket) Open() error {
)); err != nil {
return NewTTransportException(NOT_OPEN, err.Error())
}
- p.conn.socketTimeout = p.timeout
}
return nil
}
@@ -163,6 +156,9 @@ func (p *TSSLSocket) Read(buf []byte) (int, error) {
return 0, NewTTransportException(NOT_OPEN, "Connection not open")
}
p.pushDeadline(true, false)
+ // NOTE: Calling any of p.IsOpen, p.conn.read0, or p.conn.IsOpen between
+ // p.pushDeadline and p.conn.Read could cause the deadline set inside
+ // p.pushDeadline being reset, thus need to be avoided.
n, err := p.conn.Read(buf)
return n, NewTTransportExceptionFromError(err)
}