| sendfile() in Go |
Roger Pau Monné |
04/09/10 08:53 |
|
| Re: [go-nuts] sendfile() in Go |
r |
04/09/10 15:48 |
That is one bizarre system call. I've never seen anything like it. It can be written in a few lines of efficient user code. The output must be a socket. Why not a general file descriptor? Is this yet another example of ''all files are equal but networks are more equal than others?" And then I see the input must be mmap-able. What a monster! The system call provides an extra type you can use to send (and receive) other pieces of unspecified data. What's wrong with writev? On BSD it's even got an unused parameter reserved for future expansion that must be zero. There appears to be an argument that it can be more efficient because the data crosses the user/kernel boundary only once. That's just a failure of the kernel's memory management. This is a clumsy way to fix it. Wow. -rob
|
| Re: [go-nuts] sendfile() in Go |
ron minnich |
04/09/10 16:48 |
On Sat, Sep 4, 2010 at 3:48 PM, Rob 'Commander' Pike <r...@google.com> wrote: > That is one bizarre system call. I've never seen anything like it. Would it surprise you to find that the inspiration (is that the right word?) for this came from Windows? My recollection is that the main reason it went in, years back, was to make web benchmarks go faster. ron
|
| Re: [go-nuts] sendfile() in Go |
Norman Yarvin |
05/09/10 10:46 |
On Sun, Sep 05, 2010 at 08:48:35AM +1000, Rob 'Commander' Pike wrote: >That is one bizarre system call. I've never seen anything like it. To quote an old linux-kernel message about sendfile(), "It was _very_ easy to implement, and can be considered a 5-minute hack to give a feature that fit very well in the MM architecture, and that the Apache folks had already been using on other architectures." -- Linus Torvalds
|
| Re: [go-nuts] sendfile() in Go |
David Roundy |
05/09/10 12:14 |
On Sat, Sep 4, 2010 at 6:48 PM, Rob 'Commander' Pike <r...@google.com> wrote: > There appears to be an argument that it can be more efficient because > the data crosses the user/kernel boundary only once. That's just a > failure of the kernel's memory management. This is a clumsy way to fix > it. I thought that the data crossed the user/kernel boundary zero times with sendfile... -- David Roundy
|
| Re: [go-nuts] sendfile() in Go |
Roger Pau Monné |
08/09/10 02:37 |
Hello again, Thanks for the info, now I was wondering if I could be able to perform concurrent io.Copy (or io.Copyn) with the same source file, or the offset will go crazy? If so, what's the best way to do this (perform concurrent io.Copyn at different offsets from the same source file)? Thanks, Roger. 2010/9/5 David Roundy <rou...@physics.oregonstate.edu>: |
| Re: [go-nuts] sendfile() in Go |
rog |
08/09/10 02:52 |
On 8 September 2010 10:37, Roger Pau Monné <roy...@gmail.com> wrote: > Hello again, > > Thanks for the info, now I was wondering if I could be able to perform > concurrent io.Copy (or io.Copyn) with the same source file, or the > offset will go crazy? If so, what's the best way to do this (perform > concurrent io.Copyn at different offsets from the same source file)? > > Thanks, Roger. you've got two options here: open the file multiple times, or use ReadAt instead of Read, which would mean copying and mutating io.Copy to use explicit offsets. e.g. type ReadAter interface { ReadAt(b []byte, off int64) (n int, err os.Error) } func CopyThreadSafe(dst os.Writer, r ReadAter) { ... } in the above, it still uses os.Writer, so you can't be writing to the same file concurrently, but i'd guess that's what you'd want. thus CopyThreadSafe is not a great name for it, but i hope you get the idea. > > 2010/9/5 David Roundy <rou...@physics.oregonstate.edu>: >> On Sat, Sep 4, 2010 at 6:48 PM, Rob 'Commander' Pike <r...@google.com> wrote: >>> There appears to be an argument that it can be more efficient because >>> the data crosses the user/kernel boundary only once. That's just a >>> failure of the kernel's memory management. This is a clumsy way to fix >>> it. >> >> I thought that the data crossed the user/kernel boundary zero times >> with sendfile... >> -- >> David Roundy >> >
|
| Re: [go-nuts] sendfile() in Go |
Roger Pau Monné |
08/09/10 03:16 |
So os.ReadAt (that uses syscall.Pread) is thread safe? I will have to do the same inverse operation (reading from a single thread net.Conn and writing to a concurrent writer), but I think I get the idea. Thanks! 2010/9/8 roger peppe <rogp...@gmail.com>: |
| Re: [go-nuts] sendfile() in Go |
Andrew Gerrand |
08/09/10 03:16 |
Or, simpler, you can wrap your file in a pair of io.SectionReaders, which will use the File's ReadAt method and should behave nicely when read from concurrently. Andrew |
| Re: [go-nuts] sendfile() in Go |
Roger Pau Monné |
08/09/10 03:23 |
Thanks Andrew, io.SeactionReader is perfect for my use, an io.SectionWriter will also be good, but I think this is much more complicated. 2010/9/8 Andrew Gerrand <a...@golang.org>: |
| Re: [go-nuts] sendfile() in Go |
Andrew Gerrand |
08/09/10 03:25 |
On 8 September 2010 20:16, Roger Pau Monné <roy...@gmail.com> wrote: > So os.ReadAt (that uses syscall.Pread) is thread safe? I believe so. > I will have to do the same inverse operation (reading from a single > thread net.Conn and writing to a concurrent writer), but I think I get > the idea. If you're writing a single stream to multiple files you might want to check out io.MultiWriter: http://golang.org/pkg/io/#Writer.MultiWriter Andrew |
| Re: [go-nuts] sendfile() in Go |
Roger Pau Monné |
08/09/10 03:29 |
2010/9/8 Andrew Gerrand < a...@golang.org>: > On 8 September 2010 20:16, Roger Pau Monné <roy...@gmail.com> wrote: >> So os.ReadAt (that uses syscall.Pread) is thread safe? > > I believe so. > >> I will have to do the same inverse operation (reading from a single >> thread net.Conn and writing to a concurrent writer), but I think I get >> the idea. > > If you're writing a single stream to multiple files you might want to > check out io.MultiWriter: > http://golang.org/pkg/io/#Writer.MultiWriter >
Nope, I'm reading from various net.Conn and writing to several sections (offsets) of the same file at the same time. (well, now I'm not doing it at the same time, but I would like to do it). |
| Re: [go-nuts] sendfile() in Go |
Andrew Gerrand |
08/09/10 03:33 |
On 8 September 2010 20:29, Roger Pau Monné <roy...@gmail.com> wrote: > 2010/9/8 Andrew Gerrand <a...@golang.org>: >> On 8 September 2010 20:16, Roger Pau Monné <roy...@gmail.com> wrote: >>> So os.ReadAt (that uses syscall.Pread) is thread safe? >> >> I believe so. >> >>> I will have to do the same inverse operation (reading from a single >>> thread net.Conn and writing to a concurrent writer), but I think I get >>> the idea. >> >> If you're writing a single stream to multiple files you might want to >> check out io.MultiWriter: >> http://golang.org/pkg/io/#Writer.MultiWriter >> > > Nope, I'm reading from various net.Conn and writing to several > sections (offsets) of the same file at the same time. (well, now I'm > not doing it at the same time, but I would like to do it). Oh, in that case use WriteAt. If you want to write a SectionWriter, I'll review the CL. :-) http://golang.org/doc/contribute.html Andrew |
| Re: [go-nuts] sendfile() in Go |
Roger Pau Monné |
10/09/10 02:38 |
Hello again, I'm sorry to bother the list with this, I've spent 2 days trying to figure this out, but I cannot understand why it doesn't work, so let's see if someone knows what's happening (I'm sure it's just a stupid error, but I haven't been able to see it). I'm working on a bittorrent client in Go, and I have to send "piece" messages, which consists of a small header (with message length and piece index) and then a 2^14 payload that contains the data. I would like to send the piece data using io.Copy, but I don't know why it doesn't work. Here's a code that works (without using io.Copy), packing the whole message before sending (I'm sorry if it's a little difficult to understand): msg_byte = make([]byte, msg.length + 4) // Allocate memory for the whole message binary.BigEndian.PutUint32(msg_byte[0:4], msg.length) // Copy message length at the start buffer := bytes.NewBuffer(msg_byte[0:4]) buffer.WriteByte(msg.msgId) // Write msg ID ("piece" -> 7) buffer.Write(position) // Information about the piece payLoad := make([]byte, msg.length - 9) n, err := reader.Read(payLoad) if err != nil { log.Stderr("Wire -> Reading piece:", err, "read:", n) return } buffer.Write(payLoad) // Append piece data to the end log.Stderr("Wire -> Sending:", buffer.Bytes()) n, err = wire.conn.Write(buffer.Bytes()) // Send the peice log.Stderr("Wire -> Sent:", n, "bytes") if err != nil { return } And If I use io.Copy or if I send the message in two parts it doesn't work (the client on the other end closes the connection): msg_byte = make([]byte, 13) // Allocate memory for the header only binary.BigEndian.PutUint32(msg_byte[0:4], msg.length) // Write msg length buffer := bytes.NewBuffer(msg_byte[0:4]) buffer.WriteByte(msg.msgId) // Write ID buffer.Write(position) // Write info about the piece being send log.Stderr("Wire -> Sending header:", buffer.Bytes()) n, err = wire.conn.Write(buffer.Bytes()) // Send the header log.Stderr("Wire -> Sent:", n, "bytes") if err != nil { return } if msg.msgId == piece { payLoad := make([]byte, msg.length - 9) // Allocate memory for the piece data n, err := reader.Read(payLoad) // Read if err != nil { log.Stderr("Wire -> Reading piece:", err, "read:", n) } log.Stderr("Wire -> Sending piece") n, err = wire.conn.Write(payLoad) // Write if err != nil { return } log.Stderr("Wire -> Sent:", n, "bytes") } reader is an io.SectionReader in both cases, with the exact length. I don't use io.Copy in this example, but you can replace the contents of the last "if" with "io.Copy(wire.conn, reader)" and it won't work also. The number of bytes send is the same in both examples. Could someone throw some light into this? Thanks, Roger. |
| Re: [go-nuts] sendfile() in Go |
Roger Pau Monné |
10/09/10 05:06 |
Hello, I've done some more research, and I get to the conclusion that I cannot write the message using more than one call to Write(), I have tried using bufio.Writer, but still the same problem, if I try to send the message with two calls to Write, it fails, but if I do it with only one call it works (either directly to the net.Conn or using bufio.Writer). Any ideas? Thanks, Roger. 2010/9/10 Roger Pau Monné <roy...@gmail.com>: |
| Re: [go-nuts] sendfile() in Go |
Ian Lance Taylor |
10/09/10 07:21 |
Roger Pau Monné < roy...@gmail.com> writes: > if msg.msgId == piece { This is a difference between your two code fragments--the first one didn't seem to have a similar test. > payLoad := make([]byte, msg.length - 9) // Allocate memory for the piece data > n, err := reader.Read(payLoad) // Read How long does this take? Is it possible that the other end is timing out before this is read and then written? Unless the other end is using direct calls into the networking layer, I don't see how it could even detect that you are using multiple Write calls. Ian
|