karmada/pkg/util/fixedpool/fixedpool.go

81 lines
1.8 KiB
Go

package fixedpool
import (
"sync"
"github.com/karmada-io/karmada/pkg/metrics"
)
// A FixedPool like sync.Pool. But it's limited capacity.
// When pool is full, Put will abandon and call destroyFunc to destroy the object.
type FixedPool struct {
name string
lock sync.Mutex
pool []any
capacity int
newFunc func() (any, error)
destroyFunc func(any)
}
// New return a FixedPool
func New(name string, newFunc func() (any, error), destroyFunc func(any), capacity int) *FixedPool {
return &FixedPool{
name: name,
pool: make([]any, 0, capacity),
capacity: capacity,
newFunc: newFunc,
destroyFunc: destroyFunc,
}
}
// Get selects an arbitrary item from the pool, removes it from the
// pool, and returns it to the caller.
// Get may choose to ignore the pool and treat it as empty.
// Callers should not assume any relation between values passed to Put and
// the values returned by Get.
//
// If pool is empty, Get returns the result of calling newFunc.
func (p *FixedPool) Get() (any, error) {
o, ok := p.pop()
if ok {
metrics.RecordPoolGet(p.name, false)
return o, nil
}
metrics.RecordPoolGet(p.name, true)
return p.newFunc()
}
// Put adds x to the pool. If pool is full, x will be abandoned,
// and it's destroy function will be called.
func (p *FixedPool) Put(x any) {
if p.push(x) {
metrics.RecordPoolPut(p.name, false)
return
}
metrics.RecordPoolPut(p.name, true)
p.destroyFunc(x)
}
func (p *FixedPool) pop() (any, bool) {
p.lock.Lock()
defer p.lock.Unlock()
if s := len(p.pool); s > 0 {
o := p.pool[s-1]
p.pool = p.pool[:s-1]
return o, true
}
return nil, false
}
func (p *FixedPool) push(o any) bool {
p.lock.Lock()
defer p.lock.Unlock()
if s := len(p.pool); s < p.capacity {
p.pool = append(p.pool, o)
return true
}
return false
}