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