mirror of https://github.com/v2ray/v2ray-core
use readv reader by default
parent
9ad1e034e0
commit
8c841a05fb
|
@ -59,7 +59,20 @@ func NewReader(reader io.Reader) Reader {
|
||||||
return mr
|
return mr
|
||||||
}
|
}
|
||||||
|
|
||||||
return newReaderPlatform(reader)
|
if useReadv {
|
||||||
|
if sc, ok := reader.(syscall.Conn); ok {
|
||||||
|
rawConn, err := sc.SyscallConn()
|
||||||
|
if err != nil {
|
||||||
|
newError("failed to get sysconn").Base(err).WriteToLog()
|
||||||
|
} else {
|
||||||
|
return NewReadVReader(reader, rawConn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &SingleReader{
|
||||||
|
Reader: reader,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWriter creates a new Writer.
|
// NewWriter creates a new Writer.
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
// +build 386 amd64 s390 s390x
|
|
||||||
|
|
||||||
package buf
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
func newReaderPlatform(reader io.Reader) Reader {
|
|
||||||
if useReadv {
|
|
||||||
if sc, ok := reader.(syscall.Conn); ok {
|
|
||||||
rawConn, err := sc.SyscallConn()
|
|
||||||
if err != nil {
|
|
||||||
newError("failed to get sysconn").Base(err).WriteToLog()
|
|
||||||
} else {
|
|
||||||
return NewReadVReader(reader, rawConn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewBytesToBufferReader(reader)
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
// +build mips mipsle mips64 mips64le arm arm64
|
|
||||||
|
|
||||||
package buf
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
func newReaderPlatform(reader io.Reader) Reader {
|
|
||||||
return &SingleReader{
|
|
||||||
Reader: reader,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"v2ray.com/core/common"
|
"v2ray.com/core/common"
|
||||||
"v2ray.com/core/common/bytespool"
|
|
||||||
"v2ray.com/core/common/errors"
|
"v2ray.com/core/common/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -24,66 +23,6 @@ func readOne(r io.Reader) (*Buffer, error) {
|
||||||
return nil, newError("Reader returns too many empty payloads.")
|
return nil, newError("Reader returns too many empty payloads.")
|
||||||
}
|
}
|
||||||
|
|
||||||
const largeSize = 128 * 1024
|
|
||||||
|
|
||||||
// BytesToBufferReader is a Reader that adjusts its reading speed automatically.
|
|
||||||
type BytesToBufferReader struct {
|
|
||||||
io.Reader
|
|
||||||
buffer []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBytesToBufferReader returns a new BytesToBufferReader.
|
|
||||||
func NewBytesToBufferReader(reader io.Reader) Reader {
|
|
||||||
return &BytesToBufferReader{
|
|
||||||
Reader: reader,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *BytesToBufferReader) readSmall() (MultiBuffer, error) {
|
|
||||||
b, err := readOne(r.Reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if b.IsFull() && largeSize > Size {
|
|
||||||
r.buffer = bytespool.Alloc(Size + 100)
|
|
||||||
}
|
|
||||||
return NewMultiBufferValue(b), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *BytesToBufferReader) freeBuffer() {
|
|
||||||
bytespool.Free(r.buffer)
|
|
||||||
r.buffer = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadMultiBuffer implements Reader.
|
|
||||||
func (r *BytesToBufferReader) ReadMultiBuffer() (MultiBuffer, error) {
|
|
||||||
if r.buffer == nil || largeSize == Size {
|
|
||||||
return r.readSmall()
|
|
||||||
}
|
|
||||||
|
|
||||||
nBytes, err := r.Reader.Read(r.buffer)
|
|
||||||
if nBytes > 0 {
|
|
||||||
mb := NewMultiBufferCap(int32(nBytes/Size) + 1)
|
|
||||||
common.Must2(mb.Write(r.buffer[:nBytes]))
|
|
||||||
if nBytes == len(r.buffer) && nBytes < int(largeSize) {
|
|
||||||
bytespool.Free(r.buffer)
|
|
||||||
r.buffer = bytespool.Alloc(int32(nBytes) + 100)
|
|
||||||
} else if nBytes < Size {
|
|
||||||
r.freeBuffer()
|
|
||||||
}
|
|
||||||
return mb, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
r.freeBuffer()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read() returns empty payload and nil err. We don't expect this to happen, but just in case.
|
|
||||||
return r.readSmall()
|
|
||||||
}
|
|
||||||
|
|
||||||
// BufferedReader is a Reader that keeps its internal buffer.
|
// BufferedReader is a Reader that keeps its internal buffer.
|
||||||
type BufferedReader struct {
|
type BufferedReader struct {
|
||||||
// Reader is the underlying reader to be read from
|
// Reader is the underlying reader to be read from
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
package buf_test
|
package buf_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"io"
|
"io"
|
||||||
"runtime"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
. "v2ray.com/core/common/buf"
|
. "v2ray.com/core/common/buf"
|
||||||
|
@ -11,32 +9,6 @@ import (
|
||||||
. "v2ray.com/ext/assert"
|
. "v2ray.com/ext/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAdaptiveReader(t *testing.T) {
|
|
||||||
if runtime.GOARCH != "amd64" {
|
|
||||||
t.Skip("Smart reader only works on highend devices.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
assert := With(t)
|
|
||||||
|
|
||||||
reader := NewReader(bytes.NewReader(make([]byte, 1024*1024)))
|
|
||||||
b, err := reader.ReadMultiBuffer()
|
|
||||||
assert(err, IsNil)
|
|
||||||
assert(b.Len(), Equals, int32(Size))
|
|
||||||
|
|
||||||
b, err = reader.ReadMultiBuffer()
|
|
||||||
assert(err, IsNil)
|
|
||||||
assert(b.Len(), Equals, int32(8*1024))
|
|
||||||
|
|
||||||
b, err = reader.ReadMultiBuffer()
|
|
||||||
assert(err, IsNil)
|
|
||||||
assert(b.Len(), Equals, int32(32*1024))
|
|
||||||
|
|
||||||
b, err = reader.ReadMultiBuffer()
|
|
||||||
assert(err, IsNil)
|
|
||||||
assert(b.Len(), Equals, int32(128*1024))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBytesReaderWriteTo(t *testing.T) {
|
func TestBytesReaderWriteTo(t *testing.T) {
|
||||||
assert := With(t)
|
assert := With(t)
|
||||||
|
|
||||||
|
@ -87,8 +59,8 @@ func TestBytesReaderMultiBuffer(t *testing.T) {
|
||||||
func TestReaderInterface(t *testing.T) {
|
func TestReaderInterface(t *testing.T) {
|
||||||
assert := With(t)
|
assert := With(t)
|
||||||
|
|
||||||
assert((*BytesToBufferReader)(nil), Implements, (*io.Reader)(nil))
|
assert((*ReadVReader)(nil), Implements, (*io.Reader)(nil))
|
||||||
assert((*BytesToBufferReader)(nil), Implements, (*Reader)(nil))
|
assert((*ReadVReader)(nil), Implements, (*Reader)(nil))
|
||||||
|
|
||||||
assert((*BufferedReader)(nil), Implements, (*Reader)(nil))
|
assert((*BufferedReader)(nil), Implements, (*Reader)(nil))
|
||||||
assert((*BufferedReader)(nil), Implements, (*io.Reader)(nil))
|
assert((*BufferedReader)(nil), Implements, (*io.Reader)(nil))
|
||||||
|
|
|
@ -140,7 +140,12 @@ var useReadv = false
|
||||||
func init() {
|
func init() {
|
||||||
const defaultFlagValue = "NOT_DEFINED_AT_ALL"
|
const defaultFlagValue = "NOT_DEFINED_AT_ALL"
|
||||||
value := platform.NewEnvFlag("v2ray.buf.readv").GetValue(func() string { return defaultFlagValue })
|
value := platform.NewEnvFlag("v2ray.buf.readv").GetValue(func() string { return defaultFlagValue })
|
||||||
if value != defaultFlagValue && (runtime.GOOS == "linux" || runtime.GOOS == "darwin") {
|
switch value {
|
||||||
|
case defaultFlagValue, "auto":
|
||||||
|
if (runtime.GOARCH == "386" || runtime.GOARCH == "amd64" || runtime.GOARCH == "s390x") && (runtime.GOOS == "linux" || runtime.GOOS == "darwin") {
|
||||||
|
useReadv = true
|
||||||
|
}
|
||||||
|
case "enable":
|
||||||
useReadv = true
|
useReadv = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue