mirror of https://github.com/stashapp/stash.git
65 lines
1.4 KiB
Go
65 lines
1.4 KiB
Go
package utils
|
|
|
|
// MutexManager manages access to mutexes using a mutex type and key.
|
|
type MutexManager struct {
|
|
mapChan chan map[string]<-chan struct{}
|
|
}
|
|
|
|
// NewMutexManager returns a new instance of MutexManager.
|
|
func NewMutexManager() *MutexManager {
|
|
ret := &MutexManager{
|
|
mapChan: make(chan map[string]<-chan struct{}, 1),
|
|
}
|
|
|
|
initial := make(map[string]<-chan struct{})
|
|
ret.mapChan <- initial
|
|
|
|
return ret
|
|
}
|
|
|
|
// Claim blocks until the mutex for the mutexType and key pair is available.
|
|
// The mutex is then claimed by the calling code until the provided done
|
|
// channel is closed.
|
|
func (csm *MutexManager) Claim(mutexType string, key string, done <-chan struct{}) {
|
|
mapKey := mutexType + "_" + key
|
|
success := false
|
|
|
|
var existing <-chan struct{}
|
|
for !success {
|
|
// grab the map
|
|
m := <-csm.mapChan
|
|
|
|
// get the entry for the given key
|
|
newEntry := m[mapKey]
|
|
|
|
// if its the existing entry or nil, then it's available, add our channel
|
|
if newEntry == nil || newEntry == existing {
|
|
m[mapKey] = done
|
|
success = true
|
|
}
|
|
|
|
// return the map
|
|
csm.mapChan <- m
|
|
|
|
// if there is an existing entry, now we can wait for it to
|
|
// finish, then repeat the process
|
|
if newEntry != nil {
|
|
existing = newEntry
|
|
<-newEntry
|
|
}
|
|
}
|
|
|
|
// add to goroutine to remove from the map only
|
|
go func() {
|
|
<-done
|
|
|
|
m := <-csm.mapChan
|
|
|
|
if m[mapKey] == done {
|
|
delete(m, mapKey)
|
|
}
|
|
|
|
csm.mapChan <- m
|
|
}()
|
|
}
|