X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=intent.go;h=56900a437ef44a08feb2dcaf5718a830473c0f53;hb=e6b6a718a328e339e022cc05f5c79940cca6dec5;hp=853d8270902be287bd95bb4b67b171d4a5df0509;hpb=e54415863fb1aaa9a12d4a351557667f2d668c30;p=go-anidb.git diff --git a/intent.go b/intent.go index 853d827..56900a4 100644 --- a/intent.go +++ b/intent.go @@ -9,6 +9,8 @@ type intentStruct struct { type intentMapStruct struct { sync.Mutex + intentLock sync.Mutex // used by the Intent function + m map[string]*intentStruct } @@ -17,6 +19,8 @@ var intentMap = &intentMapStruct{ } // Register a channel to be notified when the specified keys are notified. +// Returns whether the caller was the first to register intent for the given +// keys. // // Cache checks should be done after registering intent, since it's possible to // register Intent while a Notify is running, and the Notify is done after @@ -24,11 +28,13 @@ var intentMap = &intentMapStruct{ func (m *intentMapStruct) Intent(ch chan Cacheable, keys ...cacheKey) bool { key := cachePath(keys...) + m.intentLock.Lock() + defer m.intentLock.Unlock() + m.Lock() s, ok := m.m[key] if !ok { s = &intentStruct{} - m.m[key] = s } m.Unlock() @@ -36,28 +42,109 @@ func (m *intentMapStruct) Intent(ch chan Cacheable, keys ...cacheKey) bool { s.chs = append(s.chs, ch) s.Unlock() + m.Lock() + // key might have been deleted while only the struct itself was locked -- recheck + _, ok = m.m[key] + m.m[key] = s + m.Unlock() + return ok } -// Notify all channels that are listening for the specified keys. +// Locks the requested keys and return the locked intentStruct. // -// Should be called after setting the cache. -func (m *intentMapStruct) Notify(v Cacheable, keys ...cacheKey) { - key := cachePath(keys...) - +// The intentStruct can be directly unlocked, or given to Free to also +// remove it from the intent map. +func (m *intentMapStruct) LockIntent(keys ...cacheKey) *intentStruct { m.Lock() defer m.Unlock() - s, ok := m.m[key] + + return m._lockIntent(keys...) +} + +func (m *intentMapStruct) _lockIntent(keys ...cacheKey) *intentStruct { + s, ok := m.m[cachePath(keys...)] if !ok { - return + return nil } s.Lock() - defer s.Unlock() + return s +} + +// Removes the given intent from the intent map and unlocks the intentStruct. +func (m *intentMapStruct) Free(is *intentStruct, keys ...cacheKey) { + m.Lock() + defer m.Unlock() + + m._free(is, keys...) +} +func (m *intentMapStruct) _free(is *intentStruct, keys ...cacheKey) { + // deletes the key before unlocking, Intent needs to recheck key status + delete(m.m, cachePath(keys...)) + // better than unlocking then deleting -- could delete a "brand new" entry + is.Unlock() +} + +// Notifies and closes all channels that are listening for the specified keys; +// also removes them from the intent map. +// +// Should be called after setting the cache. +func (m *intentMapStruct) NotifyClose(v Cacheable, keys ...cacheKey) { + m.Lock() + defer m.Unlock() + + is := m._lockIntent(keys...) + defer m._free(is, keys...) + + is.NotifyClose(v) +} + +// Closes all channels that are listening for the specified keys +// and removes them from the intent map. +func (m *intentMapStruct) Close(keys ...cacheKey) { + m.Lock() + defer m.Unlock() + + is := m._lockIntent(keys...) + defer m._free(is, keys...) + + is.Close() +} + +// Notifies all channels that are listening for the specified keys, +// but doesn't close or remove them from the intent map. +func (m *intentMapStruct) Notify(v Cacheable, keys ...cacheKey) { + m.Lock() + defer m.Unlock() + + is := m._lockIntent(keys...) + defer is.Unlock() + + is.Notify(v) +} + +// NOTE: does not lock the stuct +func (s *intentStruct) Notify(v Cacheable) { + for _, ch := range s.chs { + ch <- v + } +} + +// NOTE: does not lock the struct +func (s *intentStruct) Close() { for _, ch := range s.chs { - go func(c chan Cacheable) { c <- v }(ch) + close(ch) } + s.chs = nil +} - delete(m.m, key) +// NOTE: does not lock the struct +func (s *intentStruct) NotifyClose(v Cacheable) { + for _, ch := range s.chs { + ch <- v + close(ch) + } + s.chs = nil }