On Mon, Apr 27, 2020 at 6:59 PM Liam <networkimp...@gmail.com> wrote:
>
> On Monday, April 27, 2020 at 5:56:52 PM UTC-7, Ian Lance Taylor wrote:
>>
>> On Mon, Apr 27, 2020 at 5:10 PM Liam <networ...@gmail.com> wrote:
>> >
>> > On Monday, April 27, 2020 at 4:22:41 PM UTC-7, Ian Lance Taylor wrote:
>> >>
>> >> On Sun, Apr 26, 2020 at 4:55 PM Liam <networ...@gmail.com> wrote:
>> >> >
>> >> > During an io.Copy() where the Writer is a TCPConn and the Reader is a 
>> >> > 200K disk file, my code may concurrently Write() on the same TCPConn.
>> >> >
>> >> > I see the result of the Write() inserted into the result of the 
>> >> > io.Copy(). I had the impression that was impossible, but I must be 
>> >> > mistaken, as the sendfile(2) docs read:
>> >> >
>> >> > Note that a successful call to sendfile() may write fewer bytes than 
>> >> > requested; the caller should be prepared to retry the call if there 
>> >> > were unsent bytes.
>> >> >
>> >> > Could someone confirm that one must indeed synchronize concurrent use 
>> >> > of tcpConn.Write() and io.Copy(tcpConn, file)?
>> >>
>> >> Synchronization should not be required.  internal/poll.Sendfile
>> >> acquires a write lock on dstFD, which is the TCP socket.  That should
>> >> ensure that the contents of an ordinary Write (which also acquires a
>> >> write lock) should not interleave with the sendfile data.
>> >>
>> >> That said, if the sendfile system call cannot be used for whatever
>> >> reason, the net package will fall back on doing ordinary Read and
>> >> Write calls.  And those Write calls can be interleaved with other
>> >> Write calls done by a different goroutine.  I think that is probably
>> >> permitted, in that io.Copy doesn't promise to not interleave with
>> >> simultaneous Write calls on the destination.
>> >>
>> >> So in the general case you should indeed use your own locking to avoid
>> >> interleaving between io.Copy and a concurrent Write.
>> >
>> >
>> > Thanks for the details. Where could I add a Println() to reveal why it 
>> > doesn't call poll.Sendfile()?
>> >
>> > I expect this system to use sendfile(2). The file is a normal file on a 
>> > local partition (running on a Digital Ocean Droplet).
>> >
>> >
>> > /etc/fstab has:
>> > UUID=[omitted] /                       ext4    defaults        1 1
>> >
>> >
>> > $ df -h
>> > Filesystem      Size  Used Avail Use% Mounted on
>> > devtmpfs        981M     0  981M   0% /dev
>> > tmpfs           996M     0  996M   0% /dev/shm
>> > tmpfs           996M  436K  995M   1% /run
>> > tmpfs           996M     0  996M   0% /sys/fs/cgroup
>> > /dev/vda1        59G  5.7G   51G  11% /
>> > tmpfs           200M     0  200M   0% /run/user/0
>>
>>
>> Well, I don't know for that it doesn't use sendfile, I just can't
>> explain the results you're seeing if it does use sendfile.
>>
>> The place to start is to find out why (or whether)
>> internal/poll.Sendfile is returning 0, nil.
>
>
> Found the invocations, wrong letter case...
>
> $ grep -r 'SendFile(' /usr/local/go/src/
> /usr/local/go/src/net/sendfile_windows.go:      done, err := 
> poll.SendFile(&fd.pfd, syscall.Handle(f.Fd()), n)
> /usr/local/go/src/net/sendfile_linux.go:                written, werr = 
> poll.SendFile(&c.pfd, int(fd), remain)
> /usr/local/go/src/net/sendfile_unix_alt.go:             written, werr = 
> poll.SendFile(&c.pfd, int(fd), pos, remain)
> /usr/local/go/src/internal/poll/sendfile_windows.go:func SendFile(fd *FD, src 
> syscall.Handle, n int64) (int64, error) {
> /usr/local/go/src/internal/poll/sendfile_linux.go:func SendFile(dstFD *FD, 
> src int, remain int64) (int64, error) {
> /usr/local/go/src/internal/poll/sendfile_solaris.go:func SendFile(dstFD *FD, 
> src int, pos, remain int64) (int64, error) {
> /usr/local/go/src/internal/poll/sendfile_bsd.go:func SendFile(dstFD *FD, src 
> int, pos, remain int64) (int64, error) {
>
> $ grep -r 'sendFile(' /usr/local/go/src/net/
> /usr/local/go/src/net/sendfile_windows.go:func sendFile(fd *netFD, r 
> io.Reader) (written int64, err error, handled bool) {
> /usr/local/go/src/net/sendfile_linux.go:func sendFile(c *netFD, r io.Reader) 
> (written int64, err error, handled bool) {
> /usr/local/go/src/net/sendfile_unix_alt.go:func sendFile(c *netFD, r 
> io.Reader) (written int64, err error, handled bool) {
> /usr/local/go/src/net/sendfile_stub.go:func sendFile(c *netFD, r io.Reader) 
> (n int64, err error, handled bool) {
> /usr/local/go/src/net/tcpsock_posix.go: if n, err, handled := sendFile(c.fd, 
> r); handled {
>
> Should I check the 'handled' result of sendFile() in net/tcpsock_posix.go ?

Sure.  Should be the same thing as the result of poll.SendFile.

Ian

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAOyqgcVHJVZUtNBu04bxwK6qeHE9-VGJF3J%2B3K90KGzphP%3DaTA%40mail.gmail.com.

Reply via email to