package api import "sync" // keyedLocks hands out one mutex per string key so slow work for one instance // or user never blocks unrelated work behind a shared global lock. Registry // entries are removed once the last holder releases, keeping the map bounded. type keyedLocks struct { mu sync.Mutex locks map[string]*keyedLock } type keyedLock struct { owner *keyedLocks key string mu sync.Mutex refs int } // Acquire registers interest in the key's lock (blocking callers keep the // registry entry alive) and then blocks until the mutex is held. func (k *keyedLocks) Acquire(key string) *keyedLock { k.mu.Lock() if k.locks == nil { k.locks = make(map[string]*keyedLock) } l, ok := k.locks[key] if !ok { l = &keyedLock{owner: k, key: key} k.locks[key] = l } l.refs++ k.mu.Unlock() l.mu.Lock() return l } // Release frees the mutex and drops the registry entry when no holder or // waiter remains. func (l *keyedLock) Release() { l.mu.Unlock() k := l.owner k.mu.Lock() l.refs-- if l.refs == 0 { delete(k.locks, l.key) } k.mu.Unlock() } // held reports whether any keyed lock is currently held or being waited for. func (k *keyedLocks) held() bool { k.mu.Lock() defer k.mu.Unlock() return len(k.locks) > 0 }