func (rp *ResourcePool) Capacity() int64 {
	return rp.capacity.Get()
}
Capacity returns the capacity.
package util
import (
	"context"
	"errors"
	"fmt"
	"sync"
	"time"
	"github.com/XiaoMi/Gaea/util/sync2"
	"github.com/XiaoMi/Gaea/util/timer"
)
var (
	ErrClosed = errors.New("resource pool is closed")
	ErrTimeout = errors.New("resource pool timed out")
)
type Factory func() (Resource, error)
type Resource interface {
	Close()
}
type ResourcePool struct {
	resources   chan resourceWrapper
	factory     Factory
	capacity    sync2.AtomicInt64
	idleTimeout sync2.AtomicDuration
	idleTimer   *timer.Timer
	capTimer    *timer.Timer
	available    sync2.AtomicInt64
	active       sync2.AtomicInt64
	inUse        sync2.AtomicInt64
	waitCount    sync2.AtomicInt64
	waitTime     sync2.AtomicDuration
	idleClosed   sync2.AtomicInt64
	baseCapacity sync2.AtomicInt64
	maxCapacity  sync2.AtomicInt64
	lock         *sync.Mutex
	scaleOutTime int64
	scaleInTodo  chan int8
	Dynamic      bool
}
type resourceWrapper struct {
	resource Resource
	timeUsed time.Time
}
func NewResourcePool(factory Factory, capacity, maxCap int, idleTimeout time.Duration) *ResourcePool {
	if capacity <= 0 || maxCap <= 0 || capacity > maxCap {
		panic(errors.New("invalid/out of range capacity"))
	}
	rp := &ResourcePool{
		resources:    make(chan resourceWrapper, maxCap),
		factory:      factory,
		available:    sync2.NewAtomicInt64(int64(capacity)),
		capacity:     sync2.NewAtomicInt64(int64(capacity)),
		idleTimeout:  sync2.NewAtomicDuration(idleTimeout),
		baseCapacity: sync2.NewAtomicInt64(int64(capacity)),
		maxCapacity:  sync2.NewAtomicInt64(int64(maxCap)),
		lock:         &sync.Mutex{},
		scaleInTodo:  make(chan int8, 1),
		Dynamic:      true,  
	}
	for i := 0; i < capacity; i++ {
		rp.resources <- resourceWrapper{}
	}
	if idleTimeout != 0 {
		rp.idleTimer = timer.NewTimer(idleTimeout / 10)
		rp.idleTimer.Start(rp.closeIdleResources)
	}
	rp.capTimer = timer.NewTimer(5 * time.Second)
	rp.capTimer.Start(rp.scaleInResources)
	return rp
}
func (rp *ResourcePool) Close() {
	if rp.idleTimer != nil {
		rp.idleTimer.Stop()
	}
	if rp.capTimer != nil {
		rp.capTimer.Stop()
	}
	_ = rp.ScaleCapacity(0)
}
func (rp *ResourcePool) SetDynamic(value bool) {
	rp.Dynamic = value
}
func (rp *ResourcePool) IsClosed() (closed bool) {
	return rp.capacity.Get() == 0
}
func (rp *ResourcePool) closeIdleResources() {
	available := int(rp.Available())
	idleTimeout := rp.IdleTimeout()
	for i := 0; i < available; i++ {
		var wrapper resourceWrapper
		select {
		case wrapper, _ = <-rp.resources:
		default:
			return
		}
		if wrapper.resource != nil && idleTimeout > 0 && wrapper.timeUsed.Add(idleTimeout).Sub(time.Now()) < 0 {
			wrapper.resource.Close()
			wrapper.resource = nil
			rp.idleClosed.Add(1)
			rp.active.Add(-1)
		}
		rp.resources <- wrapper
	}
}
func (rp *ResourcePool) Get(ctx context.Context) (resource Resource, err error) {
	return rp.get(ctx, true)
}
func (rp *ResourcePool) get(ctx context.Context, wait bool) (resource Resource, err error) {
	select {
	case <-ctx.Done():
		return nil, ErrTimeout
	default:
	}
	var wrapper resourceWrapper
	var ok bool
	select {
	case wrapper, ok = <-rp.resources:
	default:
		if rp.Dynamic {
			rp.scaleOutResources()
		}
		if !wait {
			return nil, nil
		}
		startTime := time.Now()
		select {
		case wrapper, ok = <-rp.resources:
		case <-ctx.Done():
			return nil, ErrTimeout
		}
		endTime := time.Now()
		if int64(startTime.UnixNano()/100000) != int64(endTime.UnixNano()/100000) {
			rp.recordWait(startTime)
		}
	}
	if !ok {
		return nil, ErrClosed
	}
	if wrapper.resource == nil {
		wrapper.resource, err = rp.factory()  
		if err != nil {
			rp.resources <- resourceWrapper{}
			return nil, err
		}
		rp.active.Add(1)
	}
	rp.available.Add(-1)
	rp.inUse.Add(1)
	return wrapper.resource, err
}
func (rp *ResourcePool) Put(resource Resource) {
	var wrapper resourceWrapper
	if resource != nil {
		wrapper = resourceWrapper{resource, time.Now()}
	} else {
		rp.active.Add(-1)
	}
	select {
	case rp.resources <- wrapper:
	default:
		panic(errors.New("attempt to Put into a full ResourcePool"))
	}
	rp.inUse.Add(-1)
	rp.available.Add(1)
}
func (rp *ResourcePool) SetCapacity(capacity int) error {
	oldcap := rp.baseCapacity.Get()
	rp.baseCapacity.CompareAndSwap(oldcap, int64(capacity))
	if int(oldcap) < capacity {
		rp.ScaleCapacity(capacity)
	}
	return nil
}
func (rp *ResourcePool) ScaleCapacity(capacity int) error {
	if capacity < 0 || capacity > int(rp.maxCapacity.Get()) {
		return fmt.Errorf("capacity %d is out of range", capacity)
	}
	var oldcap int
	for {
		oldcap = int(rp.capacity.Get())
		if oldcap == 0 {
			return ErrClosed
		}
		if oldcap == capacity {
			return nil
		}
		if rp.capacity.CompareAndSwap(int64(oldcap), int64(capacity)) {
			break
		}
	}
	if capacity < oldcap {
		for i := 0; i < oldcap-capacity; i++ {
			wrapper := <-rp.resources
			if wrapper.resource != nil {
				wrapper.resource.Close()
				rp.active.Add(-1)
			}
			rp.available.Add(-1)
		}
	} else {
		for i := 0; i < capacity-oldcap; i++ {
			rp.resources <- resourceWrapper{}
			rp.available.Add(1)
		}
	}
	if capacity == 0 {
		close(rp.resources)
	}
	return nil
}
func (rp *ResourcePool) scaleOutResources() {
	rp.lock.Lock()
	defer rp.lock.Unlock()
	if rp.capacity.Get() < rp.maxCapacity.Get() {
		rp.ScaleCapacity(int(rp.capacity.Get()) + 1)
		rp.scaleOutTime = time.Now().Unix()
	}
}
func (rp *ResourcePool) scaleInResources() {
	rp.lock.Lock()
	defer rp.lock.Unlock()
	if rp.capacity.Get() > rp.baseCapacity.Get() && time.Now().Unix()-rp.scaleOutTime > 60 {
		select {
		case rp.scaleInTodo <- 0:
			go func() {
				rp.ScaleCapacity(int(rp.capacity.Get()) - 1)
				<-rp.scaleInTodo
			}()
		default:
			return
		}
	}
}
func (rp *ResourcePool) recordWait(start time.Time) {
	rp.waitCount.Add(1)
	rp.waitTime.Add(time.Now().Sub(start))
}
func (rp *ResourcePool) SetIdleTimeout(idleTimeout time.Duration) {
	if rp.idleTimer == nil {
		panic("SetIdleTimeout called when timer not initialized")
	}
	rp.idleTimeout.Set(idleTimeout)
	rp.idleTimer.SetInterval(idleTimeout / 10)
}
func (rp *ResourcePool) StatsJSON() string {
	return fmt.Sprintf(`{"Capacity": %v, "Available": %v, "Active": %v, "InUse": %v, "MaxCapacity": %v, "WaitCount": %v, "WaitTime": %v, "IdleTimeout": %v, "IdleClosed": %v}`,
		rp.Capacity(),
		rp.Available(),
		rp.Active(),
		rp.InUse(),
		rp.MaxCap(),
		rp.WaitCount(),
		rp.WaitTime().Nanoseconds(),
		rp.IdleTimeout().Nanoseconds(),
		rp.IdleClosed(),
	)
}