1 // Copyright (c) 2014, Suryandaru Triandana <syndtr@gmail.com>
2 // All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
21 // BufferPool is a 'buffer pool'.
22 type BufferPool struct {
43 func (p *BufferPool) poolNum(n int) int {
44 if n <= p.baseline0 && n > p.baseline0/2 {
47 for i, x := range p.baseline {
52 return len(p.baseline) + 1
55 // Get returns buffer with length of n.
56 func (p *BufferPool) Get(n int) []byte {
58 return make([]byte, n)
65 return make([]byte, n)
68 atomic.AddUint32(&p.get, 1)
70 poolNum := p.poolNum(n)
71 pool := p.pool[poolNum]
79 atomic.AddUint32(&p.half, 1)
84 return make([]byte, n)
86 atomic.AddUint32(&p.less, 1)
90 atomic.AddUint32(&p.equal, 1)
93 atomic.AddUint32(&p.greater, 1)
96 atomic.AddUint32(&p.miss, 1)
99 return make([]byte, n, p.baseline0)
101 sizePtr := &p.size[poolNum-1]
108 atomic.AddUint32(&p.half, 1)
109 sizeHalfPtr := &p.sizeHalf[poolNum-1]
110 if atomic.AddUint32(sizeHalfPtr, 1) == 20 {
111 atomic.StoreUint32(sizePtr, uint32(cap(b)/2))
112 atomic.StoreUint32(sizeHalfPtr, 0)
119 return make([]byte, n)
121 atomic.AddUint32(&p.less, 1)
125 atomic.AddUint32(&p.equal, 1)
128 atomic.AddUint32(&p.greater, 1)
129 if uint32(cap(b)) >= atomic.LoadUint32(sizePtr) {
137 atomic.AddUint32(&p.miss, 1)
140 if size := atomic.LoadUint32(sizePtr); uint32(n) > size {
142 atomic.CompareAndSwapUint32(sizePtr, 0, uint32(n))
144 sizeMissPtr := &p.sizeMiss[poolNum-1]
145 if atomic.AddUint32(sizeMissPtr, 1) == 20 {
146 atomic.StoreUint32(sizePtr, uint32(n))
147 atomic.StoreUint32(sizeMissPtr, 0)
150 return make([]byte, n)
152 return make([]byte, n, size)
157 // Put adds given buffer to the pool.
158 func (p *BufferPool) Put(b []byte) {
170 atomic.AddUint32(&p.put, 1)
172 pool := p.pool[p.poolNum(cap(b))]
180 func (p *BufferPool) Close() {
188 p.closeC <- struct{}{}
193 func (p *BufferPool) String() string {
198 return fmt.Sprintf("BufferPool{B·%d Z·%v Zm·%v Zh·%v G·%d P·%d H·%d <·%d =·%d >·%d M·%d}",
199 p.baseline0, p.size, p.sizeMiss, p.sizeHalf, p.get, p.put, p.half, p.less, p.equal, p.greater, p.miss)
202 func (p *BufferPool) drain() {
203 ticker := time.NewTicker(2 * time.Second)
208 for _, ch := range p.pool {
216 for _, ch := range p.pool {
224 // NewBufferPool creates a new initialized 'buffer pool'.
225 func NewBufferPool(baseline int) *BufferPool {
227 panic("baseline can't be <= 0")
231 baseline: [...]int{baseline / 4, baseline / 2, baseline * 2, baseline * 4},
232 closeC: make(chan struct{}, 1),
234 for i, cap := range []int{2, 2, 4, 4, 2, 1} {
235 p.pool[i] = make(chan []byte, cap)