-
Notifications
You must be signed in to change notification settings - Fork 17.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
net: arrange zero-copy of os.File and TCPConn to UnixConn #58808
Comments
Change https://go.dev/cl/472475 mentions this issue: |
/cc @rsc @ianlancetaylor |
Quite an unfortunate collision of names. |
Interesting question, I've never verified whether that approach works but I doubt it because Unix domain sockets don’t actually write the data they send to the disk like regular files, as that would be far too slow. Instead, all the data is retained within kernel memory; the only point of the socket file on disk is maintaining a reference to the sockets and giving it filesystem permissions to control access, thus, |
It seems awkward for something like It's possible that something like #41198 can help here. |
In fact, I intended to fall back to |
I think it's worth considering. I don't know for sure that it is better. I do think that it is confusing for |
Any other comments from the team on this proposal? I'd like to solicit more opinions here, thanks! |
Change https://go.dev/cl/475535 mentions this issue: |
After refreshing my memory of #41198, I don't think it necessarily helps. We can't really change But we can do something like CL 475535. I think that approach will permit the cases we want here. |
Actually, I didn't plan on returning But look at it another way, if we can update the if wt, ok := src.(WriterTo); ok {
if n, err := wt.WriteTo(dst); n > 0 || err == nil || !errors.Is(err, errors.ErrUnsupported) {
return n, err
}
}
// Similarly, if the writer has a ReadFrom method, use it to do the copy.
if rt, ok := dst.(ReaderFrom); ok {
if n, err := rt.ReadFrom(src); n > 0 || err == nil || !errors.Is(err, errors.ErrUnsupported) {
return n, err
}
} then we will be able to avoid wasting the user-provided buffer via |
Change https://go.dev/cl/475575 mentions this issue: |
After refreshing my memory of |
After a second thought, I agree that Well, this is however not good news for this proposal, we still need an appropriate fallback from Another way to help this proposal is to add a new interface similar to |
Perhaps we could support a wrapper around |
You mean an exported struct wrapper of Something like this: package net
type UnixConnReaderFrom struct {
*UnixConn
}
func (c UnixConnReaderFrom) ReadFrom(r io.Reader) (n int64, err error) {
// do something with zero-copy...
return
}
func NewUnixConnReaderFrom(c Conn) (*UnixConnReaderFrom, error) {
uc, ok := c.(*UnixConn)
if !ok {
return nil, errors.New("must be a *net.UnixConn")
}
return &UnixConnReaderFrom{uc}, nil
}
package main
func main() {
c, _ := net.Dial("unix", "/tmp/sock")
uc, _ := net.NewUnixConnReaderFrom(c)
f, _ := os.Create("log")
io.Copy(uc, f)
} |
Yes, something like that. That may be too horrible, though. |
Pros and cons:
|
In order to avoid a recursive call to ReadFrom, we were converting a *File to an io.Writer. But all we really need to do is hide the ReadFrom method. In particular, this gives us the option of adding a WriteTo method. For #58808 Change-Id: I20d3a45749d528c93c23267c467e607fc17dc83f Reviewed-on: https://go-review.googlesource.com/c/go/+/475535 Reviewed-by: Bryan Mills <bcmills@google.com> Auto-Submit: Ian Lance Taylor <iant@google.com> Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Cherry Mui <cherryyz@google.com>
Since the 1.22 tree had opened and we didn't come to a final implementation of this proposal at the time, I'd like to pick up where we left off and continue to discuss it. Any new thoughts from the team? |
Kindly ping @rsc @ianlancetaylor |
What do you see as the current proposal? Thanks. |
Well, we've made several attempts at this proposal:
Therefore, I'd like to suggest adding a new interface (given that there is already a collision between How do you like this new idea? @ianlancetaylor |
Sorry, I'm not sure what I was thinking earlier. I don't think we want a new exported function I'm not yet seeing a reasonable way to do this. |
Change https://go.dev/cl/515595 mentions this issue: |
I'm going to have to look at it more, but it seems promising. Thanks. |
This comment was marked as resolved.
This comment was marked as resolved.
This proposal has been added to the active column of the proposals project |
Have all remaining concerns about this proposal been addressed? The API change is to define WriteTo methods on os.File and net.TCPConn. |
I believe there are no remaining concerns about this proposal now. |
Based on the discussion above, this proposal seems like a likely accept. The API change is to define WriteTo methods on os.File and net.TCPConn. |
No change in consensus, so accepted. 🎉 The API change is to define WriteTo methods on os.File and net.TCPConn. |
Change https://go.dev/cl/549197 mentions this issue: |
For #58808 Change-Id: Id73b9e4b5fb96426a01b76ce7a1053a6ad61a58e Reviewed-on: https://go-review.googlesource.com/c/go/+/549197 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Roland Shoemaker <roland@golang.org> Auto-Submit: Damien Neil <dneil@google.com>
Change https://go.dev/cl/549335 mentions this issue: |
…TCPConn to net.UnixConn For #58808 Change-Id: I9b27af30888aaaa9659387a32c57aaea136b1c3a Reviewed-on: https://go-review.googlesource.com/c/go/+/549335 Reviewed-by: Damien Neil <dneil@google.com> Reviewed-by: Michael Pratt <mpratt@google.com> Auto-Submit: Michael Pratt <mpratt@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
For golang#58808 Change-Id: Id73b9e4b5fb96426a01b76ce7a1053a6ad61a58e Reviewed-on: https://go-review.googlesource.com/c/go/+/549197 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Roland Shoemaker <roland@golang.org> Auto-Submit: Damien Neil <dneil@google.com>
…TCPConn to net.UnixConn For golang#58808 Change-Id: I9b27af30888aaaa9659387a32c57aaea136b1c3a Reviewed-on: https://go-review.googlesource.com/c/go/+/549335 Reviewed-by: Damien Neil <dneil@google.com> Reviewed-by: Michael Pratt <mpratt@google.com> Auto-Submit: Michael Pratt <mpratt@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Background
For the most commonly used stream-oriented/stream-like file descriptor types that can benefit the most from Linux zero-copy tech: TCP socket, Unix domain socket, and regular file, Go currently supports these cases of zero-copy:
from which the zero-copy supports whose destinations are Unix domain sockets are missing.
Since
io.Copy(dst Writer, src Reader)
leverages thesrc.(WriterTo).WriteTo
ordst.(ReaderFrom).ReadFrom
to try zero-copy for data transfer internally, andnet.UnixConn
has already implementednet.PacketConn
that hasWriteTo
andReadFrom
methods with different function signatures, which means there is no way for us to achieve the zero-copy by implementing these two methods fornet.UnixConn
, thus, the zero-copy caseunix-socket-to-unix-socket
is off the table.Proposal
As mentioned above,
unix-socket-to-unix-socket
is unlikely to accomplish, fortunately we can still support zero-copy oftcp-socket-to-unix-socket
andfile-to-unix-socket
, therefore, I propose supporting zero-copy with destinations of Unix sockets by implementingio.WriterTo
interface onos.File
andnet.TCPConn
.Once the implementation of this proposal is done, it will make the zero-copy technique support in Go more complete.
API changes
There will be one new method for
net.TCPConn
andos.File
:WriteTo(io.Writer)
.Benefit
Performance improvement
Benchmarks
The text was updated successfully, but these errors were encountered: