openvpn-mgt/vendor/github.com/pyke369/golang-support/bslab/bslab.go

90 lines
1.7 KiB
Go

package bslab
import "sync/atomic"
type slab struct {
queue chan []byte
get, put, alloc, lost int64
}
var (
slabs = map[int]*slab{}
)
func init() {
slabs[0] = &slab{}
for size := uint(9); size <= 26; size++ {
slabs[1<<size] = &slab{queue: make(chan []byte, 1024)}
}
}
func Stats() (info map[int][5]int64) {
info = map[int][5]int64{}
for size, slab := range slabs {
info[size] = [5]int64{slab.get, slab.put, slab.alloc, slab.lost, int64(len(slab.queue))}
}
return info
}
func Get(size int, item []byte) []byte {
if size <= 0 {
return nil
}
if item != nil {
if cap(item) >= size {
return item[:0]
}
Put(item)
}
bits, power := uint(0), uint(0)
if size&(size-1) == 0 {
power = 1
}
for size != 0 {
size >>= 1
bits++
}
size = 1 << (bits - power)
if slab, ok := slabs[size]; ok {
atomic.AddInt64(&(slab.get), 1)
select {
case item := <-slab.queue:
return item[:0]
default:
atomic.AddInt64(&(slab.alloc), 1)
return make([]byte, 0, size)
}
}
atomic.AddInt64(&(slabs[0].get), 1)
atomic.AddInt64(&(slabs[0].alloc), int64(size))
return make([]byte, 0, size)
}
func Put(item []byte) {
if item == nil || cap(item) <= 0 {
return
}
size, bits := cap(item), uint(0)
for size != 0 {
size >>= 1
bits++
}
size = 1 << (bits - 1)
if size > 0 && float64(cap(item))/float64(size) <= 1.2 {
if slab, ok := slabs[size]; ok {
atomic.AddInt64(&(slab.put), 1)
select {
case slab.queue <- item:
default:
atomic.AddInt64(&(slab.lost), 1)
}
} else {
atomic.AddInt64(&(slabs[0].put), 1)
atomic.AddInt64(&(slabs[0].lost), int64(cap(item)))
}
} else {
atomic.AddInt64(&(slabs[0].put), 1)
atomic.AddInt64(&(slabs[0].lost), int64(cap(item)))
}
}