diff --git a/common/buf/copy.go b/common/buf/copy.go index 1d301b168..8f0429e53 100644 --- a/common/buf/copy.go +++ b/common/buf/copy.go @@ -3,6 +3,7 @@ package buf import ( "io" "time" + "unsafe" "v2ray.com/core/common/errors" "v2ray.com/core/common/signal" @@ -11,6 +12,7 @@ import ( type errorHandler func(error) error type dataHandler func(MultiBuffer) +//go:notinheap type copyHandler struct { onReadError []errorHandler onData []dataHandler @@ -119,10 +121,13 @@ func copyInternal(reader Reader, writer Writer, handler *copyHandler) error { // Copy dumps all payload from reader to writer or stops when an error occurs. It returns nil when EOF. func Copy(reader Reader, writer Writer, options ...CopyOption) error { var handler copyHandler + p := uintptr(unsafe.Pointer(&handler)) + h := (*copyHandler)(unsafe.Pointer(p)) + for _, option := range options { - option(&handler) + option(h) } - err := copyInternal(reader, writer, &handler) + err := copyInternal(reader, writer, h) if err != nil && errors.Cause(err) != io.EOF { return err } diff --git a/common/buf/copy_test.go b/common/buf/copy_test.go index 0467b231b..6ee700c82 100644 --- a/common/buf/copy_test.go +++ b/common/buf/copy_test.go @@ -1,7 +1,8 @@ package buf_test import ( - "crypto/rand" + "io" + "math/rand" "testing" "github.com/golang/mock/gomock" @@ -39,7 +40,7 @@ func TestWriteError(t *testing.T) { mockWriter := mocks.NewWriter(mockCtl) mockWriter.EXPECT().Write(gomock.Any()).Return(0, errors.New("error")) - err := buf.Copy(buf.NewReader(rand.Reader), buf.NewWriter(mockWriter)) + err := buf.Copy(buf.NewReader(rand.New(rand.NewSource(0))), buf.NewWriter(mockWriter)) if err == nil { t.Fatal("expected error, but nil") } @@ -52,3 +53,13 @@ func TestWriteError(t *testing.T) { t.Fatal("unexpected error message: ", err.Error()) } } + +func BenchmarkCopy(b *testing.B) { + reader := buf.NewReader(io.LimitReader(rand.New(rand.NewSource(0)), 1024*10)) + writer := buf.Discard + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = buf.Copy(reader, writer) + } +}