summaryrefslogtreecommitdiff
path: root/vendor/codeberg.org/gruf/go-cache/v3/result/cache.go
diff options
context:
space:
mode:
authorLibravatar kim <89579420+NyaaaWhatsUpDoc@users.noreply.github.com>2023-11-30 16:22:34 +0000
committerLibravatar GitHub <noreply@github.com>2023-11-30 16:22:34 +0000
commiteb170003b81504ba6eb85f950c223dc9eaf1cfca (patch)
treef1f9779e14875faa70f4db85a8cf19100633884d /vendor/codeberg.org/gruf/go-cache/v3/result/cache.go
parent[bugfix] always go through status parent dereferencing on isNew, even on data... (diff)
downloadgotosocial-eb170003b81504ba6eb85f950c223dc9eaf1cfca.tar.xz
[bugfix] return 400 Bad Request on more cases of malformed AS data (#2399)
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.go198
1 files changed, 91 insertions, 107 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 5756c0cf5..eded6e7f4 100644
--- a/vendor/codeberg.org/gruf/go-cache/v3/result/cache.go
+++ b/vendor/codeberg.org/gruf/go-cache/v3/result/cache.go
@@ -2,8 +2,6 @@ package result
import (
"context"
- "fmt"
- "os"
"reflect"
_ "unsafe"
@@ -11,8 +9,6 @@ import (
"codeberg.org/gruf/go-errors/v2"
)
-var ErrUnsupportedZero = errors.New("")
-
// Lookup represents a struct object lookup method in the cache.
type Lookup struct {
// Name is a period ('.') separated string
@@ -58,7 +54,8 @@ func New[T any](lookups []Lookup, copy func(T) T, cap int) *Cache[T] {
}
// Allocate new cache object
- c := &Cache[T]{copy: copy}
+ c := new(Cache[T])
+ c.copy = copy // use copy fn.
c.lookups = make([]structKey, len(lookups))
for i, lookup := range lookups {
@@ -96,7 +93,7 @@ func (c *Cache[T]) SetEvictionCallback(hook func(T)) {
}
// Free result and call hook.
- v := getResultValue[T](res)
+ v := res.Value.(T)
putResult(res)
hook(v)
})
@@ -125,7 +122,7 @@ func (c *Cache[T]) SetInvalidateCallback(hook func(T)) {
}
// Free result and call hook.
- v := getResultValue[T](res)
+ v := res.Value.(T)
putResult(res)
hook(v)
})
@@ -135,11 +132,8 @@ func (c *Cache[T]) SetInvalidateCallback(hook func(T)) {
func (c *Cache[T]) IgnoreErrors(ignore func(error) bool) {
if ignore == nil {
ignore = func(err error) bool {
- return errors.Comparable(
- err,
- context.Canceled,
- context.DeadlineExceeded,
- )
+ return errors.Is(err, context.Canceled) ||
+ errors.Is(err, context.DeadlineExceeded)
}
}
c.cache.Lock()
@@ -149,23 +143,83 @@ func (c *Cache[T]) IgnoreErrors(ignore func(error) bool) {
// Load will attempt to load an existing result from the cacche for the given lookup and key parts, else calling the provided load function and caching the result.
func (c *Cache[T]) Load(lookup string, load func() (T, error), keyParts ...any) (T, error) {
- var zero T
- var res *result
+ info := c.lookups.get(lookup)
+ key := info.genKey(keyParts)
+ return c.load(info, key, load)
+}
+
+// Has checks the cache for a positive result under the given lookup and key parts.
+func (c *Cache[T]) Has(lookup string, keyParts ...any) bool {
+ info := c.lookups.get(lookup)
+ key := info.genKey(keyParts)
+ return c.has(info, key)
+}
- // Get lookup key info by name.
- keyInfo := c.lookups.get(lookup)
- if !keyInfo.unique {
- panic("non-unique lookup does not support load: " + lookup)
+// Store will call the given store function, and on success store the value in the cache as a positive result.
+func (c *Cache[T]) Store(value T, store func() error) error {
+ // Attempt to store this value.
+ if err := store(); err != nil {
+ return err
}
- // Generate cache key string.
- ckey := keyInfo.genKey(keyParts)
+ // Prepare cached result.
+ result := getResult()
+ result.Keys = c.lookups.generate(value)
+ result.Value = c.copy(value)
+ result.Error = nil
+
+ var evict func()
+
+ // Lock cache.
+ c.cache.Lock()
+
+ defer func() {
+ // Unlock cache.
+ c.cache.Unlock()
+
+ if evict != nil {
+ // Call evict.
+ evict()
+ }
+
+ // Call invalidate.
+ c.invalid(value)
+ }()
+
+ // Store result in cache.
+ evict = c.store(result)
+
+ return nil
+}
+
+// Invalidate will invalidate any result from the cache found under given lookup and key parts.
+func (c *Cache[T]) Invalidate(lookup string, keyParts ...any) {
+ info := c.lookups.get(lookup)
+ key := info.genKey(keyParts)
+ c.invalidate(info, key)
+}
+
+// Clear empties the cache, calling the invalidate callback where necessary.
+func (c *Cache[T]) Clear() { c.Trim(100) }
+
+// Trim ensures the cache stays within percentage of total capacity, truncating where necessary.
+func (c *Cache[T]) Trim(perc float64) { c.cache.Trim(perc) }
+
+func (c *Cache[T]) load(lookup *structKey, key string, load func() (T, error)) (T, error) {
+ if !lookup.unique { // ensure this lookup only returns 1 result
+ panic("non-unique lookup does not support load: " + lookup.name)
+ }
+
+ var (
+ zero T
+ res *result
+ )
// Acquire cache lock
c.cache.Lock()
// Look for primary key for cache key (only accept len=1)
- if pkeys := keyInfo.pkeys[ckey]; len(pkeys) == 1 {
+ if pkeys := lookup.pkeys[key]; len(pkeys) == 1 {
// Fetch the result for primary key
entry, ok := c.cache.Cache.Get(pkeys[0])
@@ -200,8 +254,8 @@ func (c *Cache[T]) Load(lookup string, load func() (T, error), keyParts ...any)
// This load returned an error, only
// store this item under provided key.
res.Keys = []cacheKey{{
- info: keyInfo,
- key: ckey,
+ info: lookup,
+ key: key,
}}
} else {
// Alloc result.
@@ -239,66 +293,19 @@ func (c *Cache[T]) Load(lookup string, load func() (T, error), keyParts ...any)
}
// Copy value from cached result.
- v := c.copy(getResultValue[T](res))
+ v := c.copy(res.Value.(T))
return v, nil
}
-// Store will call the given store function, and on success store the value in the cache as a positive result.
-func (c *Cache[T]) Store(value T, store func() error) error {
- // Attempt to store this value.
- if err := store(); err != nil {
- return err
- }
-
- // Prepare cached result.
- result := getResult()
- result.Keys = c.lookups.generate(value)
- result.Value = c.copy(value)
- result.Error = nil
-
- var evict func()
-
- // Lock cache.
- c.cache.Lock()
-
- defer func() {
- // Unlock cache.
- c.cache.Unlock()
-
- if evict != nil {
- // Call evict.
- evict()
- }
-
- // Call invalidate.
- c.invalid(value)
- }()
-
- // Store result in cache.
- evict = c.store(result)
-
- return nil
-}
-
-// Has checks the cache for a positive result under the given lookup and key parts.
-func (c *Cache[T]) Has(lookup string, keyParts ...any) bool {
+func (c *Cache[T]) has(lookup *structKey, key string) bool {
var res *result
- // Get lookup key info by name.
- keyInfo := c.lookups.get(lookup)
- if !keyInfo.unique {
- panic("non-unique lookup does not support has: " + lookup)
- }
-
- // Generate cache key string.
- ckey := keyInfo.genKey(keyParts)
-
// Acquire cache lock
c.cache.Lock()
// Look for primary key for cache key (only accept len=1)
- if pkeys := keyInfo.pkeys[ckey]; len(pkeys) == 1 {
+ if pkeys := lookup.pkeys[key]; len(pkeys) == 1 {
// Fetch the result for primary key
entry, ok := c.cache.Cache.Get(pkeys[0])
@@ -320,31 +327,6 @@ func (c *Cache[T]) Has(lookup string, keyParts ...any) bool {
return ok
}
-// Invalidate will invalidate any result from the cache found under given lookup and key parts.
-func (c *Cache[T]) Invalidate(lookup string, keyParts ...any) {
- // Get lookup key info by name.
- keyInfo := c.lookups.get(lookup)
-
- // Generate cache key string.
- ckey := keyInfo.genKey(keyParts)
-
- // Look for primary key for cache key
- c.cache.Lock()
- pkeys := keyInfo.pkeys[ckey]
- delete(keyInfo.pkeys, ckey)
- c.cache.Unlock()
-
- // Invalidate all primary keys.
- c.cache.InvalidateAll(pkeys...)
-}
-
-// Clear empties the cache, calling the invalidate callback where necessary.
-func (c *Cache[T]) Clear() { c.Trim(100) }
-
-// Trim ensures the cache stays within percentage of total capacity, truncating where necessary.
-func (c *Cache[T]) Trim(perc float64) { c.cache.Trim(perc) }
-
-// store will cache this result under all of its required cache keys.
func (c *Cache[T]) store(res *result) (evict func()) {
var toEvict []*result
@@ -425,6 +407,17 @@ func (c *Cache[T]) store(res *result) (evict func()) {
}
}
+func (c *Cache[T]) invalidate(lookup *structKey, key string) {
+ // Look for primary key for cache key
+ c.cache.Lock()
+ pkeys := lookup.pkeys[key]
+ delete(lookup.pkeys, key)
+ c.cache.Unlock()
+
+ // Invalidate all primary keys.
+ c.cache.InvalidateAll(pkeys...)
+}
+
type result struct {
// Result primary key
PKey int64
@@ -438,12 +431,3 @@ type result struct {
// cached error
Error error
}
-
-// getResultValue is a safe way of casting and fetching result value.
-func getResultValue[T any](res *result) T {
- v, ok := res.Value.(T)
- if !ok {
- fmt.Fprintf(os.Stderr, "!! BUG: unexpected value type in result: %T\n", res.Value)
- }
- return v
-}