buffer_pool.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. package buf
  2. import (
  3. "runtime"
  4. "sync"
  5. "v2ray.com/core/common/platform"
  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. if buffer.v != nil {
  37. p.allocator.Put(buffer.v)
  38. }
  39. }
  40. // BufferPool is a Pool that utilizes an internal cache.
  41. type BufferPool struct {
  42. chain chan []byte
  43. sub Pool
  44. }
  45. // NewBufferPool creates a new BufferPool with given buffer size, and internal cache size.
  46. func NewBufferPool(bufferSize, poolSize uint32) *BufferPool {
  47. pool := &BufferPool{
  48. chain: make(chan []byte, poolSize),
  49. sub: NewSyncPool(bufferSize),
  50. }
  51. for i := uint32(0); i < poolSize; i++ {
  52. pool.chain <- make([]byte, bufferSize)
  53. }
  54. return pool
  55. }
  56. // Allocate implements Pool.Allocate().
  57. func (p *BufferPool) Allocate() *Buffer {
  58. select {
  59. case b := <-p.chain:
  60. return &Buffer{
  61. v: b,
  62. pool: p,
  63. }
  64. default:
  65. return p.sub.Allocate()
  66. }
  67. }
  68. // Free implements Pool.Free().
  69. func (p *BufferPool) Free(buffer *Buffer) {
  70. if buffer.v == nil {
  71. return
  72. }
  73. select {
  74. case p.chain <- buffer.v:
  75. default:
  76. p.sub.Free(buffer)
  77. }
  78. }
  79. const (
  80. // Size of a regular buffer.
  81. Size = 2 * 1024
  82. poolSizeEnvKey = "v2ray.buffer.size"
  83. )
  84. var (
  85. mediumPool Pool
  86. )
  87. func getDefaultPoolSize() int {
  88. switch runtime.GOARCH {
  89. case "amd64", "386":
  90. return 20
  91. default:
  92. return 5
  93. }
  94. }
  95. func init() {
  96. f := platform.EnvFlag{
  97. Name: poolSizeEnvKey,
  98. AltName: platform.NormalizeEnvName(poolSizeEnvKey),
  99. }
  100. size := f.GetValueAsInt(getDefaultPoolSize())
  101. if size > 0 {
  102. totalByteSize := uint32(size) * 1024 * 1024
  103. mediumPool = NewBufferPool(Size, totalByteSize/Size)
  104. } else {
  105. mediumPool = NewSyncPool(Size)
  106. }
  107. }