mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 20:22:25 -05:00 
			
		
		
		
	[chore] bump go-cache to v3.1.7 to fix possible issues with zero value keys (#1038)
Signed-off-by: kim <grufwub@gmail.com> Signed-off-by: kim <grufwub@gmail.com>
This commit is contained in:
		
					parent
					
						
							
								f7cde0dfa7
							
						
					
				
			
			
				commit
				
					
						e8c733da3f
					
				
			
		
					 6 changed files with 149 additions and 118 deletions
				
			
		
							
								
								
									
										2
									
								
								go.mod
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
										
									
									
									
								
							|  | @ -6,7 +6,7 @@ require ( | ||||||
| 	codeberg.org/gruf/go-bytesize v1.0.0 | 	codeberg.org/gruf/go-bytesize v1.0.0 | ||||||
| 	codeberg.org/gruf/go-byteutil v1.0.2 | 	codeberg.org/gruf/go-byteutil v1.0.2 | ||||||
| 	codeberg.org/gruf/go-cache/v2 v2.1.4 | 	codeberg.org/gruf/go-cache/v2 v2.1.4 | ||||||
| 	codeberg.org/gruf/go-cache/v3 v3.1.6 | 	codeberg.org/gruf/go-cache/v3 v3.1.7 | ||||||
| 	codeberg.org/gruf/go-debug v1.2.0 | 	codeberg.org/gruf/go-debug v1.2.0 | ||||||
| 	codeberg.org/gruf/go-errors/v2 v2.0.2 | 	codeberg.org/gruf/go-errors/v2 v2.0.2 | ||||||
| 	codeberg.org/gruf/go-kv v1.5.2 | 	codeberg.org/gruf/go-kv v1.5.2 | ||||||
|  |  | ||||||
							
								
								
									
										4
									
								
								go.sum
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
										
									
									
									
								
							|  | @ -71,8 +71,8 @@ codeberg.org/gruf/go-byteutil v1.0.2 h1:OesVyK5VKWeWdeDR00zRJ+Oy8hjXx1pBhn7WVvcZ | ||||||
| codeberg.org/gruf/go-byteutil v1.0.2/go.mod h1:cWM3tgMCroSzqoBXUXMhvxTxYJp+TbCr6ioISRY5vSU= | codeberg.org/gruf/go-byteutil v1.0.2/go.mod h1:cWM3tgMCroSzqoBXUXMhvxTxYJp+TbCr6ioISRY5vSU= | ||||||
| codeberg.org/gruf/go-cache/v2 v2.1.4 h1:r+6wJiTHZn0qqf+p1VtAjGOgXXJl7s8txhPIwoSMZtI= | codeberg.org/gruf/go-cache/v2 v2.1.4 h1:r+6wJiTHZn0qqf+p1VtAjGOgXXJl7s8txhPIwoSMZtI= | ||||||
| codeberg.org/gruf/go-cache/v2 v2.1.4/go.mod h1:j7teiz814lG0PfSfnUs+6HA+2/jcjTAR71Ou3Wbt2Xk= | codeberg.org/gruf/go-cache/v2 v2.1.4/go.mod h1:j7teiz814lG0PfSfnUs+6HA+2/jcjTAR71Ou3Wbt2Xk= | ||||||
| codeberg.org/gruf/go-cache/v3 v3.1.6 h1:LMpQoLRoGTH64WyLCew6wMVqC3Vzve09MCYbt5c0WR4= | codeberg.org/gruf/go-cache/v3 v3.1.7 h1:mWeLxh4CnIfBIbzxdCPlPsRjrernqIlFsMQdLQhUBMo= | ||||||
| codeberg.org/gruf/go-cache/v3 v3.1.6/go.mod h1:h6im2UVGdrGtNt4IVKARVeoW4kAdok5ts7CbH15UWXs= | codeberg.org/gruf/go-cache/v3 v3.1.7/go.mod h1:h6im2UVGdrGtNt4IVKARVeoW4kAdok5ts7CbH15UWXs= | ||||||
| codeberg.org/gruf/go-debug v1.2.0 h1:WBbTMnK1ArFKUmgv04aO2JiC/daTOB8zQGi521qb7OU= | codeberg.org/gruf/go-debug v1.2.0 h1:WBbTMnK1ArFKUmgv04aO2JiC/daTOB8zQGi521qb7OU= | ||||||
| codeberg.org/gruf/go-debug v1.2.0/go.mod h1:N+vSy9uJBQgpQcJUqjctvqFz7tBHJf+S/PIjLILzpLg= | codeberg.org/gruf/go-debug v1.2.0/go.mod h1:N+vSy9uJBQgpQcJUqjctvqFz7tBHJf+S/PIjLILzpLg= | ||||||
| codeberg.org/gruf/go-errors/v2 v2.0.0/go.mod h1:ZRhbdhvgoUA3Yw6e56kd9Ox984RrvbEFC2pOXyHDJP4= | codeberg.org/gruf/go-errors/v2 v2.0.0/go.mod h1:ZRhbdhvgoUA3Yw6e56kd9Ox984RrvbEFC2pOXyHDJP4= | ||||||
|  |  | ||||||
|  | @ -36,9 +36,9 @@ type tombstoneDB struct { | ||||||
| 
 | 
 | ||||||
| func (t *tombstoneDB) init() { | func (t *tombstoneDB) init() { | ||||||
| 	// Initialize tombstone result cache | 	// Initialize tombstone result cache | ||||||
| 	t.cache = result.NewSized([]string{ | 	t.cache = result.NewSized([]result.Lookup{ | ||||||
| 		"ID", | 		{Name: "ID"}, | ||||||
| 		"URI", | 		{Name: "URI"}, | ||||||
| 	}, func(t1 *gtsmodel.Tombstone) *gtsmodel.Tombstone { | 	}, func(t1 *gtsmodel.Tombstone) *gtsmodel.Tombstone { | ||||||
| 		t2 := new(gtsmodel.Tombstone) | 		t2 := new(gtsmodel.Tombstone) | ||||||
| 		*t2 = *t1 | 		*t2 = *t1 | ||||||
|  |  | ||||||
							
								
								
									
										99
									
								
								vendor/codeberg.org/gruf/go-cache/v3/result/cache.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										99
									
								
								vendor/codeberg.org/gruf/go-cache/v3/result/cache.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -7,7 +7,20 @@ import ( | ||||||
| 	"codeberg.org/gruf/go-cache/v3/ttl" | 	"codeberg.org/gruf/go-cache/v3/ttl" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Cache ... | // Lookup represents a struct object lookup method in the cache. | ||||||
|  | type Lookup struct { | ||||||
|  | 	// Name is a period ('.') separated string | ||||||
|  | 	// of struct fields this Key encompasses. | ||||||
|  | 	Name string | ||||||
|  | 
 | ||||||
|  | 	// AllowZero indicates whether to accept and cache | ||||||
|  | 	// under zero value keys, otherwise ignore them. | ||||||
|  | 	AllowZero bool | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Cache provides a means of caching value structures, along with | ||||||
|  | // the results of attempting to load them. An example usecase of this | ||||||
|  | // cache would be in wrapping a database, allowing caching of sql.ErrNoRows. | ||||||
| type Cache[Value any] struct { | type Cache[Value any] struct { | ||||||
| 	cache   ttl.Cache[int64, result[Value]] // underlying result cache | 	cache   ttl.Cache[int64, result[Value]] // underlying result cache | ||||||
| 	lookups structKeys                      // pre-determined struct lookups | 	lookups structKeys                      // pre-determined struct lookups | ||||||
|  | @ -16,12 +29,12 @@ type Cache[Value any] struct { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // New returns a new initialized Cache, with given lookups and underlying value copy function. | // New returns a new initialized Cache, with given lookups and underlying value copy function. | ||||||
| func New[Value any](lookups []string, copy func(Value) Value) *Cache[Value] { | func New[Value any](lookups []Lookup, copy func(Value) Value) *Cache[Value] { | ||||||
| 	return NewSized(lookups, copy, 64) | 	return NewSized(lookups, copy, 64) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewSized returns a new initialized Cache, with given lookups, underlying value copy function and provided capacity. | // NewSized returns a new initialized Cache, with given lookups, underlying value copy function and provided capacity. | ||||||
| func NewSized[Value any](lookups []string, copy func(Value) Value, cap int) *Cache[Value] { | func NewSized[Value any](lookups []Lookup, copy func(Value) Value, cap int) *Cache[Value] { | ||||||
| 	var z Value | 	var z Value | ||||||
| 
 | 
 | ||||||
| 	// Determine generic type | 	// Determine generic type | ||||||
|  | @ -39,13 +52,11 @@ func NewSized[Value any](lookups []string, copy func(Value) Value, cap int) *Cac | ||||||
| 
 | 
 | ||||||
| 	// Allocate new cache object | 	// Allocate new cache object | ||||||
| 	c := &Cache[Value]{copy: copy} | 	c := &Cache[Value]{copy: copy} | ||||||
| 	c.lookups = make([]keyFields, len(lookups)) | 	c.lookups = make([]structKey, len(lookups)) | ||||||
| 
 | 
 | ||||||
| 	for i, lookup := range lookups { | 	for i, lookup := range lookups { | ||||||
| 		// Generate keyed field info for lookup | 		// Generate keyed field info for lookup | ||||||
| 		c.lookups[i].pkeys = make(map[string]int64, cap) | 		c.lookups[i] = genStructKey(lookup, t) | ||||||
| 		c.lookups[i].lookup = lookup |  | ||||||
| 		c.lookups[i].populate(t) |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Create and initialize underlying cache | 	// Create and initialize underlying cache | ||||||
|  | @ -82,7 +93,7 @@ func (c *Cache[Value]) SetEvictionCallback(hook func(Value)) { | ||||||
| 	c.cache.SetEvictionCallback(func(item *ttl.Entry[int64, result[Value]]) { | 	c.cache.SetEvictionCallback(func(item *ttl.Entry[int64, result[Value]]) { | ||||||
| 		for _, key := range item.Value.Keys { | 		for _, key := range item.Value.Keys { | ||||||
| 			// Delete key->pkey lookup | 			// Delete key->pkey lookup | ||||||
| 			pkeys := key.fields.pkeys | 			pkeys := key.key.pkeys | ||||||
| 			delete(pkeys, key.value) | 			delete(pkeys, key.value) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -104,12 +115,10 @@ func (c *Cache[Value]) SetInvalidateCallback(hook func(Value)) { | ||||||
| 	} | 	} | ||||||
| 	c.cache.SetInvalidateCallback(func(item *ttl.Entry[int64, result[Value]]) { | 	c.cache.SetInvalidateCallback(func(item *ttl.Entry[int64, result[Value]]) { | ||||||
| 		for _, key := range item.Value.Keys { | 		for _, key := range item.Value.Keys { | ||||||
| 			if key.fields != nil { |  | ||||||
| 			// Delete key->pkey lookup | 			// Delete key->pkey lookup | ||||||
| 				pkeys := key.fields.pkeys | 			pkeys := key.key.pkeys | ||||||
| 			delete(pkeys, key.value) | 			delete(pkeys, key.value) | ||||||
| 		} | 		} | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		if item.Value.Error != nil { | 		if item.Value.Error != nil { | ||||||
| 			// Skip error hooks | 			// Skip error hooks | ||||||
|  | @ -121,25 +130,24 @@ func (c *Cache[Value]) SetInvalidateCallback(hook func(Value)) { | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Load ... | // Load will attempt to load an existing result from the cacche for the given lookup and key parts, else calling the load function and caching that result. | ||||||
| func (c *Cache[Value]) Load(lookup string, load func() (Value, error), keyParts ...any) (Value, error) { | func (c *Cache[Value]) Load(lookup string, load func() (Value, error), keyParts ...any) (Value, error) { | ||||||
| 	var ( | 	var ( | ||||||
| 		zero Value | 		zero Value | ||||||
| 		res  result[Value] | 		res  result[Value] | ||||||
| 	) | 	) | ||||||
| 
 | 
 | ||||||
| 	// Get lookup map by name. | 	// Get lookup key info by name. | ||||||
| 	kfields := c.getFields(lookup) | 	keyInfo := c.lookups.get(lookup) | ||||||
| 	lmap := kfields.pkeys |  | ||||||
| 
 | 
 | ||||||
| 	// Generate cache key string. | 	// Generate cache key string. | ||||||
| 	ckey := genkey(keyParts...) | 	ckey := genKey(keyParts...) | ||||||
| 
 | 
 | ||||||
| 	// Acquire cache lock | 	// Acquire cache lock | ||||||
| 	c.cache.Lock() | 	c.cache.Lock() | ||||||
| 
 | 
 | ||||||
| 	// Look for primary key | 	// Look for primary key for cache key | ||||||
| 	pkey, ok := lmap[ckey] | 	pkey, ok := keyInfo.pkeys[ckey] | ||||||
| 
 | 
 | ||||||
| 	if ok { | 	if ok { | ||||||
| 		// Fetch the result for primary key | 		// Fetch the result for primary key | ||||||
|  | @ -157,9 +165,9 @@ func (c *Cache[Value]) Load(lookup string, load func() (Value, error), keyParts | ||||||
| 		if res.Error != nil { | 		if res.Error != nil { | ||||||
| 			// This load returned an error, only | 			// This load returned an error, only | ||||||
| 			// store this item under provided key. | 			// store this item under provided key. | ||||||
| 			res.Keys = []cacheKey{{ | 			res.Keys = []cachedKey{{ | ||||||
|  | 				key:   keyInfo, | ||||||
| 				value: ckey, | 				value: ckey, | ||||||
| 				fields: kfields, |  | ||||||
| 			}} | 			}} | ||||||
| 		} else { | 		} else { | ||||||
| 			// This was a successful load, generate keys. | 			// This was a successful load, generate keys. | ||||||
|  | @ -185,7 +193,7 @@ func (c *Cache[Value]) Load(lookup string, load func() (Value, error), keyParts | ||||||
| 	return c.copy(res.Value), nil | 	return c.copy(res.Value), nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Store ... | // Store will call the given store function, and on success store the value in the cache as a positive result. | ||||||
| func (c *Cache[Value]) Store(value Value, store func() error) error { | func (c *Cache[Value]) Store(value Value, store func() error) error { | ||||||
| 	// Attempt to store this value. | 	// Attempt to store this value. | ||||||
| 	if err := store(); err != nil { | 	if err := store(); err != nil { | ||||||
|  | @ -212,22 +220,21 @@ func (c *Cache[Value]) Store(value Value, store func() error) error { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Has ... | // Has checks the cache for a positive result under the given lookup and key parts. | ||||||
| func (c *Cache[Value]) Has(lookup string, keyParts ...any) bool { | func (c *Cache[Value]) Has(lookup string, keyParts ...any) bool { | ||||||
| 	var res result[Value] | 	var res result[Value] | ||||||
| 
 | 
 | ||||||
| 	// Get lookup map by name. | 	// Get lookup key type by name. | ||||||
| 	kfields := c.getFields(lookup) | 	keyType := c.lookups.get(lookup) | ||||||
| 	lmap := kfields.pkeys |  | ||||||
| 
 | 
 | ||||||
| 	// Generate cache key string. | 	// Generate cache key string. | ||||||
| 	ckey := genkey(keyParts...) | 	ckey := genKey(keyParts...) | ||||||
| 
 | 
 | ||||||
| 	// Acquire cache lock | 	// Acquire cache lock | ||||||
| 	c.cache.Lock() | 	c.cache.Lock() | ||||||
| 
 | 
 | ||||||
| 	// Look for primary key | 	// Look for primary key for cache key | ||||||
| 	pkey, ok := lmap[ckey] | 	pkey, ok := keyType.pkeys[ckey] | ||||||
| 
 | 
 | ||||||
| 	if ok { | 	if ok { | ||||||
| 		// Fetch the result for primary key | 		// Fetch the result for primary key | ||||||
|  | @ -242,18 +249,17 @@ func (c *Cache[Value]) Has(lookup string, keyParts ...any) bool { | ||||||
| 	return ok && (res.Error == nil) | 	return ok && (res.Error == nil) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Invalidate ... | // Invalidate will invalidate any result from the cache found under given lookup and key parts. | ||||||
| func (c *Cache[Value]) Invalidate(lookup string, keyParts ...any) { | func (c *Cache[Value]) Invalidate(lookup string, keyParts ...any) { | ||||||
| 	// Get lookup map by name. | 	// Get lookup key type by name. | ||||||
| 	kfields := c.getFields(lookup) | 	keyType := c.lookups.get(lookup) | ||||||
| 	lmap := kfields.pkeys |  | ||||||
| 
 | 
 | ||||||
| 	// Generate cache key string. | 	// Generate cache key string. | ||||||
| 	ckey := genkey(keyParts...) | 	ckey := genKey(keyParts...) | ||||||
| 
 | 
 | ||||||
| 	// Look for primary key | 	// Look for primary key for cache key | ||||||
| 	c.cache.Lock() | 	c.cache.Lock() | ||||||
| 	pkey, ok := lmap[ckey] | 	pkey, ok := keyType.pkeys[ckey] | ||||||
| 	c.cache.Unlock() | 	c.cache.Unlock() | ||||||
| 
 | 
 | ||||||
| 	if !ok { | 	if !ok { | ||||||
|  | @ -269,29 +275,19 @@ func (c *Cache[Value]) Clear() { | ||||||
| 	c.cache.Clear() | 	c.cache.Clear() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Len ... | // Len returns the current length of the cache. | ||||||
| func (c *Cache[Value]) Len() int { | func (c *Cache[Value]) Len() int { | ||||||
| 	return c.cache.Cache.Len() | 	return c.cache.Cache.Len() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Cap ... | // Cap returns the maximum capacity of this result cache. | ||||||
| func (c *Cache[Value]) Cap() int { | func (c *Cache[Value]) Cap() int { | ||||||
| 	return c.cache.Cache.Cap() | 	return c.cache.Cache.Cap() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Cache[Value]) getFields(name string) *keyFields { |  | ||||||
| 	for _, k := range c.lookups { |  | ||||||
| 		// Find key fields with name |  | ||||||
| 		if k.lookup == name { |  | ||||||
| 			return &k |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	panic("invalid lookup: " + name) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (c *Cache[Value]) storeResult(res result[Value]) (string, bool) { | func (c *Cache[Value]) storeResult(res result[Value]) (string, bool) { | ||||||
| 	for _, key := range res.Keys { | 	for _, key := range res.Keys { | ||||||
| 		pkeys := key.fields.pkeys | 		pkeys := key.key.pkeys | ||||||
| 
 | 
 | ||||||
| 		// Look for cache primary key | 		// Look for cache primary key | ||||||
| 		pkey, ok := pkeys[key.value] | 		pkey, ok := pkeys[key.value] | ||||||
|  | @ -304,6 +300,9 @@ func (c *Cache[Value]) storeResult(res result[Value]) (string, bool) { | ||||||
| 			if entry.Value.Error == nil { | 			if entry.Value.Error == nil { | ||||||
| 				return key.value, false | 				return key.value, false | ||||||
| 			} | 			} | ||||||
|  | 
 | ||||||
|  | 			// Delete existing error result | ||||||
|  | 			c.cache.Cache.Delete(pkey) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -313,7 +312,7 @@ func (c *Cache[Value]) storeResult(res result[Value]) (string, bool) { | ||||||
| 
 | 
 | ||||||
| 	// Store all primary key lookups | 	// Store all primary key lookups | ||||||
| 	for _, key := range res.Keys { | 	for _, key := range res.Keys { | ||||||
| 		pkeys := key.fields.pkeys | 		pkeys := key.key.pkeys | ||||||
| 		pkeys[key.value] = pkey | 		pkeys[key.value] = pkey | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -331,7 +330,7 @@ func (c *Cache[Value]) storeResult(res result[Value]) (string, bool) { | ||||||
| 
 | 
 | ||||||
| type result[Value any] struct { | type result[Value any] struct { | ||||||
| 	// keys accessible under | 	// keys accessible under | ||||||
| 	Keys []cacheKey | 	Keys []cachedKey | ||||||
| 
 | 
 | ||||||
| 	// cached value | 	// cached value | ||||||
| 	Value Value | 	Value Value | ||||||
|  |  | ||||||
							
								
								
									
										148
									
								
								vendor/codeberg.org/gruf/go-cache/v3/result/key.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										148
									
								
								vendor/codeberg.org/gruf/go-cache/v3/result/key.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -12,22 +12,24 @@ import ( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // structKeys provides convience methods for a list | // structKeys provides convience methods for a list | ||||||
| // of struct field combinations used for cache keys. | // of structKey field combinations used for cache keys. | ||||||
| type structKeys []keyFields | type structKeys []structKey | ||||||
| 
 | 
 | ||||||
| // get fetches the key-fields for given lookup (else, panics). | // get fetches the structKey info for given lookup name (else, panics). | ||||||
| func (sk structKeys) get(lookup string) *keyFields { | func (sk structKeys) get(name string) *structKey { | ||||||
| 	for i := range sk { | 	for i := range sk { | ||||||
| 		if sk[i].lookup == lookup { | 		if sk[i].name == name { | ||||||
| 			return &sk[i] | 			return &sk[i] | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	panic("unknown lookup: \"" + lookup + "\"") | 	panic("unknown lookup: \"" + name + "\"") | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // generate will calculate the value string for each required | // generate will calculate and produce a slice of cache keys the given value | ||||||
| // cache key as laid-out by the receiving structKeys{}. | // can be stored under in the, as determined by receiving struct keys. | ||||||
| func (sk structKeys) generate(a any) []cacheKey { | func (sk structKeys) generate(a any) []cachedKey { | ||||||
|  | 	var keys []cachedKey | ||||||
|  | 
 | ||||||
| 	// Get reflected value in order | 	// Get reflected value in order | ||||||
| 	// to access the struct fields | 	// to access the struct fields | ||||||
| 	v := reflect.ValueOf(a) | 	v := reflect.ValueOf(a) | ||||||
|  | @ -40,9 +42,6 @@ func (sk structKeys) generate(a any) []cacheKey { | ||||||
| 		v = v.Elem() | 		v = v.Elem() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Preallocate expected slice of keys |  | ||||||
| 	keys := make([]cacheKey, len(sk)) |  | ||||||
| 
 |  | ||||||
| 	// Acquire byte buffer | 	// Acquire byte buffer | ||||||
| 	buf := bufpool.Get().(*byteutil.Buffer) | 	buf := bufpool.Get().(*byteutil.Buffer) | ||||||
| 	defer bufpool.Put(buf) | 	defer bufpool.Put(buf) | ||||||
|  | @ -51,33 +50,8 @@ func (sk structKeys) generate(a any) []cacheKey { | ||||||
| 		// Reset buffer | 		// Reset buffer | ||||||
| 		buf.B = buf.B[:0] | 		buf.B = buf.B[:0] | ||||||
| 
 | 
 | ||||||
| 		// Set the key-fields reference |  | ||||||
| 		keys[i].fields = &sk[i] |  | ||||||
| 
 |  | ||||||
| 		// Calculate cache-key value |  | ||||||
| 		keys[i].populate(buf, v) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return keys |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // cacheKey represents an actual cache key. |  | ||||||
| type cacheKey struct { |  | ||||||
| 	// value is the actual string representing |  | ||||||
| 	// this cache key for hashmap lookups. |  | ||||||
| 	value string |  | ||||||
| 
 |  | ||||||
| 	// fieldsRO is a read-only slice (i.e. we should |  | ||||||
| 	// NOT be modifying them, only using for reference) |  | ||||||
| 	// of struct fields encapsulated by this cache key. |  | ||||||
| 	fields *keyFields |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // populate will calculate the cache key's value string for given |  | ||||||
| // value's reflected information. Passed encoder is for string building. |  | ||||||
| func (k *cacheKey) populate(buf *byteutil.Buffer, v reflect.Value) { |  | ||||||
| 		// Append each field value to buffer. | 		// Append each field value to buffer. | ||||||
| 	for _, idx := range k.fields.fields { | 		for _, idx := range sk[i].fields { | ||||||
| 			fv := v.Field(idx) | 			fv := v.Field(idx) | ||||||
| 			fi := fv.Interface() | 			fi := fv.Interface() | ||||||
| 			buf.B = mangler.Append(buf.B, fi) | 			buf.B = mangler.Append(buf.B, fi) | ||||||
|  | @ -87,18 +61,52 @@ func (k *cacheKey) populate(buf *byteutil.Buffer, v reflect.Value) { | ||||||
| 		// Drop last '.' | 		// Drop last '.' | ||||||
| 		buf.Truncate(1) | 		buf.Truncate(1) | ||||||
| 
 | 
 | ||||||
| 	// Create string copy from buf | 		// Don't generate keys for zero values | ||||||
| 	k.value = string(buf.B) | 		if allowZero := sk[i].zero == ""; // nocollapse | ||||||
|  | 		!allowZero && buf.String() == sk[i].zero { | ||||||
|  | 			continue | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| // keyFields represents a list of struct fields | 		// Append new cached key to slice | ||||||
| // encompassed in a single cache key, the string name | 		keys = append(keys, cachedKey{ | ||||||
| // of the lookup, and the lookup map to primary keys. | 			key:   &sk[i], | ||||||
| type keyFields struct { | 			value: string(buf.B), // copy | ||||||
| 	// lookup is the calculated (well, provided) | 		}) | ||||||
| 	// cache key lookup, consisting of dot sep'd | 	} | ||||||
| 	// struct field names. | 
 | ||||||
| 	lookup string | 	return keys | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // cachedKey represents an actual cached key. | ||||||
|  | type cachedKey struct { | ||||||
|  | 	// key is a reference to the structKey this | ||||||
|  | 	// cacheKey is representing. This is a shared | ||||||
|  | 	// reference and as such only the structKey.pkeys | ||||||
|  | 	// lookup map is expecting to be modified. | ||||||
|  | 	key *structKey | ||||||
|  | 
 | ||||||
|  | 	// value is the actual string representing | ||||||
|  | 	// this cache key for hashmap lookups. | ||||||
|  | 	value string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // structKey represents a list of struct fields | ||||||
|  | // encompassing a single cache key, the string name | ||||||
|  | // of the lookup, the lookup map to primary cache | ||||||
|  | // keys, and the key's possible zero value string. | ||||||
|  | type structKey struct { | ||||||
|  | 	// name is the provided cache lookup name for | ||||||
|  | 	// this particular struct key, consisting of | ||||||
|  | 	// 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 | ||||||
| 
 | 
 | ||||||
| 	// fields is a slice of runtime struct field | 	// fields is a slice of runtime struct field | ||||||
| 	// indices, of the fields encompassed by this key. | 	// indices, of the fields encompassed by this key. | ||||||
|  | @ -109,19 +117,20 @@ type keyFields struct { | ||||||
| 	pkeys map[string]int64 | 	pkeys map[string]int64 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // populate will populate this keyFields{} object's .fields member by determining | // genStructKey will generate a structKey{} information object for user-given lookup | ||||||
| // the field names from the given lookup, and querying given reflected type to get | // key information, and the receiving generic paramter's type information. Panics on error. | ||||||
| // the runtime field indices for each of the fields. this speeds-up future value lookups. | func genStructKey(lk Lookup, t reflect.Type) structKey { | ||||||
| func (kf *keyFields) populate(t reflect.Type) { | 	var zeros []any | ||||||
|  | 
 | ||||||
| 	// Split dot-separated lookup to get | 	// Split dot-separated lookup to get | ||||||
| 	// the individual struct field names | 	// the individual struct field names | ||||||
| 	names := strings.Split(kf.lookup, ".") | 	names := strings.Split(lk.Name, ".") | ||||||
| 	if len(names) == 0 { | 	if len(names) == 0 { | ||||||
| 		panic("no key fields specified") | 		panic("no key fields specified") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Pre-allocate slice of expected length | 	// Pre-allocate slice of expected length | ||||||
| 	kf.fields = make([]int, len(names)) | 	fields := make([]int, len(names)) | ||||||
| 
 | 
 | ||||||
| 	for i, name := range names { | 	for i, name := range names { | ||||||
| 		// Get field info for given name | 		// Get field info for given name | ||||||
|  | @ -136,13 +145,36 @@ func (kf *keyFields) populate(t reflect.Type) { | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// Set the runtime field index | 		// Set the runtime field index | ||||||
| 		kf.fields[i] = ft.Index[0] | 		fields[i] = ft.Index[0] | ||||||
|  | 
 | ||||||
|  | 		// Allocate new instance of field | ||||||
|  | 		v := reflect.New(ft.Type) | ||||||
|  | 		v = v.Elem() | ||||||
|  | 
 | ||||||
|  | 		if !lk.AllowZero { | ||||||
|  | 			// Append the zero value interface | ||||||
|  | 			zeros = append(zeros, v.Interface()) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| // genkey generates a cache key for given key values. | 	var zvalue string | ||||||
| func genkey(parts ...any) string { | 
 | ||||||
| 	if len(parts) < 1 { | 	if len(zeros) > 0 { | ||||||
|  | 		// Generate zero value string | ||||||
|  | 		zvalue = genKey(zeros...) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return structKey{ | ||||||
|  | 		name:   lk.Name, | ||||||
|  | 		zero:   zvalue, | ||||||
|  | 		fields: fields, | ||||||
|  | 		pkeys:  make(map[string]int64), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // genKey generates a cache key for given key values. | ||||||
|  | func genKey(parts ...any) string { | ||||||
|  | 	if len(parts) == 0 { | ||||||
| 		// Panic to prevent annoying usecase | 		// Panic to prevent annoying usecase | ||||||
| 		// where user forgets to pass lookup | 		// where user forgets to pass lookup | ||||||
| 		// and instead only passes a key part, | 		// and instead only passes a key part, | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								vendor/modules.txt
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/modules.txt
									
										
									
									
										vendored
									
									
								
							|  | @ -16,7 +16,7 @@ codeberg.org/gruf/go-byteutil | ||||||
| # codeberg.org/gruf/go-cache/v2 v2.1.4 | # codeberg.org/gruf/go-cache/v2 v2.1.4 | ||||||
| ## explicit; go 1.19 | ## explicit; go 1.19 | ||||||
| codeberg.org/gruf/go-cache/v2 | codeberg.org/gruf/go-cache/v2 | ||||||
| # codeberg.org/gruf/go-cache/v3 v3.1.6 | # codeberg.org/gruf/go-cache/v3 v3.1.7 | ||||||
| ## explicit; go 1.19 | ## explicit; go 1.19 | ||||||
| codeberg.org/gruf/go-cache/v3/result | codeberg.org/gruf/go-cache/v3/result | ||||||
| codeberg.org/gruf/go-cache/v3/ttl | codeberg.org/gruf/go-cache/v3/ttl | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue