diff --git a/common/buf/multi_buffer.go b/common/buf/multi_buffer.go index b65a14713..57ccf6824 100644 --- a/common/buf/multi_buffer.go +++ b/common/buf/multi_buffer.go @@ -98,17 +98,24 @@ func ReadFrom(reader io.Reader) (MultiBuffer, error) { // It returns the new address of MultiBuffer leftover, and number of bytes written into the input byte slice. func SplitBytes(mb MultiBuffer, b []byte) (MultiBuffer, int) { totalBytes := 0 - - for len(mb) > 0 { - bb := mb[0] - nBytes, _ := bb.Read(b) + endIndex := -1 + for i := range mb { + pBuffer := mb[i] + nBytes, _ := pBuffer.Read(b) totalBytes += nBytes b = b[nBytes:] - if !bb.IsEmpty() { + if !pBuffer.IsEmpty() { + endIndex = i break } - bb.Release() - mb = mb[1:] + pBuffer.Release() + mb[i] = nil + } + + if endIndex == -1 { + mb = mb[:0] + } else { + mb = mb[endIndex:] } return mb, totalBytes diff --git a/common/buf/multi_buffer_test.go b/common/buf/multi_buffer_test.go index 8fd20d4d3..59b4edfb2 100644 --- a/common/buf/multi_buffer_test.go +++ b/common/buf/multi_buffer_test.go @@ -94,3 +94,16 @@ func TestMultiBufferSplitFirst(t *testing.T) { t.Error("expect empty buffer, but got ", mb.String()) } } + +func BenchmarkSplitBytes(b *testing.B) { + var mb MultiBuffer + raw := make([]byte, Size) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + buffer := StackNew() + buffer.Extend(Size) + mb = append(mb, &buffer) + mb, _ = SplitBytes(mb, raw) + } +} diff --git a/common/buf/readv_reader.go b/common/buf/readv_reader.go index ef10ead35..cf3bd49b3 100644 --- a/common/buf/readv_reader.go +++ b/common/buf/readv_reader.go @@ -48,6 +48,7 @@ type multiReader interface { Clear() } +// ReadVReader is a Reader that uses readv(2) syscall to read data. type ReadVReader struct { io.Reader rawConn syscall.RawConn @@ -55,6 +56,7 @@ type ReadVReader struct { alloc allocStrategy } +// NewReadVReader creates a new ReadVReader. func NewReadVReader(reader io.Reader, rawConn syscall.RawConn) *ReadVReader { return &ReadVReader{ Reader: reader,