diff options
Diffstat (limited to 'go/util/bytes_pool.go')
| -rw-r--r-- | go/util/bytes_pool.go | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/go/util/bytes_pool.go b/go/util/bytes_pool.go new file mode 100644 index 000000000..58ed6feca --- /dev/null +++ b/go/util/bytes_pool.go @@ -0,0 +1,127 @@ +package util + +import ( + "bytes" + "fmt" + "sync" + "sync/atomic" + "time" +) + +var ( + ChunkSizes = []int{ + 1 << 4, // index 0, 16 bytes, inclusive + 1 << 6, // index 1, 64 bytes + 1 << 8, // index 2, 256 bytes + 1 << 10, // index 3, 1K bytes + 1 << 12, // index 4, 4K bytes + 1 << 14, // index 5, 16K bytes + 1 << 16, // index 6, 64K bytes + 1 << 18, // index 7, 256K bytes + 1 << 20, // index 8, 1M bytes + 1 << 22, // index 9, 4M bytes + 1 << 24, // index 10, 16M bytes + 1 << 26, // index 11, 64M bytes + 1 << 28, // index 12, 128M bytes + } + + _DEBUG = false +) + +type BytesPool struct { + chunkPools []*byteChunkPool +} + +func NewBytesPool() *BytesPool { + var bp BytesPool + for _, size := range ChunkSizes { + bp.chunkPools = append(bp.chunkPools, newByteChunkPool(size)) + } + ret := &bp + if _DEBUG { + t := time.NewTicker(10 * time.Second) + go func() { + for { + println("buffer:", ret.String()) + <-t.C + } + }() + } + return ret +} + +func (m *BytesPool) String() string { + var buf bytes.Buffer + for index, size := range ChunkSizes { + if m.chunkPools[index].count > 0 { + buf.WriteString(fmt.Sprintf("size:%d count:%d\n", size, m.chunkPools[index].count)) + } + } + return buf.String() +} + +func findChunkPoolIndex(size int) int { + if size <= 0 { + return -1 + } + size = (size - 1) >> 4 + ret := 0 + for size > 0 { + size = size >> 2 + ret = ret + 1 + } + if ret >= len(ChunkSizes) { + return -1 + } + return ret +} + +func (m *BytesPool) Get(size int) []byte { + index := findChunkPoolIndex(size) + // println("get index:", index) + if index < 0 { + return make([]byte, size) + } + return m.chunkPools[index].Get() +} + +func (m *BytesPool) Put(b []byte) { + index := findChunkPoolIndex(len(b)) + // println("put index:", index) + if index < 0 { + return + } + m.chunkPools[index].Put(b) +} + +// a pool of fix-sized []byte chunks. The pool size is managed by Go GC +type byteChunkPool struct { + sync.Pool + chunkSizeLimit int + count int64 +} + +var count int + +func newByteChunkPool(chunkSizeLimit int) *byteChunkPool { + var m byteChunkPool + m.chunkSizeLimit = chunkSizeLimit + m.Pool.New = func() interface{} { + count++ + // println("creating []byte size", m.chunkSizeLimit, "new", count, "count", m.count) + return make([]byte, m.chunkSizeLimit) + } + return &m +} + +func (m *byteChunkPool) Get() []byte { + // println("before get size:", m.chunkSizeLimit, "count:", m.count) + atomic.AddInt64(&m.count, 1) + return m.Pool.Get().([]byte) +} + +func (m *byteChunkPool) Put(b []byte) { + atomic.AddInt64(&m.count, -1) + // println("after put get size:", m.chunkSizeLimit, "count:", m.count) + m.Pool.Put(b) +} |
