From 0fc9ed6ba0f8d1acb8bba8f86671d24f57ea7a31 Mon Sep 17 00:00:00 2001 From: Stephen J Day Date: Fri, 1 Dec 2017 10:00:50 -0800 Subject: [PATCH] ttrpc: use syscall.RawConn to access fd over File Due to a performance drop when calling `(*net.UnixConn).File`, this change uses the `syscall.RawConn` directly to call `Control` on the socket. The result is there is no longer a performance penalty to using unix socket credentials. The benchmarks after this change are as follows: ``` goos: linux goarch: amd64 pkg: github.com/stevvooe/ttrpc BenchmarkRoundTrip-8 50000 22474 ns/op 2593 B/op 43 allocs/op BenchmarkRoundTripUnixSocketCreds-8 100000 22120 ns/op 2593 B/op 43 allocs/op PASS ok github.com/stevvooe/ttrpc 4.049s ``` Signed-off-by: Stephen J Day --- unixcreds.go | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/unixcreds.go b/unixcreds.go index 5de8b92..23eb358 100644 --- a/unixcreds.go +++ b/unixcreds.go @@ -20,17 +20,21 @@ func (fn UnixCredentialsFunc) Handshake(ctx context.Context, conn net.Conn) (net return nil, nil, errors.Wrap(err, "ttrpc.UnixCredentialsFunc: require unix socket") } - // TODO(stevvooe): Calling (*UnixConn).File causes a 5x performance - // decrease vs just accessing the fd directly. Need to do some more - // troubleshooting to isolate this to Go runtime or kernel. - fp, err := uc.File() + rs, err := uc.SyscallConn() if err != nil { - return nil, nil, errors.Wrap(err, "ttrpc.UnixCredentialsFunc: failed to get unix file") + return nil, nil, errors.Wrap(err, "ttrpc.UnixCredentialsFunc: (net.UnixConn).SyscallConn failed") + } + var ( + ucred *unix.Ucred + ucredErr error + ) + if err := rs.Control(func(fd uintptr) { + ucred, ucredErr = unix.GetsockoptUcred(int(fd), unix.SOL_SOCKET, unix.SO_PEERCRED) + }); err != nil { + return nil, nil, errors.Wrapf(err, "ttrpc.UnixCredentialsFunc: (*syscall.RawConn).Control failed") } - defer fp.Close() // this gets duped and must be closed when this method is complete. - ucred, err := unix.GetsockoptUcred(int(fp.Fd()), unix.SOL_SOCKET, unix.SO_PEERCRED) - if err != nil { + if ucredErr != nil { return nil, nil, errors.Wrapf(err, "ttrpc.UnixCredentialsFunc: failed to retrieve socket peer credentials") }