You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							200 lines
						
					
					
						
							4.4 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							200 lines
						
					
					
						
							4.4 KiB
						
					
					
				
								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
							 | 
						|
								}
							 |