karmada/pkg/util/fixedpool/fixedpool.go

97 lines
2.3 KiB
Go

/*
Copyright 2022 The Karmada Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
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
}