buffer_pool.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  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. rawBuffer := buffer.v
  38. if rawBuffer == nil {
  39. return
  40. }
  41. p.allocator.Put(rawBuffer)
  42. }
  43. // BufferPool is a Pool that utilizes an internal cache.
  44. type BufferPool struct {
  45. chain chan []byte
  46. allocator *sync.Pool
  47. }
  48. // NewBufferPool creates a new BufferPool with given buffer size, and internal cache size.
  49. func NewBufferPool(bufferSize, poolSize uint32) *BufferPool {
  50. pool := &BufferPool{
  51. chain: make(chan []byte, poolSize),
  52. allocator: &sync.Pool{
  53. New: func() interface{} { return make([]byte, bufferSize) },
  54. },
  55. }
  56. for i := uint32(0); i < poolSize; i++ {
  57. pool.chain <- make([]byte, bufferSize)
  58. }
  59. return pool
  60. }
  61. // Allocate implements Pool.Allocate().
  62. func (p *BufferPool) Allocate() *Buffer {
  63. var b []byte
  64. select {
  65. case b = <-p.chain:
  66. default:
  67. b = p.allocator.Get().([]byte)
  68. }
  69. return &Buffer{
  70. v: b,
  71. pool: p,
  72. }
  73. }
  74. // Free implements Pool.Free().
  75. func (p *BufferPool) Free(buffer *Buffer) {
  76. rawBuffer := buffer.v
  77. if rawBuffer == nil {
  78. return
  79. }
  80. select {
  81. case p.chain <- rawBuffer:
  82. default:
  83. p.allocator.Put(rawBuffer)
  84. }
  85. }
  86. const (
  87. // Size of a regular buffer.
  88. Size = 2 * 1024
  89. poolSizeEnvKey = "v2ray.buffer.size"
  90. )
  91. var (
  92. mediumPool Pool
  93. )
  94. func getDefaultPoolSize() uint32 {
  95. switch runtime.GOARCH {
  96. case "amd64", "386":
  97. return 20
  98. default:
  99. return 5
  100. }
  101. }
  102. func init() {
  103. size := getDefaultPoolSize()
  104. sizeStr := os.Getenv(poolSizeEnvKey)
  105. if len(sizeStr) > 0 {
  106. customSize, err := strconv.ParseUint(sizeStr, 10, 32)
  107. if err == nil {
  108. size = uint32(customSize)
  109. }
  110. }
  111. if size > 0 {
  112. totalByteSize := size * 1024 * 1024
  113. mediumPool = NewBufferPool(Size, totalByteSize/Size)
  114. } else {
  115. mediumPool = NewSyncPool(Size)
  116. }
  117. }