You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

127 lines
2.5 KiB

  1. package util
  2. import (
  3. "bytes"
  4. "fmt"
  5. "sync"
  6. "sync/atomic"
  7. "time"
  8. )
  9. var (
  10. ChunkSizes = []int{
  11. 1 << 4, // index 0, 16 bytes, inclusive
  12. 1 << 6, // index 1, 64 bytes
  13. 1 << 8, // index 2, 256 bytes
  14. 1 << 10, // index 3, 1K bytes
  15. 1 << 12, // index 4, 4K bytes
  16. 1 << 14, // index 5, 16K bytes
  17. 1 << 16, // index 6, 64K bytes
  18. 1 << 18, // index 7, 256K bytes
  19. 1 << 20, // index 8, 1M bytes
  20. 1 << 22, // index 9, 4M bytes
  21. 1 << 24, // index 10, 16M bytes
  22. 1 << 26, // index 11, 64M bytes
  23. 1 << 28, // index 12, 128M bytes
  24. }
  25. _DEBUG = false
  26. )
  27. type BytesPool struct {
  28. chunkPools []*byteChunkPool
  29. }
  30. func NewBytesPool() *BytesPool {
  31. var bp BytesPool
  32. for _, size := range ChunkSizes {
  33. bp.chunkPools = append(bp.chunkPools, newByteChunkPool(size))
  34. }
  35. ret := &bp
  36. if _DEBUG {
  37. t := time.NewTicker(10 * time.Second)
  38. go func() {
  39. for {
  40. println("buffer:", ret.String())
  41. <-t.C
  42. }
  43. }()
  44. }
  45. return ret
  46. }
  47. func (m *BytesPool) String() string {
  48. var buf bytes.Buffer
  49. for index, size := range ChunkSizes {
  50. if m.chunkPools[index].count > 0 {
  51. buf.WriteString(fmt.Sprintf("size:%d count:%d\n", size, m.chunkPools[index].count))
  52. }
  53. }
  54. return buf.String()
  55. }
  56. func findChunkPoolIndex(size int) int {
  57. if size <= 0 {
  58. return -1
  59. }
  60. size = (size - 1) >> 4
  61. ret := 0
  62. for size > 0 {
  63. size = size >> 2
  64. ret = ret + 1
  65. }
  66. if ret >= len(ChunkSizes) {
  67. return -1
  68. }
  69. return ret
  70. }
  71. func (m *BytesPool) Get(size int) []byte {
  72. index := findChunkPoolIndex(size)
  73. // println("get index:", index)
  74. if index < 0 {
  75. return make([]byte, size)
  76. }
  77. return m.chunkPools[index].Get()
  78. }
  79. func (m *BytesPool) Put(b []byte) {
  80. index := findChunkPoolIndex(len(b))
  81. // println("put index:", index)
  82. if index < 0 {
  83. return
  84. }
  85. m.chunkPools[index].Put(b)
  86. }
  87. // a pool of fix-sized []byte chunks. The pool size is managed by Go GC
  88. type byteChunkPool struct {
  89. sync.Pool
  90. chunkSizeLimit int
  91. count int64
  92. }
  93. var count int
  94. func newByteChunkPool(chunkSizeLimit int) *byteChunkPool {
  95. var m byteChunkPool
  96. m.chunkSizeLimit = chunkSizeLimit
  97. m.Pool.New = func() interface{} {
  98. count++
  99. // println("creating []byte size", m.chunkSizeLimit, "new", count, "count", m.count)
  100. return make([]byte, m.chunkSizeLimit)
  101. }
  102. return &m
  103. }
  104. func (m *byteChunkPool) Get() []byte {
  105. // println("before get size:", m.chunkSizeLimit, "count:", m.count)
  106. atomic.AddInt64(&m.count, 1)
  107. return m.Pool.Get().([]byte)
  108. }
  109. func (m *byteChunkPool) Put(b []byte) {
  110. atomic.AddInt64(&m.count, -1)
  111. // println("after put get size:", m.chunkSizeLimit, "count:", m.count)
  112. m.Pool.Put(b)
  113. }