Package cache contains caching functions.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

130 lines
2.9 KiB

// Package cache contains caching functions
package cache
import "time"
// Cache describes an interface for storing arbitrary key/value pairs. Structs
// implementing the Cache interface should have a configurable Backend.
type Cache interface {
// Len returns the number of unique keys in the cache
Len() int
// Contains if the item is found in the cache
Contains(key interface{}) (bool, error)
// Get an item from the cache
Get(key interface{}) (interface{}, bool, error)
// Set an item in the cache
Set(key, value interface{}) error
// RunGC runs garbage collection on the cache
RunGC()
}
// SimpleCache is a cache without any additional features.
type SimpleCache struct {
Backend
}
// NewCache returns a simple cache without expiration. By default the MemoryKV
// backend is used.
func NewCache() *SimpleCache {
return &SimpleCache{NewMemoryKV()}
}
func (c *SimpleCache) RunGC() {}
// TTLCache is a cache with values that can expire.
type TTLCache struct {
Backend Backend
TTL time.Duration
gc *GC
}
// NewTTLCache runs with a timed garbage collector that runs at the selected
// interval. By default the MemoryKV backend is used.
func NewTTLCache(ttl, purge time.Duration) *TTLCache {
c := &TTLCache{
Backend: NewMemoryKV(),
TTL: ttl,
}
c.gc = NewGC(purge, c)
go c.gc.Run()
return c
}
// TTLCacheItem is a single cached item.
type TTLCacheItem struct {
Value interface{}
Expire int64
}
// Contains checks if a key is contained in the cache and if it hasn't expired.
func (c *TTLCache) Contains(key interface{}) (bool, error) {
if item, ok, err := c.Backend.Get(key); err != nil {
return false, err
} else if ok {
now := time.Now().Unix()
if item.(*TTLCacheItem).Expire > now {
return true, nil
}
if _, err = c.Backend.Delete(key); err != nil {
return true, err
}
}
return false, nil
}
// Get a value from the cache.
func (c *TTLCache) Get(key interface{}) (interface{}, bool, error) {
if item, ok, err := c.Backend.Get(key); err != nil {
return nil, false, err
} else if ok {
now := time.Now().Unix()
if item.(*TTLCacheItem).Expire > now {
return item.(*TTLCacheItem).Value, true, nil
}
if _, err = c.Backend.Delete(key); err != nil {
return nil, false, err
}
}
return nil, false, nil
}
// Len is the number of cached entries, it does not check if the keys are
// expired.
func (c *TTLCache) Len() int {
return c.Backend.Len()
}
// Set a key-value pair.
func (c *TTLCache) Set(key, value interface{}) error {
return c.Backend.Set(key, &TTLCacheItem{
Value: value,
Expire: time.Now().Add(c.TTL).Unix(),
})
}
// Stop the GC process.
func (c *TTLCache) Stop() {
if c.gc != nil {
c.gc.Stop()
}
}
// RunGC removes expired entries from the cache.
func (c *TTLCache) RunGC() {
now := time.Now().Unix()
c.Backend.Iter(func(key, value interface{}) {
if value.(*TTLCacheItem).Expire <= now {
c.Backend.Delete(key)
}
})
}
var (
_ Cache = (*SimpleCache)(nil)
_ Cache = (*TTLCache)(nil)
)