123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- package resource_pool
- import (
- "fmt"
- "sync"
- "errors"
- )
- // A resource pool implementation that manages multiple resource location
- // entries. The handles to each resource location entry acts independently.
- // For example "tcp localhost:11211" could act as memcache
- // shard 0 and "tcp localhost:11212" could act as memcache shard 1.
- type multiResourcePool struct {
- options Options
- createPool func(Options) ResourcePool
- rwMutex sync.RWMutex
- isLameDuck bool // guarded by rwMutex
- // NOTE: the locationPools is guarded by rwMutex, but the pool entries
- // are not.
- locationPools map[string]ResourcePool
- }
- // This returns a MultiResourcePool, which manages multiple
- // resource location entries. The handles to each resource location
- // entry acts independently.
- //
- // When createPool is nil, NewSimpleResourcePool is used as default.
- func NewMultiResourcePool(
- options Options,
- createPool func(Options) ResourcePool) ResourcePool {
- if createPool == nil {
- createPool = NewSimpleResourcePool
- }
- return &multiResourcePool{
- options: options,
- createPool: createPool,
- rwMutex: sync.RWMutex{},
- isLameDuck: false,
- locationPools: make(map[string]ResourcePool),
- }
- }
- // See ResourcePool for documentation.
- func (p *multiResourcePool) NumActive() int32 {
- total := int32(0)
- p.rwMutex.RLock()
- defer p.rwMutex.RUnlock()
- for _, pool := range p.locationPools {
- total += pool.NumActive()
- }
- return total
- }
- // See ResourcePool for documentation.
- func (p *multiResourcePool) ActiveHighWaterMark() int32 {
- high := int32(0)
- p.rwMutex.RLock()
- defer p.rwMutex.RUnlock()
- for _, pool := range p.locationPools {
- val := pool.ActiveHighWaterMark()
- if val > high {
- high = val
- }
- }
- return high
- }
- // See ResourcePool for documentation.
- func (p *multiResourcePool) NumIdle() int {
- total := 0
- p.rwMutex.RLock()
- defer p.rwMutex.RUnlock()
- for _, pool := range p.locationPools {
- total += pool.NumIdle()
- }
- return total
- }
- // See ResourcePool for documentation.
- func (p *multiResourcePool) Register(resourceLocation string) error {
- if resourceLocation == "" {
- return errors.New("Registering invalid resource location")
- }
- p.rwMutex.Lock()
- defer p.rwMutex.Unlock()
- if p.isLameDuck {
- return fmt.Errorf(
- "Cannot register %s to lame duck resource pool",
- resourceLocation)
- }
- if _, inMap := p.locationPools[resourceLocation]; inMap {
- return nil
- }
- pool := p.createPool(p.options)
- if err := pool.Register(resourceLocation); err != nil {
- return err
- }
- p.locationPools[resourceLocation] = pool
- return nil
- }
- // See ResourcePool for documentation.
- func (p *multiResourcePool) Unregister(resourceLocation string) error {
- p.rwMutex.Lock()
- defer p.rwMutex.Unlock()
- if pool, inMap := p.locationPools[resourceLocation]; inMap {
- _ = pool.Unregister("")
- pool.EnterLameDuckMode()
- delete(p.locationPools, resourceLocation)
- }
- return nil
- }
- func (p *multiResourcePool) ListRegistered() []string {
- p.rwMutex.RLock()
- defer p.rwMutex.RUnlock()
- result := make([]string, 0, len(p.locationPools))
- for key, _ := range p.locationPools {
- result = append(result, key)
- }
- return result
- }
- // See ResourcePool for documentation.
- func (p *multiResourcePool) Get(
- resourceLocation string) (ManagedHandle, error) {
- pool := p.getPool(resourceLocation)
- if pool == nil {
- return nil, fmt.Errorf(
- "%s is not registered in the resource pool",
- resourceLocation)
- }
- return pool.Get(resourceLocation)
- }
- // See ResourcePool for documentation.
- func (p *multiResourcePool) Release(handle ManagedHandle) error {
- pool := p.getPool(handle.ResourceLocation())
- if pool == nil {
- return errors.New(
- "Resource pool cannot take control of a handle owned " +
- "by another resource pool")
- }
- return pool.Release(handle)
- }
- // See ResourcePool for documentation.
- func (p *multiResourcePool) Discard(handle ManagedHandle) error {
- pool := p.getPool(handle.ResourceLocation())
- if pool == nil {
- return errors.New(
- "Resource pool cannot take control of a handle owned " +
- "by another resource pool")
- }
- return pool.Discard(handle)
- }
- // See ResourcePool for documentation.
- func (p *multiResourcePool) EnterLameDuckMode() {
- p.rwMutex.Lock()
- defer p.rwMutex.Unlock()
- p.isLameDuck = true
- for _, pool := range p.locationPools {
- pool.EnterLameDuckMode()
- }
- }
- func (p *multiResourcePool) getPool(resourceLocation string) ResourcePool {
- p.rwMutex.RLock()
- defer p.rwMutex.RUnlock()
- if pool, inMap := p.locationPools[resourceLocation]; inMap {
- return pool
- }
- return nil
- }
|