diff options
author | 2023-08-04 12:28:33 +0100 | |
---|---|---|
committer | 2023-08-04 12:28:33 +0100 | |
commit | 9a291dea843448f78b4b98ea6813739aebe708c6 (patch) | |
tree | f1ce643a3c9fe1b13e4c107f15b1ac4b20fe5b86 /vendor/codeberg.org | |
parent | [feature] simpler cache size configuration (#2051) (diff) | |
download | gotosocial-9a291dea843448f78b4b98ea6813739aebe708c6.tar.xz |
[performance] add caching of status fave, boost of, in reply to ID lists (#2060)
Diffstat (limited to 'vendor/codeberg.org')
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) |