On Monday, April 27, 2020 at 10:00:52 PM UTC-7, Ian Lance Taylor wrote:
>
> On Mon, Apr 27, 2020 at 6:59 PM Liam <networ...@gmail.com <javascript:>> 
> 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 this is a surprise... Added some println()s

// my network setup
   aCfgTcp := net.ListenConfig{KeepAlive: -1}
   aListener, err := aCfgTcp.Listen(nil, iConf.Listen.Net, 
iConf.Listen.Laddr)
   if err != nil { return err }
   aCert, err := tls.LoadX509KeyPair(iConf.Listen.CertPath, 
iConf.Listen.KeyPath)
   if err != nil { return err }
   aCfgTls := tls.Config{Certificates: []tls.Certificate{aCert}}
   aListener = tls.NewListener(aListener, &aCfgTls)

// conn writer goroutine, before io.Copy
   println(".. io.Copy to net") 
// conn reader goroutine, before io.CopyN
   println(".. io.CopyN to file") 

// package io
func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err 
error) {
        // If the reader has a WriteTo method, use it to do the copy.
        // Avoids an allocation and a copy.
        if wt, ok := src.(WriterTo); ok {
println(".. WriteTo")
                return wt.WriteTo(dst)
        }
        // Similarly, if the writer has a ReadFrom method, use it to do the 
copy.
        if rt, ok := dst.(ReaderFrom); ok {
println(".. ReadFrom")
                return rt.ReadFrom(src)
        }
println(".. manual")
[etc]

// package net
func (c *TCPConn) readFrom(r io.Reader) (int64, error) {
        if n, err, handled := splice(c.fd, r); handled {
println(".. spliced")
                return n, err
        }
        if n, err, handled := sendFile(c.fd, r); handled {
println(".. sendFiled")
                return n, err
        }
println(".. generic")
        return genericReadFrom(c, r)

LOG:
.. io.CopyN to file
.. manual
.. io.Copy to net
.. manual
.. io.CopyN to file
.. manual
.. io.Copy to net
.. manual
.. io.CopyN to file
.. manual
.. io.Copy to net
.. manual
.. io.Copy to net
.. manual
.. io.Copy to net
.. manual
.. io.Copy to net
.. manual

Not a sendfile(2) or splice(2) in sight :-(

-- 
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/45642e1e-a9d6-4cd2-9e1f-ea1499a530b5%40googlegroups.com.

Reply via email to