improve performance on copy

pull/1435/head
Darien Raymond 2018-11-15 19:44:24 +01:00
parent 4de776265b
commit 9bc6a5813e
No known key found for this signature in database
GPG Key ID: 7251FFA14BB18169
2 changed files with 20 additions and 4 deletions

View File

@ -3,6 +3,7 @@ package buf
import ( import (
"io" "io"
"time" "time"
"unsafe"
"v2ray.com/core/common/errors" "v2ray.com/core/common/errors"
"v2ray.com/core/common/signal" "v2ray.com/core/common/signal"
@ -11,6 +12,7 @@ import (
type errorHandler func(error) error type errorHandler func(error) error
type dataHandler func(MultiBuffer) type dataHandler func(MultiBuffer)
//go:notinheap
type copyHandler struct { type copyHandler struct {
onReadError []errorHandler onReadError []errorHandler
onData []dataHandler 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. // 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 { func Copy(reader Reader, writer Writer, options ...CopyOption) error {
var handler copyHandler var handler copyHandler
p := uintptr(unsafe.Pointer(&handler))
h := (*copyHandler)(unsafe.Pointer(p))
for _, option := range options { 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 { if err != nil && errors.Cause(err) != io.EOF {
return err return err
} }

View File

@ -1,7 +1,8 @@
package buf_test package buf_test
import ( import (
"crypto/rand" "io"
"math/rand"
"testing" "testing"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
@ -39,7 +40,7 @@ func TestWriteError(t *testing.T) {
mockWriter := mocks.NewWriter(mockCtl) mockWriter := mocks.NewWriter(mockCtl)
mockWriter.EXPECT().Write(gomock.Any()).Return(0, errors.New("error")) 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 { if err == nil {
t.Fatal("expected error, but nil") t.Fatal("expected error, but nil")
} }
@ -52,3 +53,13 @@ func TestWriteError(t *testing.T) {
t.Fatal("unexpected error message: ", err.Error()) 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)
}
}