Skip to content

proposal: bufio: add a new method "Handover" for Writer and Reader #46758

@panjf2000

Description

@panjf2000

What version of Go are you using (go version)?

$ go version
go version go1.16.5 linux/amd64

Does this issue reproduce with the latest release?

Yes.

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN="/data/go/bin"
GOCACHE="/root/.cache/go-build"
GOENV="/root/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/data/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/data/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/snap/go/7736"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/snap/go/7736/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.16.5"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build1082148225=/tmp/go-build -gno-record-gcc-switches"

What did you do?

bufio.Writer:

type Writer struct {
	err error
	buf []byte
	n   int
	wr  io.Writer
}

I set up a net.Conn c as the underlying io.Writer wr of bufio.Writer bw and replaced bw.wr with a bytes.Buffer bb (by calling bufio.Reset(bb)) when the TCP socket disconnected caused by any network problem, so other goroutines can continue calling bufio.Write()/Flush() to write/flush data into the local buffer bb (bw.wr), not knowing the network problem, I will create a new net.Conn and replace bw.wr with it, then copy all data in bb to bw.buf once the TCP socket resumes.

Because the bw was shared by multiple goroutines (goroutine-safe along with mutex), some of goroutines might have called bufio.Write() writing data into the bw.buf before bufio.Reset(bb) was called, which means those data will be lost, when I reconnected to the remote server, I want to send all buffered data (including data was in bw.buf before bufio.Reset(bb) was called) to the remote server.

What did you expect to see?

All buffered data was sent to the remote server after a reconnection.

What did you see instead?

I lost some data by calling bufio.Reset(bb).

So I propose to add a new method "Handover" for Writer and Reader, Handover is the same as Reset, except it retains all unflushed buffered data and migrates them to the new underlying io.Writer.

It would be something like this:

func (b *Writer) Handover(w io.Writer) error {
	if err := b.err; err != nil || b.n == 0 {
		b.Reset(w)
		return err
	}
	b.wr = w
	b.err = b.Flush()
	return b.err
}

func (b *Reader) Handover(r io.Reader) error {
	n := b.Buffered()
	if err := b.err; err != nil || n == 0 {
		b.Reset(r)
		return err
	}
	b.rd = r
	b.err = nil
	return nil
}

I can call bw.Handover(bb) to retain all unflushed buffered data and flush it to bytes.Buffer bb instead of calling bw.Reset(bb) to discard all unflushed buffered data in bw.buf.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions