status-go/vendor/github.com/syndtr/goleveldb/leveldb/util/buffer_pool.go

136 lines
2.6 KiB
Go

// Copyright (c) 2014, Suryandaru Triandana <syndtr@gmail.com>
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package util
import (
"fmt"
"sync"
"sync/atomic"
)
// BufferPool is a 'buffer pool'.
type BufferPool struct {
pool [6]sync.Pool
baseline [5]int
get uint32
put uint32
less uint32
equal uint32
greater uint32
miss uint32
}
func (p *BufferPool) poolNum(n int) int {
for i, x := range p.baseline {
if n <= x {
return i
}
}
return len(p.baseline)
}
// Get returns buffer with length of n.
func (p *BufferPool) Get(n int) []byte {
if p == nil {
return make([]byte, n)
}
atomic.AddUint32(&p.get, 1)
poolNum := p.poolNum(n)
b := p.pool[poolNum].Get().(*[]byte)
if cap(*b) == 0 {
// If we grabbed nothing, increment the miss stats.
atomic.AddUint32(&p.miss, 1)
if poolNum == len(p.baseline) {
*b = make([]byte, n)
return *b
}
*b = make([]byte, p.baseline[poolNum])
*b = (*b)[:n]
return *b
} else {
// If there is enough capacity in the bytes grabbed, resize the length
// to n and return.
if n < cap(*b) {
atomic.AddUint32(&p.less, 1)
*b = (*b)[:n]
return *b
} else if n == cap(*b) {
atomic.AddUint32(&p.equal, 1)
*b = (*b)[:n]
return *b
} else if n > cap(*b) {
atomic.AddUint32(&p.greater, 1)
}
}
if poolNum == len(p.baseline) {
*b = make([]byte, n)
return *b
}
*b = make([]byte, p.baseline[poolNum])
*b = (*b)[:n]
return *b
}
// Put adds given buffer to the pool.
func (p *BufferPool) Put(b []byte) {
if p == nil {
return
}
poolNum := p.poolNum(cap(b))
atomic.AddUint32(&p.put, 1)
p.pool[poolNum].Put(&b)
}
func (p *BufferPool) String() string {
if p == nil {
return "<nil>"
}
return fmt.Sprintf("BufferPool{B·%d G·%d P·%d <·%d =·%d >·%d M·%d}",
p.baseline, p.get, p.put, p.less, p.equal, p.greater, p.miss)
}
// NewBufferPool creates a new initialized 'buffer pool'.
func NewBufferPool(baseline int) *BufferPool {
if baseline <= 0 {
panic("baseline can't be <= 0")
}
bufPool := &BufferPool{
baseline: [...]int{baseline / 4, baseline / 2, baseline, baseline * 2, baseline * 4},
pool: [6]sync.Pool{
{
New: func() interface{} { return new([]byte) },
},
{
New: func() interface{} { return new([]byte) },
},
{
New: func() interface{} { return new([]byte) },
},
{
New: func() interface{} { return new([]byte) },
},
{
New: func() interface{} { return new([]byte) },
},
{
New: func() interface{} { return new([]byte) },
},
},
}
return bufPool
}