mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
209 lines
4.0 KiB
Go
209 lines
4.0 KiB
Go
//Simple caching library with expiration capabilities
|
|
package cache2go
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type expiringCacheEntry interface {
|
|
XCache(key string, expire time.Duration, value expiringCacheEntry)
|
|
timer() *time.Timer
|
|
age() time.Duration
|
|
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
|
|
}
|
|
|
|
func (xe *XEntry) age() time.Duration {
|
|
return time.Since(xe.timestamp)
|
|
|
|
}
|
|
|
|
// 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 GetKeyAge(key string) (time.Duration, error) {
|
|
mux.RLock()
|
|
defer mux.RUnlock()
|
|
if r, ok := cache[key]; ok {
|
|
return time.Since(r.timestamp), nil
|
|
}
|
|
return 0, errors.New("not found")
|
|
}
|
|
|
|
func GetXKeyAge(key string) (time.Duration, error) {
|
|
xMux.RLock()
|
|
defer xMux.RUnlock()
|
|
if r, ok := xcache[key]; ok {
|
|
return r.age(), nil
|
|
}
|
|
return 0, errors.New("not found")
|
|
}
|
|
|
|
func RemKey(key string) {
|
|
mux.Lock()
|
|
defer mux.Unlock()
|
|
delete(cache, key)
|
|
}
|
|
|
|
func RemPrefixKey(prefix string) {
|
|
mux.Lock()
|
|
defer mux.Unlock()
|
|
for key, _ := range cache {
|
|
if strings.HasPrefix(key, prefix) {
|
|
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)
|
|
}
|
|
func XRemPrefixKey(prefix string) {
|
|
xMux.Lock()
|
|
defer xMux.Unlock()
|
|
for key, _ := range xcache {
|
|
if strings.HasPrefix(key, prefix) {
|
|
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)
|
|
}
|
|
|
|
func CountEntries(prefix string) (result int) {
|
|
for key, _ := range cache {
|
|
if strings.HasPrefix(key, prefix) {
|
|
result++
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func XCountEntries(prefix string) (result int) {
|
|
for key, _ := range xcache {
|
|
if strings.HasPrefix(key, prefix) {
|
|
result++
|
|
}
|
|
}
|
|
return
|
|
}
|