Files
cgrates/cache2go/cache.go
2014-09-04 02:28:10 +03:00

180 lines
3.4 KiB
Go

//Simple caching library with expiration capabilities
package cache2go
import (
"errors"
"sync"
"time"
"github.com/cgrates/cgrates/utils"
)
const (
PREFIX_LEN = 4
KIND_ADD = "ADD"
KIND_ADP = "ADP"
KIND_REM = "REM"
KIND_PRF = "PRF"
)
type timestampedValue struct {
timestamp time.Time
value interface{}
}
func (tsv timestampedValue) Value() interface{} {
return tsv.value
}
type transactionItem struct {
key string
value interface{}
kind string
}
var (
cache = make(cacheStore)
mux sync.RWMutex
// transaction stuff
transactionBuffer []transactionItem
transactionMux sync.Mutex
transactionON = false
transactionLock = false
)
func BeginTransaction() {
transactionMux.Lock()
transactionLock = true
transactionON = true
}
func RollbackTransaction() {
transactionBuffer = nil
transactionLock = false
transactionON = false
transactionMux.Unlock()
}
func CommitTransaction() {
transactionON = false
// apply all transactioned items
mux.Lock()
for _, item := range transactionBuffer {
switch item.kind {
case KIND_REM:
RemKey(item.key)
case KIND_PRF:
RemPrefixKey(item.key)
case KIND_ADD:
Cache(item.key, item.value)
case KIND_ADP:
CachePush(item.key, item.value)
}
}
mux.Unlock()
transactionBuffer = nil
transactionLock = false
transactionMux.Unlock()
}
// The function to be used to cache a key/value pair when expiration is not needed
func Cache(key string, value interface{}) {
if !transactionLock {
mux.Lock()
defer mux.Unlock()
}
if !transactionON {
cache.Put(key, value)
//fmt.Println("ADD: ", key)
} else {
transactionBuffer = append(transactionBuffer, transactionItem{key: key, value: value, kind: KIND_ADD})
}
}
// Appends to an existing slice in the cache key
func CachePush(key string, value interface{}) {
if !transactionLock {
mux.Lock()
defer mux.Unlock()
}
if !transactionON {
cache.Append(key, value)
} else {
transactionBuffer = append(transactionBuffer, transactionItem{key: key, value: value, kind: KIND_ADP})
}
}
// 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()
return cache.Get(key)
}
func GetKeyAge(key string) (time.Duration, error) {
mux.RLock()
defer mux.RUnlock()
return cache.GetAge(key)
}
func RemKey(key string) {
if !transactionLock {
mux.Lock()
defer mux.Unlock()
}
if !transactionON {
cache.Delete(key)
} else {
transactionBuffer = append(transactionBuffer, transactionItem{key: key, kind: KIND_REM})
}
}
func RemPrefixKey(prefix string) {
if !transactionLock {
mux.Lock()
defer mux.Unlock()
}
if !transactionON {
cache.DeletePrefix(prefix)
} else {
transactionBuffer = append(transactionBuffer, transactionItem{key: prefix, kind: KIND_PRF})
}
}
// Delete all keys from cache
func Flush() {
mux.Lock()
defer mux.Unlock()
cache = make(cacheStore)
}
func CountEntries(prefix string) (result int64) {
mux.RLock()
defer mux.RUnlock()
if _, ok := cache[prefix]; ok {
return int64(len(cache[prefix]))
}
return 0
}
func GetAllEntries(prefix string) (map[string]timestampedValue, error) {
mux.RLock()
defer mux.RUnlock()
if keyMap, ok := cache[prefix]; ok {
return keyMap, nil
}
return nil, errors.New(utils.ERR_NOT_FOUND)
}
func GetEntriesKeys(prefix string) (keys []string) {
mux.RLock()
defer mux.RUnlock()
if keyMap, ok := cache[prefix]; ok {
for key := range keyMap {
keys = append(keys, key)
}
}
return
}