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