fixes
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
package actor
|
||||
|
||||
import "sync"
|
||||
|
||||
// keyedMutex provides one logical mutex per key (grain id). It is the
|
||||
// mechanism that enforces the core actor guarantee: a single grain only ever
|
||||
// processes one message (spawn / mutation / read) at a time, while distinct
|
||||
// grains run fully in parallel.
|
||||
//
|
||||
// Locks are reference counted and removed once no caller holds or waits on
|
||||
// them, so memory stays proportional to in-flight grains rather than the total
|
||||
// number of grains ever touched.
|
||||
type keyedMutex struct {
|
||||
mu sync.Mutex
|
||||
locks map[uint64]*keyedMutexEntry
|
||||
}
|
||||
|
||||
type keyedMutexEntry struct {
|
||||
mu sync.Mutex
|
||||
refs int
|
||||
}
|
||||
|
||||
func newKeyedMutex() *keyedMutex {
|
||||
return &keyedMutex{locks: make(map[uint64]*keyedMutexEntry)}
|
||||
}
|
||||
|
||||
// lock acquires the mutex for id and returns an unlock function. The returned
|
||||
// function must be called exactly once.
|
||||
func (k *keyedMutex) lock(id uint64) func() {
|
||||
k.mu.Lock()
|
||||
entry, ok := k.locks[id]
|
||||
if !ok {
|
||||
entry = &keyedMutexEntry{}
|
||||
k.locks[id] = entry
|
||||
}
|
||||
entry.refs++
|
||||
k.mu.Unlock()
|
||||
|
||||
entry.mu.Lock()
|
||||
|
||||
return func() {
|
||||
entry.mu.Unlock()
|
||||
k.mu.Lock()
|
||||
entry.refs--
|
||||
if entry.refs == 0 {
|
||||
delete(k.locks, id)
|
||||
}
|
||||
k.mu.Unlock()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user