diff options
author | 2023-11-30 16:22:34 +0000 | |
---|---|---|
committer | 2023-11-30 16:22:34 +0000 | |
commit | eb170003b81504ba6eb85f950c223dc9eaf1cfca (patch) | |
tree | f1f9779e14875faa70f4db85a8cf19100633884d /vendor/codeberg.org/gruf/go-cache/v3/result/cache.go | |
parent | [bugfix] always go through status parent dereferencing on isNew, even on data... (diff) | |
download | gotosocial-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.go | 198 |
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 -} |