-
-
Notifications
You must be signed in to change notification settings - Fork 464
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
pool pool buffer ppp buffer up
- Loading branch information
Showing
17 changed files
with
243 additions
and
96 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Package buffer provides a pool of []byte. | ||
package buffer | ||
|
||
import ( | ||
"github.com/xjasonlyu/tun2socks/v2/buffer/allocator" | ||
) | ||
|
||
const ( | ||
// MaxSegmentSize is the largest possible UDP datagram size. | ||
MaxSegmentSize = (1 << 16) - 1 | ||
|
||
// RelayBufferSize is a buffer of 20 KiB to reduce the memory | ||
// of each TCP relay as io.Copy default buffer size is 32 KiB, | ||
// but the maximum packet size of vmess/shadowsocks is about | ||
// 16 KiB, so define . | ||
RelayBufferSize = 20 << 10 | ||
) | ||
|
||
var _allocator = allocator.New() | ||
|
||
// Get gets a []byte from default allocator with most appropriate cap. | ||
func Get(size int) []byte { | ||
return _allocator.Get(size) | ||
} | ||
|
||
// Put returns a []byte to default allocator for future use. | ||
func Put(buf []byte) error { | ||
return _allocator.Put(buf) | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,38 @@ | ||
// Package pool provides a pool of []byte. | ||
// Package pool provides internal pool utilities. | ||
package pool | ||
|
||
const ( | ||
// MaxSegmentSize is the largest possible UDP datagram size. | ||
MaxSegmentSize = (1 << 16) - 1 | ||
|
||
// RelayBufferSize is a buffer of 20 KiB to reduce the memory | ||
// of each TCP relay as io.Copy default buffer size is 32 KiB, | ||
// but the maximum packet size of vmess/shadowsocks is about | ||
// 16 KiB, so define . | ||
RelayBufferSize = 20 << 10 | ||
import ( | ||
"sync" | ||
) | ||
|
||
// Get gets a []byte from default allocator with most appropriate cap. | ||
func Get(size int) []byte { | ||
return _allocator.Get(size) | ||
// A Pool is a generic wrapper around [sync.Pool] to provide strongly-typed | ||
// object pooling. | ||
// | ||
// Note that SA6002 (ref: https://staticcheck.io/docs/checks/#SA6002) will | ||
// not be detected, so all internal pool use must take care to only store | ||
// pointer types. | ||
type Pool[T any] struct { | ||
pool sync.Pool | ||
} | ||
|
||
// New returns a new [Pool] for T, and will use fn to construct new Ts when | ||
// the pool is empty. | ||
func New[T any](fn func() T) *Pool[T] { | ||
return &Pool[T]{ | ||
pool: sync.Pool{ | ||
New: func() any { | ||
return fn() | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
// Get gets a T from the pool, or creates a new one if the pool is empty. | ||
func (p *Pool[T]) Get() T { | ||
return p.pool.Get().(T) | ||
} | ||
|
||
// Put returns a []byte to default allocator for future use. | ||
func Put(buf []byte) error { | ||
return _allocator.Put(buf) | ||
// Put returns x into the pool. | ||
func (p *Pool[T]) Put(x T) { | ||
p.pool.Put(x) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package pool | ||
|
||
import ( | ||
"runtime/debug" | ||
"sync" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
type pooledValue[T any] struct { | ||
value T | ||
} | ||
|
||
func TestNew(t *testing.T) { | ||
// Disable GC to avoid the victim cache during the test. | ||
defer debug.SetGCPercent(debug.SetGCPercent(-1)) | ||
|
||
p := New(func() *pooledValue[string] { | ||
return &pooledValue[string]{ | ||
value: "new", | ||
} | ||
}) | ||
|
||
// Probabilistically, 75% of sync.Pool.Put calls will succeed when -race | ||
// is enabled (see ref below); attempt to make this quasi-deterministic by | ||
// brute force (i.e., put significantly more objects in the pool than we | ||
// will need for the test) in order to avoid testing without race enabled. | ||
// | ||
// ref: https://cs.opensource.google/go/go/+/refs/tags/go1.20.2:src/sync/pool.go;l=100-103 | ||
for i := 0; i < 1_000; i++ { | ||
p.Put(&pooledValue[string]{ | ||
value: t.Name(), | ||
}) | ||
} | ||
|
||
// Ensure that we always get the expected value. Note that this must only | ||
// run a fraction of the number of times that Put is called above. | ||
for i := 0; i < 10; i++ { | ||
func() { | ||
x := p.Get() | ||
defer p.Put(x) | ||
require.Equal(t, t.Name(), x.value) | ||
}() | ||
} | ||
|
||
// Depool all objects that might be in the pool to ensure that it's empty. | ||
for i := 0; i < 1_000; i++ { | ||
p.Get() | ||
} | ||
|
||
// Now that the pool is empty, it should use the value specified in the | ||
// underlying sync.Pool.New func. | ||
require.Equal(t, "new", p.Get().value) | ||
} | ||
|
||
func TestNew_Race(t *testing.T) { | ||
p := New(func() *pooledValue[int] { | ||
return &pooledValue[int]{ | ||
value: -1, | ||
} | ||
}) | ||
|
||
var wg sync.WaitGroup | ||
defer wg.Wait() | ||
|
||
// Run a number of goroutines that read and write pool object fields to | ||
// tease out races. | ||
for i := 0; i < 1_000; i++ { | ||
i := i | ||
|
||
wg.Add(1) | ||
go func() { | ||
defer wg.Done() | ||
|
||
x := p.Get() | ||
defer p.Put(x) | ||
|
||
// Must both read and write the field. | ||
if n := x.value; n >= -1 { | ||
x.value = i | ||
} | ||
}() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package bufferpool | ||
|
||
import ( | ||
"bytes" | ||
|
||
"github.com/xjasonlyu/tun2socks/v2/internal/pool" | ||
) | ||
|
||
const _size = 1024 // by default, create 1 KiB buffers | ||
|
||
var _pool = pool.New(func() *bytes.Buffer { | ||
buf := &bytes.Buffer{} | ||
buf.Grow(_size) | ||
return buf | ||
}) | ||
|
||
func Get() *bytes.Buffer { | ||
buf := _pool.Get() | ||
buf.Reset() | ||
return buf | ||
} | ||
|
||
func Put(b *bytes.Buffer) { | ||
_pool.Put(b) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.