buffer_pool.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. package buf
  2. import (
  3. "os"
  4. "runtime"
  5. "strconv"
  6. "sync"
  7. )
  8. // Pool provides functionality to generate and recycle buffers on demand.
  9. type Pool interface {
  10. // Allocate either returns a unused buffer from the pool, or generates a new one from system.
  11. Allocate() *Buffer
  12. // Free recycles the given buffer.
  13. Free(*Buffer)
  14. }
  15. // SyncPool is a buffer pool based on sync.Pool
  16. type SyncPool struct {
  17. allocator *sync.Pool
  18. }
  19. // NewSyncPool creates a SyncPool with given buffer size.
  20. func NewSyncPool(bufferSize uint32) *SyncPool {
  21. pool := &SyncPool{
  22. allocator: &sync.Pool{
  23. New: func() interface{} { return make([]byte, bufferSize) },
  24. },
  25. }
  26. return pool
  27. }
  28. // Allocate implements Pool.Allocate().
  29. func (p *SyncPool) Allocate() *Buffer {
  30. return &Buffer{
  31. v: p.allocator.Get().([]byte),
  32. pool: p,
  33. }
  34. }
  35. // Free implements Pool.Free().
  36. func (p *SyncPool) Free(buffer *Buffer) {
  37. if buffer.v != nil {
  38. p.allocator.Put(buffer.v)
  39. }
  40. }
  41. // BufferPool is a Pool that utilizes an internal cache.
  42. type BufferPool struct {
  43. chain chan []byte
  44. sub Pool
  45. }
  46. // NewBufferPool creates a new BufferPool with given buffer size, and internal cache size.
  47. func NewBufferPool(bufferSize, poolSize uint32) *BufferPool {
  48. pool := &BufferPool{
  49. chain: make(chan []byte, poolSize),
  50. sub: NewSyncPool(bufferSize),
  51. }
  52. for i := uint32(0); i < poolSize; i++ {
  53. pool.chain <- make([]byte, bufferSize)
  54. }
  55. return pool
  56. }
  57. // Allocate implements Pool.Allocate().
  58. func (p *BufferPool) Allocate() *Buffer {
  59. select {
  60. case b := <-p.chain:
  61. return &Buffer{
  62. v: b,
  63. pool: p,
  64. }
  65. default:
  66. return p.sub.Allocate()
  67. }
  68. }
  69. // Free implements Pool.Free().
  70. func (p *BufferPool) Free(buffer *Buffer) {
  71. if buffer.v == nil {
  72. return
  73. }
  74. select {
  75. case p.chain <- buffer.v:
  76. default:
  77. p.sub.Free(buffer)
  78. }
  79. }
  80. const (
  81. // Size of a regular buffer.
  82. Size = 2 * 1024
  83. poolSizeEnvKey = "v2ray.buffer.size"
  84. )
  85. var (
  86. mediumPool Pool
  87. )
  88. func getDefaultPoolSize() uint32 {
  89. switch runtime.GOARCH {
  90. case "amd64", "386":
  91. return 20
  92. default:
  93. return 5
  94. }
  95. }
  96. func init() {
  97. size := getDefaultPoolSize()
  98. sizeStr := os.Getenv(poolSizeEnvKey)
  99. if len(sizeStr) > 0 {
  100. customSize, err := strconv.ParseUint(sizeStr, 10, 32)
  101. if err == nil {
  102. size = uint32(customSize)
  103. }
  104. }
  105. if size > 0 {
  106. totalByteSize := size * 1024 * 1024
  107. mediumPool = NewBufferPool(Size, totalByteSize/Size)
  108. } else {
  109. mediumPool = NewSyncPool(Size)
  110. }
  111. }