diff options
Diffstat (limited to 'vendor/codeberg.org/gruf/go-cache/v3/ttl/ttl.go')
-rw-r--r-- | vendor/codeberg.org/gruf/go-cache/v3/ttl/ttl.go | 636 |
1 files changed, 0 insertions, 636 deletions
diff --git a/vendor/codeberg.org/gruf/go-cache/v3/ttl/ttl.go b/vendor/codeberg.org/gruf/go-cache/v3/ttl/ttl.go deleted file mode 100644 index 106d675c8..000000000 --- a/vendor/codeberg.org/gruf/go-cache/v3/ttl/ttl.go +++ /dev/null @@ -1,636 +0,0 @@ -package ttl - -import ( - "sync" - "time" - _ "unsafe" - - "codeberg.org/gruf/go-maps" -) - -// Entry represents an item in the cache, with it's currently calculated Expiry time. -type Entry[Key comparable, Value any] struct { - Key Key - Value Value - Expiry uint64 -} - -// Cache is the underlying TTLCache implementation, providing both the base Cache interface and unsafe access to underlying map to allow flexibility in building your own. -type Cache[Key comparable, Value any] struct { - // TTL is the cache item TTL. - TTL time.Duration - - // Evict is the hook that is called when an item is evicted from the cache. - Evict func(Key, Value) - - // Invalid is the hook that is called when an item's data in the cache is invalidated, includes Add/Set. - Invalid func(Key, Value) - - // Cache is the underlying hashmap used for this cache. - Cache maps.LRUMap[Key, *Entry[Key, Value]] - - // stop is the eviction routine cancel func. - stop func() - - // pool is a memory pool of entry objects. - pool []*Entry[Key, Value] - - // Embedded mutex. - sync.Mutex -} - -// New returns a new initialized Cache with given initial length, maximum capacity and item TTL. -func New[K comparable, V any](len, cap int, ttl time.Duration) *Cache[K, V] { - c := new(Cache[K, V]) - c.Init(len, cap, ttl) - return c -} - -// Init will initialize this cache with given initial length, maximum capacity and item TTL. -func (c *Cache[K, V]) Init(len, cap int, ttl time.Duration) { - if ttl <= 0 { - // Default duration - ttl = time.Second * 5 - } - c.TTL = ttl - c.SetEvictionCallback(nil) - c.SetInvalidateCallback(nil) - c.Cache.Init(len, cap) -} - -// Start: implements cache.Cache's Start(). -func (c *Cache[K, V]) Start(freq time.Duration) (ok bool) { - // Nothing to start - if freq <= 0 { - return false - } - - // Safely start - c.Lock() - - if ok = (c.stop == nil); ok { - // Not yet running, schedule us - c.stop = schedule(c.Sweep, freq) - } - - // Done with lock - c.Unlock() - - return -} - -// Stop: implements cache.Cache's Stop(). -func (c *Cache[K, V]) Stop() (ok bool) { - // Safely stop - c.Lock() - - if ok = (c.stop != nil); ok { - // We're running, cancel evicts - c.stop() - c.stop = nil - } - - // Done with lock - c.Unlock() - - return -} - -// Sweep attempts to evict expired items (with callback!) from cache. -func (c *Cache[K, V]) Sweep(_ time.Time) { - var ( - // evicted key-values. - kvs []kv[K, V] - - // hook func ptrs. - evict func(K, V) - - // get current nanoseconds. - now = runtime_nanotime() - ) - - c.locked(func() { - if c.TTL <= 0 { - // sweep is - // disabled - return - } - - // Sentinel value - after := -1 - - // The cache will be ordered by expiry date, we iterate until we reach the index of - // the youngest item that hsa expired, as all succeeding items will also be expired. - c.Cache.RangeIf(0, c.Cache.Len(), func(i int, _ K, item *Entry[K, V]) bool { - if now > item.Expiry { - after = i - - // evict all older items - // than this (inclusive) - return false - } - - // cont. loop. - return true - }) - - if after == -1 { - // No Truncation needed - return - } - - // Set hook func ptr. - evict = c.Evict - - // Truncate determined size. - sz := c.Cache.Len() - after - kvs = c.truncate(sz, evict) - }) - - if evict != nil { - for x := range kvs { - // Pass to eviction hook. - evict(kvs[x].K, kvs[x].V) - } - } -} - -// SetEvictionCallback: implements cache.Cache's SetEvictionCallback(). -func (c *Cache[K, V]) SetEvictionCallback(hook func(K, V)) { - c.locked(func() { - c.Evict = hook - }) -} - -// SetInvalidateCallback: implements cache.Cache's SetInvalidateCallback(). -func (c *Cache[K, V]) SetInvalidateCallback(hook func(K, V)) { - c.locked(func() { - c.Invalid = hook - }) -} - -// SetTTL: implements cache.Cache's SetTTL(). -func (c *Cache[K, V]) SetTTL(ttl time.Duration, update bool) { - c.locked(func() { - // Set updated TTL - diff := ttl - c.TTL - c.TTL = ttl - - if update { - // Update existing cache entries with new expiry time - c.Cache.Range(0, c.Cache.Len(), func(i int, _ K, item *Entry[K, V]) { - item.Expiry += uint64(diff) - }) - } - }) -} - -// Get: implements cache.Cache's Get(). -func (c *Cache[K, V]) Get(key K) (V, bool) { - var ( - // did exist in cache? - ok bool - - // cached value. - v V - ) - - c.locked(func() { - var item *Entry[K, V] - - // Check for item in cache - item, ok = c.Cache.Get(key) - if !ok { - return - } - - // Update fetched's expiry - item.Expiry = c.expiry() - - // Set value. - v = item.Value - }) - - return v, ok -} - -// Add: implements cache.Cache's Add(). -func (c *Cache[K, V]) Add(key K, value V) bool { - var ( - // did exist in cache? - ok bool - - // was entry evicted? - ev bool - - // evicted key values. - evcK K - evcV V - - // hook func ptrs. - evict func(K, V) - ) - - c.locked(func() { - // Check if in cache. - ok = c.Cache.Has(key) - if ok { - return - } - - // Alloc new entry. - new := c.alloc() - new.Expiry = c.expiry() - new.Key = key - new.Value = value - - // Add new entry to cache and catched any evicted item. - c.Cache.SetWithHook(key, new, func(_ K, item *Entry[K, V]) { - evcK = item.Key - evcV = item.Value - ev = true - c.free(item) - }) - - // Set hook func ptr. - evict = c.Evict - }) - - if ev && evict != nil { - // Pass to eviction hook. - evict(evcK, evcV) - } - - return !ok -} - -// Set: implements cache.Cache's Set(). -func (c *Cache[K, V]) Set(key K, value V) { - var ( - // did exist in cache? - ok bool - - // was entry evicted? - ev bool - - // old value. - oldV V - - // evicted key values. - evcK K - evcV V - - // hook func ptrs. - invalid func(K, V) - evict func(K, V) - ) - - c.locked(func() { - var item *Entry[K, V] - - // Check for item in cache - item, ok = c.Cache.Get(key) - - if ok { - // Set old value. - oldV = item.Value - - // Update the existing item. - item.Expiry = c.expiry() - item.Value = value - } else { - // Alloc new entry. - new := c.alloc() - new.Expiry = c.expiry() - new.Key = key - new.Value = value - - // Add new entry to cache and catched any evicted item. - c.Cache.SetWithHook(key, new, func(_ K, item *Entry[K, V]) { - evcK = item.Key - evcV = item.Value - ev = true - c.free(item) - }) - } - - // Set hook func ptrs. - invalid = c.Invalid - evict = c.Evict - }) - - if ok && invalid != nil { - // Pass to invalidate hook. - invalid(key, oldV) - } - - if ev && evict != nil { - // Pass to eviction hook. - evict(evcK, evcV) - } -} - -// CAS: implements cache.Cache's CAS(). -func (c *Cache[K, V]) CAS(key K, old V, new V, cmp func(V, V) bool) bool { - var ( - // did exist in cache? - ok bool - - // swapped value. - oldV V - - // hook func ptrs. - invalid func(K, V) - ) - - c.locked(func() { - var item *Entry[K, V] - - // Check for item in cache - item, ok = c.Cache.Get(key) - if !ok { - return - } - - // Perform the comparison - if !cmp(old, item.Value) { - return - } - - // Set old value. - oldV = item.Value - - // Update value + expiry. - item.Expiry = c.expiry() - item.Value = new - - // Set hook func ptr. - invalid = c.Invalid - }) - - if ok && invalid != nil { - // Pass to invalidate hook. - invalid(key, oldV) - } - - return ok -} - -// Swap: implements cache.Cache's Swap(). -func (c *Cache[K, V]) Swap(key K, swp V) V { - var ( - // did exist in cache? - ok bool - - // swapped value. - oldV V - - // hook func ptrs. - invalid func(K, V) - ) - - c.locked(func() { - var item *Entry[K, V] - - // Check for item in cache - item, ok = c.Cache.Get(key) - if !ok { - return - } - - // Set old value. - oldV = item.Value - - // Update value + expiry. - item.Expiry = c.expiry() - item.Value = swp - - // Set hook func ptr. - invalid = c.Invalid - }) - - if ok && invalid != nil { - // Pass to invalidate hook. - invalid(key, oldV) - } - - return oldV -} - -// Has: implements cache.Cache's Has(). -func (c *Cache[K, V]) Has(key K) (ok bool) { - c.locked(func() { - ok = c.Cache.Has(key) - }) - return -} - -// Invalidate: implements cache.Cache's Invalidate(). -func (c *Cache[K, V]) Invalidate(key K) (ok bool) { - var ( - // old value. - oldV V - - // hook func ptrs. - invalid func(K, V) - ) - - c.locked(func() { - var item *Entry[K, V] - - // Check for item in cache - item, ok = c.Cache.Get(key) - if !ok { - return - } - - // Set old value. - oldV = item.Value - - // Remove from cache map - _ = c.Cache.Delete(key) - - // Free entry - c.free(item) - - // Set hook func ptrs. - invalid = c.Invalid - }) - - if ok && invalid != nil { - // Pass to invalidate hook. - invalid(key, oldV) - } - - return -} - -// InvalidateAll: implements cache.Cache's InvalidateAll(). -func (c *Cache[K, V]) InvalidateAll(keys ...K) (ok bool) { - var ( - // invalidated kvs. - kvs []kv[K, V] - - // hook func ptrs. - invalid func(K, V) - ) - - // Allocate a slice for invalidated. - kvs = make([]kv[K, V], 0, len(keys)) - - c.locked(func() { - for x := range keys { - var item *Entry[K, V] - - // Check for item in cache - item, ok = c.Cache.Get(keys[x]) - if !ok { - continue - } - - // Append this old value to slice - kvs = append(kvs, kv[K, V]{ - K: keys[x], - V: item.Value, - }) - - // Remove from cache map - _ = c.Cache.Delete(keys[x]) - - // Free entry - c.free(item) - } - - // Set hook func ptrs. - invalid = c.Invalid - }) - - if invalid != nil { - for x := range kvs { - // Pass to invalidate hook. - invalid(kvs[x].K, kvs[x].V) - } - } - - return -} - -// Clear: implements cache.Cache's Clear(). -func (c *Cache[K, V]) Clear() { - var ( - // deleted key-values. - kvs []kv[K, V] - - // hook func ptrs. - invalid func(K, V) - ) - - c.locked(func() { - // Set hook func ptr. - invalid = c.Invalid - - // Truncate the entire cache length. - kvs = c.truncate(c.Cache.Len(), invalid) - }) - - if invalid != nil { - for x := range kvs { - // Pass to invalidate hook. - invalid(kvs[x].K, kvs[x].V) - } - } -} - -// Len: implements cache.Cache's Len(). -func (c *Cache[K, V]) Len() (l int) { - c.locked(func() { l = c.Cache.Len() }) - return -} - -// Cap: implements cache.Cache's Cap(). -func (c *Cache[K, V]) Cap() (l int) { - c.locked(func() { l = c.Cache.Cap() }) - return -} - -// locked performs given function within mutex lock (NOTE: UNLOCK IS NOT DEFERRED). -func (c *Cache[K, V]) locked(fn func()) { - c.Lock() - fn() - c.Unlock() -} - -// truncate will truncate the cache by given size, returning deleted items. -func (c *Cache[K, V]) truncate(sz int, hook func(K, V)) []kv[K, V] { - if hook == nil { - // No hook to execute, simply free all truncated entries. - c.Cache.Truncate(sz, func(_ K, e *Entry[K, V]) { c.free(e) }) - return nil - } - - // Allocate a slice for deleted k-v pairs. - deleted := make([]kv[K, V], 0, sz) - - c.Cache.Truncate(sz, func(_ K, item *Entry[K, V]) { - // Store key-value pair for later access. - deleted = append(deleted, kv[K, V]{ - K: item.Key, - V: item.Value, - }) - - // Free entry. - c.free(item) - }) - - return deleted -} - -// alloc will acquire cache entry from pool, or allocate new. -func (c *Cache[K, V]) alloc() *Entry[K, V] { - if len(c.pool) == 0 { - return &Entry[K, V]{} - } - idx := len(c.pool) - 1 - e := c.pool[idx] - c.pool = c.pool[:idx] - return e -} - -// clone allocates a new Entry and copies all info from passed Entry. -func (c *Cache[K, V]) clone(e *Entry[K, V]) *Entry[K, V] { - e2 := c.alloc() - e2.Key = e.Key - e2.Value = e.Value - e2.Expiry = e.Expiry - return e2 -} - -// free will reset entry fields and place back in pool. -func (c *Cache[K, V]) free(e *Entry[K, V]) { - var ( - zk K - zv V - ) - e.Expiry = 0 - e.Key = zk - e.Value = zv - c.pool = append(c.pool, e) -} - -//go:linkname runtime_nanotime runtime.nanotime -func runtime_nanotime() uint64 - -// expiry returns an the next expiry time to use for an entry, -// which is equivalent to time.Now().Add(ttl), or zero if disabled. -func (c *Cache[K, V]) expiry() uint64 { - if ttl := c.TTL; ttl > 0 { - return runtime_nanotime() + - uint64(c.TTL) - } - return 0 -} - -type kv[K comparable, V any] struct { - K K - V V -} |