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