go/src/io
Jorropo 079a027d27 io: add WriterTo to MultiReader
This patch allows to zerocopy using MultiReader.
This is done by MultiReader implementing WriterTo.

Each sub reader is copied using usual io copy helper and thus use
WriterTo or ReadFrom with reflection.

There is a special case for when a subreader is a MultiReader.
Instead of using copyBuffer which would call multiReader.WriteTo,
multiReader.writeToWithBuffer is used instead, the difference
is that the temporary copy buffer is passed along, saving
allocations for nested MultiReaders.

The workflow looks like this:
- multiReader.WriteTo (allocates 32k buffer)
  - multiReader.writeToWithBuffer
    - for each subReader:
      - is instance of multiReader ?
        - yes, call multiReader.writeToWithBuffer
        - no, call copyBuffer(writer, currentReader, buffer)
          - does currentReader implements WriterTo ?
           - yes, use use currentReader.WriteTo
           - no, does writer implement ReadFrom ?
             - yes, use writer.ReadFrom
             - no, copy using Read / Write with buffer

This can be improved by lazy allocating the 32k buffer.
For example a MultiReader of such types:
  MultiReader(
    bytes.Reader, // WriterTo-able
    bytes.Reader, // WriterTo-able
    bytes.Reader, // WriterTo-able
  )

Doesn't need any allocation, all copy can be done using bytes.Reader's
internal data slice. However currently we still allocate a 32k buffer
for nothing.

This optimisation has been omitted for a future patch because of high
complexity costs for a non obvious performance cost (it needs a benchmark).
This patch at least is on par with the previous MultiReader.Read
workflow allocation wise.

Fixes #50842

Change-Id: Ib070c8f36337d9dd86090df8a703c5df97a773ae
GitHub-Last-Rev: 8ebe60ceac
GitHub-Pull-Request: golang/go#51502
Reviewed-on: https://go-review.googlesource.com/c/go/+/390215
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Trust: Daniel Martí <mvdan@mvdan.cc>
2022-03-07 23:22:26 +00:00
..
fs all: gofmt -w -r 'interface{} -> any' src 2021-12-13 18:45:54 +00:00
ioutil io/ioutil: use correct Go version in redirection comments 2021-03-19 01:02:56 +00:00
example_test.go io: add error check to TeeReader Example 2021-11-11 19:34:23 +00:00
export_test.go io: unexport ErrBadWriteCount 2020-10-16 17:52:59 +00:00
io.go all: gofmt -w -r 'interface{} -> any' src 2021-12-13 18:45:54 +00:00
io_test.go io: avoid integer overflow in NewSectionReader 2021-09-27 22:57:08 +00:00
multi.go io: add WriterTo to MultiReader 2022-03-07 23:22:26 +00:00
multi_test.go io: add WriterTo to MultiReader 2022-03-07 23:22:26 +00:00
pipe.go io: unexport internal methods 2021-08-19 09:11:02 +00:00
pipe_test.go io: add error check on pipe close functions to avoid error overwriting 2019-08-28 18:35:24 +00:00