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) }