woodpecker/vendor/github.com/koding/cache/memory_ttl.go

111 lines
2.2 KiB
Go

package cache
import (
"sync"
"time"
)
var zeroTTL = time.Duration(0)
// MemoryTTL holds the required variables to compose an in memory cache system
// which also provides expiring key mechanism
type MemoryTTL struct {
// Mutex is used for handling the concurrent
// read/write requests for cache
sync.Mutex
// cache holds the cache data
cache *MemoryNoTS
// setAts holds the time that related item's set at
setAts map[string]time.Time
// ttl is a duration for a cache key to expire
ttl time.Duration
// gcInterval is a duration for garbage collection
gcInterval time.Duration
}
// NewMemoryWithTTL creates an inmemory cache system
// Which everytime will return the true values about a cache hit
// and never will leak memory
// ttl is used for expiration of a key from cache
func NewMemoryWithTTL(ttl time.Duration) *MemoryTTL {
return &MemoryTTL{
cache: NewMemoryNoTS(),
setAts: map[string]time.Time{},
ttl: ttl,
}
}
// StartGC starts the garbage collection process in a go routine
func (r *MemoryTTL) StartGC(gcInterval time.Duration) {
r.gcInterval = gcInterval
go func() {
for _ = range time.Tick(gcInterval) {
for key := range r.cache.items {
if !r.isValid(key) {
r.Delete(key)
}
}
}
}()
}
// Get returns a value of a given key if it exists
// and valid for the time being
func (r *MemoryTTL) Get(key string) (interface{}, error) {
r.Lock()
defer r.Unlock()
if !r.isValid(key) {
r.delete(key)
return nil, ErrNotFound
}
value, err := r.cache.Get(key)
if err != nil {
return nil, err
}
return value, nil
}
// Set will persist a value to the cache or
// override existing one with the new one
func (r *MemoryTTL) Set(key string, value interface{}) error {
r.Lock()
defer r.Unlock()
r.cache.Set(key, value)
r.setAts[key] = time.Now()
return nil
}
// Delete deletes a given key if exists
func (r *MemoryTTL) Delete(key string) error {
r.Lock()
defer r.Unlock()
r.delete(key)
return nil
}
func (r *MemoryTTL) delete(key string) {
r.cache.Delete(key)
delete(r.setAts, key)
}
func (r *MemoryTTL) isValid(key string) bool {
setAt, ok := r.setAts[key]
if !ok {
return false
}
if r.ttl == zeroTTL {
return true
}
return setAt.Add(r.ttl).After(time.Now())
}