summaryrefslogtreecommitdiff
path: root/vendor/codeberg.org/gruf/go-cache
diff options
context:
space:
mode:
authorLibravatar kim <89579420+NyaaaWhatsUpDoc@users.noreply.github.com>2023-08-04 12:28:33 +0100
committerLibravatar GitHub <noreply@github.com>2023-08-04 12:28:33 +0100
commit9a291dea843448f78b4b98ea6813739aebe708c6 (patch)
treef1ce643a3c9fe1b13e4c107f15b1ac4b20fe5b86 /vendor/codeberg.org/gruf/go-cache
parent[feature] simpler cache size configuration (#2051) (diff)
downloadgotosocial-9a291dea843448f78b4b98ea6813739aebe708c6.tar.xz
[performance] add caching of status fave, boost of, in reply to ID lists (#2060)
Diffstat (limited to 'vendor/codeberg.org/gruf/go-cache')
-rw-r--r--vendor/codeberg.org/gruf/go-cache/v3/result/cache.go86
-rw-r--r--vendor/codeberg.org/gruf/go-cache/v3/result/key.go147
-rw-r--r--vendor/codeberg.org/gruf/go-cache/v3/simple/cache.go16
-rw-r--r--vendor/codeberg.org/gruf/go-cache/v3/simple/pool.go8
4 files changed, 143 insertions, 114 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 f31e6604a..665481d55 100644
--- a/vendor/codeberg.org/gruf/go-cache/v3/result/cache.go
+++ b/vendor/codeberg.org/gruf/go-cache/v3/result/cache.go
@@ -11,28 +11,7 @@ import (
"codeberg.org/gruf/go-errors/v2"
)
-type result struct {
- // Result primary key
- PKey int64
-
- // keys accessible under
- Keys cacheKeys
-
- // cached value
- Value any
-
- // 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
-}
+var ErrUnsupportedZero = errors.New("")
// Lookup represents a struct object lookup method in the cache.
type Lookup struct {
@@ -255,13 +234,15 @@ func (c *Cache[T]) Load(lookup string, load func() (T, error), keyParts ...any)
evict = c.store(res)
}
- // Catch and return error
- if res.Error != nil {
- return zero, res.Error
+ // Catch and return cached error
+ if err := res.Error; err != nil {
+ return zero, err
}
- // Return a copy of value from cache
- return c.copy(getResultValue[T](res)), nil
+ // Copy value from cached result.
+ v := c.copy(getResultValue[T](res))
+
+ return v, nil
}
// Store will call the given store function, and on success store the value in the cache as a positive result.
@@ -332,11 +313,13 @@ func (c *Cache[T]) Has(lookup string, keyParts ...any) bool {
}
}
+ // Check for result AND non-error result.
+ ok := (res != nil && res.Error == nil)
+
// Done with lock
c.cache.Unlock()
- // Check for result AND non-error result.
- return (res != nil && res.Error == nil)
+ return ok
}
// Invalidate will invalidate any result from the cache found under given lookup and key parts.
@@ -407,13 +390,18 @@ func (c *Cache[T]) store(res *result) (evict func()) {
key.info.pkeys[key.key] = pkeys
}
+ // Acquire new cache entry.
+ entry := simple.GetEntry()
+ entry.Key = res.PKey
+ entry.Value = res
+
+ evictFn := func(_ int64, entry *simple.Entry) {
+ // on evict during set, store evicted result.
+ toEvict = append(toEvict, entry.Value.(*result))
+ }
+
// Store main entry under primary key, catch evicted.
- c.cache.Cache.SetWithHook(res.PKey, &simple.Entry{
- Key: res.PKey,
- Value: res,
- }, func(_ int64, item *simple.Entry) {
- toEvict = append(toEvict, item.Value.(*result))
- })
+ c.cache.Cache.SetWithHook(res.PKey, entry, evictFn)
if len(toEvict) == 0 {
// none evicted.
@@ -421,9 +409,35 @@ func (c *Cache[T]) store(res *result) (evict func()) {
}
return func() {
- for _, res := range toEvict {
+ for i := range toEvict {
+ // Rescope result.
+ res := toEvict[i]
+
// Call evict hook on each entry.
c.cache.Evict(res.PKey, res)
}
}
}
+
+type result struct {
+ // Result primary key
+ PKey int64
+
+ // keys accessible under
+ Keys cacheKeys
+
+ // cached value
+ Value any
+
+ // 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
+}
diff --git a/vendor/codeberg.org/gruf/go-cache/v3/result/key.go b/vendor/codeberg.org/gruf/go-cache/v3/result/key.go
index cf86c7c30..5e10e6fa1 100644
--- a/vendor/codeberg.org/gruf/go-cache/v3/result/key.go
+++ b/vendor/codeberg.org/gruf/go-cache/v3/result/key.go
@@ -47,27 +47,32 @@ func (sk structKeys) generate(a any) []cacheKey {
buf := getBuf()
defer putBuf(buf)
+outer:
for i := range sk {
// Reset buffer
- buf.B = buf.B[:0]
+ buf.Reset()
// Append each field value to buffer.
for _, field := range sk[i].fields {
fv := v.Field(field.index)
fi := fv.Interface()
- buf.B = field.mangle(buf.B, fi)
+
+ // Mangle this key part into buffer.
+ ok := field.manglePart(buf, fi)
+
+ if !ok {
+ // don't generate keys
+ // for zero value parts.
+ continue outer
+ }
+
+ // Append part separator.
buf.B = append(buf.B, '.')
}
// Drop last '.'
buf.Truncate(1)
- // Don't generate keys for zero values
- if allowZero := sk[i].zero == ""; // nocollapse
- !allowZero && buf.String() == sk[i].zero {
- continue
- }
-
// Append new cached key to slice
keys = append(keys, cacheKey{
info: &sk[i],
@@ -114,14 +119,6 @@ type structKey struct {
// period ('.') separated struct field names.
name string
- // zero is the possible zero value for this key.
- // if set, this will _always_ be non-empty, as
- // the mangled cache key will never be empty.
- //
- // i.e. zero = "" --> allow zero value keys
- // zero != "" --> don't allow zero value keys
- zero string
-
// unique determines whether this structKey supports
// multiple or just the singular unique result.
unique bool
@@ -135,47 +132,10 @@ type structKey struct {
pkeys map[string][]int64
}
-type structField struct {
- // index is the reflect index of this struct field.
- index int
-
- // mangle is the mangler function for
- // serializing values of this struct field.
- mangle mangler.Mangler
-}
-
-// genKey generates a cache key string for given key parts (i.e. serializes them using "go-mangler").
-func (sk *structKey) genKey(parts []any) string {
- // Check this expected no. key parts.
- if len(parts) != len(sk.fields) {
- panic(fmt.Sprintf("incorrect no. key parts provided: want=%d received=%d", len(parts), len(sk.fields)))
- }
-
- // Acquire byte buffer
- buf := getBuf()
- defer putBuf(buf)
- buf.Reset()
-
- // Encode each key part
- for i, part := range parts {
- buf.B = sk.fields[i].mangle(buf.B, part)
- buf.B = append(buf.B, '.')
- }
-
- // Drop last '.'
- buf.Truncate(1)
-
- // Return string copy
- return string(buf.B)
-}
-
// newStructKey will generate a structKey{} information object for user-given lookup
// key information, and the receiving generic paramter's type information. Panics on error.
func newStructKey(lk Lookup, t reflect.Type) structKey {
- var (
- sk structKey
- zeros []any
- )
+ var sk structKey
// Set the lookup name
sk.name = lk.Name
@@ -183,9 +143,6 @@ func newStructKey(lk Lookup, t reflect.Type) structKey {
// Split dot-separated lookup to get
// the individual struct field names
names := strings.Split(lk.Name, ".")
- if len(names) == 0 {
- panic("no key fields specified")
- }
// Allocate the mangler and field indices slice.
sk.fields = make([]structField, len(names))
@@ -213,16 +170,12 @@ func newStructKey(lk Lookup, t reflect.Type) structKey {
sk.fields[i].mangle = mangler.Get(ft.Type)
if !lk.AllowZero {
- // Append the zero value interface
- zeros = append(zeros, v.Interface())
+ // Append the mangled zero value interface
+ zero := sk.fields[i].mangle(nil, v.Interface())
+ sk.fields[i].zero = string(zero)
}
}
- if len(zeros) > 0 {
- // Generate zero value string
- sk.zero = sk.genKey(zeros)
- }
-
// Set unique lookup flag.
sk.unique = !lk.Multi
@@ -232,6 +185,68 @@ func newStructKey(lk Lookup, t reflect.Type) structKey {
return sk
}
+// genKey generates a cache key string for given key parts (i.e. serializes them using "go-mangler").
+func (sk *structKey) genKey(parts []any) string {
+ // Check this expected no. key parts.
+ if len(parts) != len(sk.fields) {
+ panic(fmt.Sprintf("incorrect no. key parts provided: want=%d received=%d", len(parts), len(sk.fields)))
+ }
+
+ // Acquire byte buffer
+ buf := getBuf()
+ defer putBuf(buf)
+ buf.Reset()
+
+ for i, part := range parts {
+ // Mangle this key part into buffer.
+ // specifically ignoring whether this
+ // is returning a zero value key part.
+ _ = sk.fields[i].manglePart(buf, part)
+
+ // Append part separator.
+ buf.B = append(buf.B, '.')
+ }
+
+ // Drop last '.'
+ buf.Truncate(1)
+
+ // Return string copy
+ return string(buf.B)
+}
+
+type structField struct {
+ // index is the reflect index of this struct field.
+ index int
+
+ // zero is the possible zero value for this
+ // key part. if set, this will _always_ be
+ // non-empty due to how the mangler works.
+ //
+ // i.e. zero = "" --> allow zero value keys
+ // zero != "" --> don't allow zero value keys
+ zero string
+
+ // mangle is the mangler function for
+ // serializing values of this struct field.
+ mangle mangler.Mangler
+}
+
+// manglePart ...
+func (field *structField) manglePart(buf *byteutil.Buffer, part any) bool {
+ // Start of part bytes.
+ start := len(buf.B)
+
+ // Mangle this key part into buffer.
+ buf.B = field.mangle(buf.B, part)
+
+ // End of part bytes.
+ end := len(buf.B)
+
+ // Return whether this is zero value.
+ return (field.zero == "" ||
+ string(buf.B[start:end]) != field.zero)
+}
+
// isExported checks whether function name is exported.
func isExported(fnName string) bool {
r, _ := utf8.DecodeRuneInString(fnName)
@@ -246,12 +261,12 @@ var bufPool = sync.Pool{
},
}
-// getBuf ...
+// getBuf acquires a byte buffer from memory pool.
func getBuf() *byteutil.Buffer {
return bufPool.Get().(*byteutil.Buffer)
}
-// putBuf ...
+// putBuf replaces a byte buffer back in memory pool.
func putBuf(buf *byteutil.Buffer) {
if buf.Cap() > int(^uint16(0)) {
return // drop large bufs
diff --git a/vendor/codeberg.org/gruf/go-cache/v3/simple/cache.go b/vendor/codeberg.org/gruf/go-cache/v3/simple/cache.go
index 0224871bc..1452a0648 100644
--- a/vendor/codeberg.org/gruf/go-cache/v3/simple/cache.go
+++ b/vendor/codeberg.org/gruf/go-cache/v3/simple/cache.go
@@ -102,7 +102,7 @@ func (c *Cache[K, V]) Add(key K, value V) bool {
}
// Alloc new entry.
- new := getEntry()
+ new := GetEntry()
new.Key = key
new.Value = value
@@ -111,7 +111,7 @@ func (c *Cache[K, V]) Add(key K, value V) bool {
evcK = item.Key.(K)
evcV = item.Value.(V)
ev = true
- putEntry(item)
+ PutEntry(item)
})
// Set hook func ptr.
@@ -161,7 +161,7 @@ func (c *Cache[K, V]) Set(key K, value V) {
item.Value = value
} else {
// Alloc new entry.
- new := getEntry()
+ new := GetEntry()
new.Key = key
new.Value = value
@@ -170,7 +170,7 @@ func (c *Cache[K, V]) Set(key K, value V) {
evcK = item.Key.(K)
evcV = item.Value.(V)
ev = true
- putEntry(item)
+ PutEntry(item)
})
}
@@ -311,7 +311,7 @@ func (c *Cache[K, V]) Invalidate(key K) (ok bool) {
_ = c.Cache.Delete(key)
// Free entry
- putEntry(item)
+ PutEntry(item)
// Set hook func ptrs.
invalid = c.Invalid
@@ -367,7 +367,7 @@ func (c *Cache[K, V]) InvalidateAll(keys ...K) (ok bool) {
invalid(k, v)
// Free this entry.
- putEntry(items[x])
+ PutEntry(items[x])
}
}
@@ -410,7 +410,7 @@ func (c *Cache[K, V]) Trim(perc float64) {
invalid(k, v)
// Free this entry.
- putEntry(items[x])
+ PutEntry(items[x])
}
}
}
@@ -438,7 +438,7 @@ func (c *Cache[K, V]) locked(fn func()) {
func (c *Cache[K, V]) truncate(sz int, hook func(K, V)) []*Entry {
if hook == nil {
// No hook to execute, simply release all truncated entries.
- c.Cache.Truncate(sz, func(_ K, item *Entry) { putEntry(item) })
+ c.Cache.Truncate(sz, func(_ K, item *Entry) { PutEntry(item) })
return nil
}
diff --git a/vendor/codeberg.org/gruf/go-cache/v3/simple/pool.go b/vendor/codeberg.org/gruf/go-cache/v3/simple/pool.go
index 2fc99ab0f..34ae17546 100644
--- a/vendor/codeberg.org/gruf/go-cache/v3/simple/pool.go
+++ b/vendor/codeberg.org/gruf/go-cache/v3/simple/pool.go
@@ -6,8 +6,8 @@ import "sync"
// objects, regardless of cache type.
var entryPool sync.Pool
-// getEntry fetches an Entry from pool, or allocates new.
-func getEntry() *Entry {
+// GetEntry fetches an Entry from pool, or allocates new.
+func GetEntry() *Entry {
v := entryPool.Get()
if v == nil {
return new(Entry)
@@ -15,8 +15,8 @@ func getEntry() *Entry {
return v.(*Entry)
}
-// putEntry replaces an Entry in the pool.
-func putEntry(e *Entry) {
+// PutEntry replaces an Entry in the pool.
+func PutEntry(e *Entry) {
e.Key = nil
e.Value = nil
entryPool.Put(e)