mirror of
https://github.com/grafana/grafana.git
synced 2024-11-29 04:04:00 -06:00
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[any]*sync.RWMutex
|
|
locksRW *sync.RWMutex
|
|
}
|
|
|
|
func newLocker() *locker {
|
|
return &locker{
|
|
locks: make(map[any]*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 any) {
|
|
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 any) {
|
|
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 any) {
|
|
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 any) {
|
|
lk, ok := lkr.getLock(key)
|
|
if !ok {
|
|
panic(fmt.Errorf("lock for key '%s' not initialized", key))
|
|
}
|
|
lk.RUnlock()
|
|
}
|
|
|
|
func (lkr *locker) newLock(key any) *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 any) (*sync.RWMutex, bool) {
|
|
lkr.locksRW.RLock()
|
|
defer lkr.locksRW.RUnlock()
|
|
|
|
lock, ok := lkr.locks[key]
|
|
return lock, ok
|
|
}
|