2
0

Save memory on non blocking read path

Only create RawConn.Read callback once and have it use NetConn fields.
Avoids the closure and some allocations.

https://github.com/jackc/pgx/issues/1481
This commit is contained in:
Jack Christensen
2023-01-27 20:53:30 -06:00
parent 2c7d86a543
commit bc754291c1
2 changed files with 24 additions and 8 deletions
+7
View File
@@ -79,6 +79,13 @@ type NetConn struct {
nonblockWriteErr error nonblockWriteErr error
nonblockWriteN int nonblockWriteN int
// non-blocking reads with syscall.RawConn are done with a callback function. By using these fields instead of the
// callback functions closure to pass the buf argument and receive the n and err results we avoid some allocations.
nonblockReadFunc func(fd uintptr) (done bool)
nonblockReadBuf []byte
nonblockReadErr error
nonblockReadN int
readDeadlineLock sync.Mutex readDeadlineLock sync.Mutex
readDeadline time.Time readDeadline time.Time
readNonblocking bool readNonblocking bool
+17 -8
View File
@@ -24,6 +24,7 @@ func (c *NetConn) realNonblockingWrite(b []byte) (n int, err error) {
err = c.rawConn.Write(c.nonblockWriteFunc) err = c.rawConn.Write(c.nonblockWriteFunc)
n = c.nonblockWriteN n = c.nonblockWriteN
c.nonblockWriteBuf = nil // ensure that no reference to b is kept.
if err == nil && c.nonblockWriteErr != nil { if err == nil && c.nonblockWriteErr != nil {
if errors.Is(c.nonblockWriteErr, syscall.EWOULDBLOCK) { if errors.Is(c.nonblockWriteErr, syscall.EWOULDBLOCK) {
err = ErrWouldBlock err = ErrWouldBlock
@@ -44,16 +45,24 @@ func (c *NetConn) realNonblockingWrite(b []byte) (n int, err error) {
} }
func (c *NetConn) realNonblockingRead(b []byte) (n int, err error) { func (c *NetConn) realNonblockingRead(b []byte) (n int, err error) {
var funcErr error if c.nonblockReadFunc == nil {
err = c.rawConn.Read(func(fd uintptr) (done bool) { c.nonblockReadFunc = func(fd uintptr) (done bool) {
n, funcErr = syscall.Read(int(fd), b) c.nonblockReadN, c.nonblockReadErr = syscall.Read(int(fd), c.nonblockReadBuf)
return true return true
}) }
if err == nil && funcErr != nil { }
if errors.Is(funcErr, syscall.EWOULDBLOCK) { c.nonblockReadBuf = b
c.nonblockReadN = 0
c.nonblockReadErr = nil
err = c.rawConn.Read(c.nonblockReadFunc)
n = c.nonblockReadN
c.nonblockReadBuf = nil // ensure that no reference to b is kept.
if err == nil && c.nonblockReadErr != nil {
if errors.Is(c.nonblockReadErr, syscall.EWOULDBLOCK) {
err = ErrWouldBlock err = ErrWouldBlock
} else { } else {
err = funcErr err = c.nonblockReadErr
} }
} }
if err != nil { if err != nil {