mirror of https://github.com/v2ray/v2ray-core
improve performance on copy
parent
4de776265b
commit
9bc6a5813e
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue