blob: 2d90704cc9f969aad8c695c6d9634d7378c5760c [file] [log] [blame]
package common
import (
"sync/atomic"
)
type Pool struct {
New func() interface{}
Destroy func(interface{})
pool chan interface{}
created int32 //Number of objects created
}
/*
NewPool creates thread safe Pool object and returns a pointer to it.
poolSize int - sets the capacity of the pool
newObj func - specifies a function to generate a value (pool element)
destroyObj func - specifies a function to destroy a value (pool element)
*/
func NewPool(poolSize int, newObj func() interface{}, destroyObj func(interface{})) *Pool{
return &Pool{
New: newObj,
Destroy: destroyObj,
pool: make(chan interface{}, poolSize),
}
}
/*
Retrieve an object from the pool.
If the pool is empty and the number of used object is less than capacity, a new object is created by calling New.
Otherwise, the method blocks until an object is returned to the pool.
*/
func (p *Pool) Get() interface{} {
select {
case obj := <-p.pool:
return obj
default:
if atomic.AddInt32(&p.created, 1) <= int32(cap(p.pool)) && p.New != nil {
p.pool <- p.New()
}
}
return <-p.pool //block waiting
}
/*
Return an object to the pool.
If capacity is exceeded the object is discarded after calling Destroy on it if Destroy is not nil.
*/
func (p *Pool) Put(obj interface{}) {
if obj != nil {
select {
case p.pool <- obj:
default:
if p.Destroy != nil {
p.Destroy(obj)
}
}
}
}
/*
Closes the pool and if Destroy is not nil, call Destroy on each object in the pool
The pool must not be used once this method is called.
*/
func (p *Pool) Close() {
close(p.pool)
available := len(p.pool)
if p.Destroy != nil {
for obj := range p.pool {
p.Destroy(obj)
}
}
atomic.AddInt32(&p.created, -int32(available))
}
/*
Return statistics.
available - the number of available instances
created - the number of created instances
*/
func (p *Pool) Stats() (available int, created int) {
return len(p.pool), int(p.created)
}