Files
cgrates/cache2go/cache.go
2013-11-27 20:13:25 +02:00

142 lines
2.8 KiB
Go

//Simple caching library with expiration capabilities
package cache2go
import (
"errors"
"sync"
"time"
)
type expiringCacheEntry interface {
XCache(key string, expire time.Duration, value expiringCacheEntry)
timer() *time.Timer
KeepAlive()
}
// Structure that must be embeded in the objectst that must be cached with expiration.
// If the expiration is not needed this can be ignored
type XEntry struct {
sync.Mutex
key string
keepAlive bool
expireDuration time.Duration
timestamp time.Time
t *time.Timer
}
type timestampedValue struct {
timestamp time.Time
value interface{}
}
var (
xcache = make(map[string]expiringCacheEntry)
xMux sync.RWMutex
cache = make(map[string]timestampedValue)
mux sync.RWMutex
)
// The main function to cache with expiration
func (xe *XEntry) XCache(key string, expire time.Duration, value expiringCacheEntry) {
xe.keepAlive = true
xe.key = key
xe.expireDuration = expire
xe.timestamp = time.Now()
xMux.Lock()
xcache[key] = value
xMux.Unlock()
go xe.expire()
}
// The internal mechanism for expiartion
func (xe *XEntry) expire() {
for xe.keepAlive {
xe.Lock()
xe.keepAlive = false
xe.Unlock()
xe.t = time.NewTimer(xe.expireDuration)
<-xe.t.C
if !xe.keepAlive {
xMux.Lock()
delete(xcache, xe.key)
xMux.Unlock()
}
}
}
// Getter for the timer
func (xe *XEntry) timer() *time.Timer {
return xe.t
}
// Mark entry to be kept another expirationDuration period
func (xe *XEntry) KeepAlive() {
xe.Lock()
defer xe.Unlock()
xe.keepAlive = true
}
// Get an entry from the expiration cache and mark it for keeping alive
func GetXCached(key string) (ece expiringCacheEntry, err error) {
xMux.RLock()
defer xMux.RUnlock()
if r, ok := xcache[key]; ok {
r.KeepAlive()
return r, nil
}
return nil, errors.New("not found")
}
// The function to be used to cache a key/value pair when expiration is not needed
func Cache(key string, value interface{}) {
mux.Lock()
defer mux.Unlock()
cache[key] = timestampedValue{time.Now(), value}
}
// The function to extract a value for a key that never expire
func GetCached(key string) (v interface{}, err error) {
mux.RLock()
defer mux.RUnlock()
if r, ok := cache[key]; ok {
return r.value, nil
}
return nil, errors.New("not found")
}
func RemKey(key string) {
mux.Lock()
defer mux.Unlock()
delete(cache, key)
}
func XRemKey(key string) {
xMux.Lock()
defer xMux.Unlock()
if r, ok := xcache[key]; ok {
if r.timer() != nil {
r.timer().Stop()
}
}
delete(xcache, key)
}
// Delete all keys from expiraton cache
func XFlush() {
xMux.Lock()
defer xMux.Unlock()
for _, v := range xcache {
if v.timer() != nil {
v.timer().Stop()
}
}
xcache = make(map[string]expiringCacheEntry)
}
// Delete all keys from cache
func Flush() {
mux.Lock()
defer mux.Unlock()
cache = make(map[string]timestampedValue)
}