mirror of https://github.com/grafana/grafana.git
				
				
				
			
		
			
	
	
		
			86 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Go
		
	
	
	
		
		
			
		
	
	
			86 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Go
		
	
	
	
|  | package postgres | ||
|  | 
 | ||
|  | import ( | ||
|  | 	"fmt" | ||
|  | 	"sync" | ||
|  | ) | ||
|  | 
 | ||
|  | // locker is a named reader/writer mutual exclusion lock.
 | ||
|  | // The lock for each particular key can be held by an arbitrary number of readers or a single writer.
 | ||
|  | type locker struct { | ||
|  | 	locks   map[interface{}]*sync.RWMutex | ||
|  | 	locksRW *sync.RWMutex | ||
|  | } | ||
|  | 
 | ||
|  | func newLocker() *locker { | ||
|  | 	return &locker{ | ||
|  | 		locks:   make(map[interface{}]*sync.RWMutex), | ||
|  | 		locksRW: new(sync.RWMutex), | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // Lock locks named rw mutex with specified key for writing.
 | ||
|  | // If the lock with the same key is already locked for reading or writing,
 | ||
|  | // Lock blocks until the lock is available.
 | ||
|  | func (lkr *locker) Lock(key interface{}) { | ||
|  | 	lk, ok := lkr.getLock(key) | ||
|  | 	if !ok { | ||
|  | 		lk = lkr.newLock(key) | ||
|  | 	} | ||
|  | 	lk.Lock() | ||
|  | } | ||
|  | 
 | ||
|  | // Unlock unlocks named rw mutex with specified key for writing. It is a run-time error if rw is
 | ||
|  | // not locked for writing on entry to Unlock.
 | ||
|  | func (lkr *locker) Unlock(key interface{}) { | ||
|  | 	lk, ok := lkr.getLock(key) | ||
|  | 	if !ok { | ||
|  | 		panic(fmt.Errorf("lock for key '%s' not initialized", key)) | ||
|  | 	} | ||
|  | 	lk.Unlock() | ||
|  | } | ||
|  | 
 | ||
|  | // RLock locks named rw mutex with specified key for reading.
 | ||
|  | //
 | ||
|  | // It should not be used for recursive read locking for the same key; a blocked Lock
 | ||
|  | // call excludes new readers from acquiring the lock. See the
 | ||
|  | // documentation on the golang RWMutex type.
 | ||
|  | func (lkr *locker) RLock(key interface{}) { | ||
|  | 	lk, ok := lkr.getLock(key) | ||
|  | 	if !ok { | ||
|  | 		lk = lkr.newLock(key) | ||
|  | 	} | ||
|  | 	lk.RLock() | ||
|  | } | ||
|  | 
 | ||
|  | // RUnlock undoes a single RLock call for specified key;
 | ||
|  | // it does not affect other simultaneous readers of locker for specified key.
 | ||
|  | // It is a run-time error if locker for specified key is not locked for reading
 | ||
|  | func (lkr *locker) RUnlock(key interface{}) { | ||
|  | 	lk, ok := lkr.getLock(key) | ||
|  | 	if !ok { | ||
|  | 		panic(fmt.Errorf("lock for key '%s' not initialized", key)) | ||
|  | 	} | ||
|  | 	lk.RUnlock() | ||
|  | } | ||
|  | 
 | ||
|  | func (lkr *locker) newLock(key interface{}) *sync.RWMutex { | ||
|  | 	lkr.locksRW.Lock() | ||
|  | 	defer lkr.locksRW.Unlock() | ||
|  | 
 | ||
|  | 	if lk, ok := lkr.locks[key]; ok { | ||
|  | 		return lk | ||
|  | 	} | ||
|  | 	lk := new(sync.RWMutex) | ||
|  | 	lkr.locks[key] = lk | ||
|  | 	return lk | ||
|  | } | ||
|  | 
 | ||
|  | func (lkr *locker) getLock(key interface{}) (*sync.RWMutex, bool) { | ||
|  | 	lkr.locksRW.RLock() | ||
|  | 	defer lkr.locksRW.RUnlock() | ||
|  | 
 | ||
|  | 	lock, ok := lkr.locks[key] | ||
|  | 	return lock, ok | ||
|  | } |