buffer_pool.go 2.5 KB

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