cache/cache.go

103 lines
1.9 KiB
Go
Raw Normal View History

2021-11-19 13:21:46 +01:00
// Package cache defines an in-memory key-value store.
//
2025-01-17 10:33:39 +01:00
// It supports exîration dates and can store arbitrary values of any type.
2021-11-19 13:21:46 +01:00
// Keys must be strings.
2025-01-18 00:55:00 +01:00
//
// Cache values are safe to share between goroutines.
2021-11-19 13:21:46 +01:00
package cache
import (
"sync"
"time"
)
2025-01-18 00:55:00 +01:00
type entry[V any] struct {
2025-01-17 10:33:39 +01:00
expirationDate *time.Time
2025-01-18 00:55:00 +01:00
value V
}
func (e entry[V]) isExpired() bool {
return e.expirationDate != nil && e.expirationDate.Before(time.Now())
2021-11-19 13:21:46 +01:00
}
// Cache is an in-memory key-value store.
2025-01-18 00:55:00 +01:00
type Cache[K comparable, V any] struct {
data map[K]entry[V]
2025-01-18 01:37:41 +01:00
mu sync.RWMutex
2021-11-19 13:21:46 +01:00
}
// New instantiate a new cache.
2025-01-18 00:55:00 +01:00
func New[K comparable, V any]() *Cache[K, V] {
return &Cache[K, V]{
data: make(map[K]entry[V]),
2021-11-19 13:21:46 +01:00
}
}
// Put stores a value in the cache under the given key.
2025-01-18 00:55:00 +01:00
func (c *Cache[K, V]) Put(key K, val V) {
2021-11-19 13:21:46 +01:00
c.mu.Lock()
defer c.mu.Unlock()
2025-01-18 00:55:00 +01:00
c.data[key] = entry[V]{nil, val}
2021-11-19 13:21:46 +01:00
}
// PutTTL stores a value in the cache under the given key. The value will
// be expired after the given ttl.
//
// A 0 ttl value disables the expiration of the value.
2025-01-18 00:55:00 +01:00
func (c *Cache[K, V]) PutTTL(key K, val V, ttl time.Duration) {
2021-11-19 13:21:46 +01:00
if ttl == 0 {
2025-01-18 00:55:00 +01:00
c.Put(key, val)
return
2021-11-19 13:21:46 +01:00
}
2025-01-18 00:55:00 +01:00
exp := time.Now().Add(ttl)
2021-11-19 13:21:46 +01:00
2025-01-18 01:37:41 +01:00
c.mu.Lock()
defer c.mu.Unlock()
2025-01-18 00:55:00 +01:00
c.data[key] = entry[V]{&exp, val}
2021-11-19 13:21:46 +01:00
}
// Get returns the value asspciated with the given key.
// The second return values indicates if the cache hs been hit or not.
2025-01-18 00:55:00 +01:00
func (c *Cache[K, V]) Get(key K) (V, bool) {
2021-11-19 13:21:46 +01:00
c.mu.RLock()
2025-01-18 00:55:00 +01:00
entry, ok := c.data[key]
2021-11-19 13:21:46 +01:00
c.mu.RUnlock()
if !ok {
2025-01-18 00:55:00 +01:00
var t V
return t, false
2021-11-19 13:21:46 +01:00
}
2025-01-18 00:55:00 +01:00
if entry.isExpired() {
2021-11-19 13:21:46 +01:00
c.Del(key)
2025-01-18 00:55:00 +01:00
var t V
return t, false
2021-11-19 13:21:46 +01:00
}
2025-01-18 00:55:00 +01:00
return entry.value, ok
2021-11-19 13:21:46 +01:00
}
2025-01-18 00:55:00 +01:00
// Del deletes the entry for the given key.
2021-11-19 13:21:46 +01:00
// It does not fail if the key does not exist.
2025-01-18 00:55:00 +01:00
func (c *Cache[K, V]) Del(key K) {
2021-11-19 13:21:46 +01:00
c.mu.Lock()
defer c.mu.Unlock()
delete(c.data, key)
}
// Count returns the total number of entries in the cache (vamid and expired).
2025-01-18 00:55:00 +01:00
func (c *Cache[K, V]) Count() int {
2021-11-19 13:21:46 +01:00
c.mu.RLock()
defer c.mu.RUnlock()
return len(c.data)
}