diff options
Diffstat (limited to 'vendor/codeberg.org/gruf/go-cache/v3/result/cache.go')
-rw-r--r-- | vendor/codeberg.org/gruf/go-cache/v3/result/cache.go | 85 |
1 files changed, 60 insertions, 25 deletions
diff --git a/vendor/codeberg.org/gruf/go-cache/v3/result/cache.go b/vendor/codeberg.org/gruf/go-cache/v3/result/cache.go index 805a4d989..5b16712b6 100644 --- a/vendor/codeberg.org/gruf/go-cache/v3/result/cache.go +++ b/vendor/codeberg.org/gruf/go-cache/v3/result/cache.go @@ -97,20 +97,22 @@ func (c *Cache[Value]) SetEvictionCallback(hook func(Value)) { // Ensure non-nil hook. hook = func(Value) {} } - c.cache.SetEvictionCallback(func(item *ttl.Entry[int64, result[Value]]) { - for _, key := range item.Value.Keys { + c.cache.SetEvictionCallback(func(pkey int64, res result[Value]) { + c.cache.Lock() + for _, key := range res.Keys { // Delete key->pkey lookup pkeys := key.info.pkeys delete(pkeys, key.key) } + c.cache.Unlock() - if item.Value.Error != nil { + if res.Error != nil { // Skip error hooks return } // Call user hook. - hook(item.Value.Value) + hook(res.Value) }) } @@ -121,20 +123,22 @@ func (c *Cache[Value]) SetInvalidateCallback(hook func(Value)) { hook = func(Value) {} } // store hook. c.invalid = hook - c.cache.SetInvalidateCallback(func(item *ttl.Entry[int64, result[Value]]) { - for _, key := range item.Value.Keys { + c.cache.SetInvalidateCallback(func(pkey int64, res result[Value]) { + c.cache.Lock() + for _, key := range res.Keys { // Delete key->pkey lookup pkeys := key.info.pkeys delete(pkeys, key.key) } + c.cache.Unlock() - if item.Value.Error != nil { + if res.Error != nil { // Skip error hooks return } // Call user hook. - hook(item.Value.Value) + hook(res.Value) }) } @@ -178,9 +182,17 @@ func (c *Cache[Value]) Load(lookup string, load func() (Value, error), keyParts pkeys := keyInfo.pkeys[ckey] if ok = (len(pkeys) > 0); ok { + var entry *ttl.Entry[int64, result[Value]] + // Fetch the result for primary key - entry, _ := c.cache.Cache.Get(pkeys[0]) - res = entry.Value + entry, ok = c.cache.Cache.Get(pkeys[0]) + if ok { + // Since the invalidation / eviction hooks acquire a mutex + // lock separately, and only at this point are the pkeys + // updated, there is a chance that a primary key may return + // no matching entry. Hence we have to check for it here. + res = entry.Value + } } // Done with lock @@ -213,12 +225,19 @@ func (c *Cache[Value]) Load(lookup string, load func() (Value, error), keyParts res.Keys = c.lookups.generate(res.Value) } + var evict func() + // Acquire cache lock. c.cache.Lock() - defer c.cache.Unlock() + defer func() { + c.cache.Unlock() + if evict != nil { + evict() + } + }() - // Cache result - c.store(res) + // Store result in cache. + evict = c.store(res) } // Catch and return error @@ -244,12 +263,19 @@ func (c *Cache[Value]) Store(value Value, store func() error) error { Error: nil, } + var evict func() + // Acquire cache lock. c.cache.Lock() - defer c.cache.Unlock() + defer func() { + c.cache.Unlock() + if evict != nil { + evict() + } + }() - // Cache result - c.store(result) + // Store result in cache. + evict = c.store(result) // Call invalidate. c.invalid(value) @@ -278,9 +304,17 @@ func (c *Cache[Value]) Has(lookup string, keyParts ...any) bool { pkeys := keyInfo.pkeys[ckey] if ok = (len(pkeys) > 0); ok { + var entry *ttl.Entry[int64, result[Value]] + // Fetch the result for primary key - entry, _ := c.cache.Cache.Get(pkeys[0]) - res = entry.Value + entry, ok = c.cache.Cache.Get(pkeys[0]) + if ok { + // Since the invalidation / eviction hooks acquire a mutex + // lock separately, and only at this point are the pkeys + // updated, there is a chance that a primary key may return + // no matching entry. Hence we have to check for it here. + res = entry.Value + } } // Done with lock @@ -301,19 +335,18 @@ func (c *Cache[Value]) Invalidate(lookup string, keyParts ...any) { // Look for primary key for cache key c.cache.Lock() pkeys := keyInfo.pkeys[ckey] + delete(keyInfo.pkeys, ckey) c.cache.Unlock() - for _, pkey := range pkeys { - // Invalidate each primary key - c.cache.Invalidate(pkey) - } + // Invalidate all primary keys. + c.cache.InvalidateAll(pkeys...) } // Clear empties the cache, calling the invalidate callback. func (c *Cache[Value]) Clear() { c.cache.Clear() } // store will cache this result under all of its required cache keys. -func (c *Cache[Value]) store(res result[Value]) { +func (c *Cache[Value]) store(res result[Value]) (evict func()) { // Get primary key pnext := c.next c.next++ @@ -341,7 +374,7 @@ func (c *Cache[Value]) store(res result[Value]) { } } - // Drop these keys. + // Drop existing. pkeys = pkeys[:0] } @@ -356,8 +389,10 @@ func (c *Cache[Value]) store(res result[Value]) { Key: pnext, Value: res, }, func(_ int64, item *ttl.Entry[int64, result[Value]]) { - c.cache.Evict(item) + evict = func() { c.cache.Evict(item.Key, item.Value) } }) + + return evict } type result[Value any] struct { |