Files
cgrates/engine/cache.go
2016-07-06 22:29:32 +03:00

194 lines
3.9 KiB
Go

//Simple caching library with expiration capabilities
package engine
import "sync"
const (
PREFIX_LEN = 4
KIND_ADD = "ADD"
KIND_ADP = "ADP"
KIND_REM = "REM"
KIND_POP = "POP"
KIND_PRF = "PRF"
DOUBLE_CACHE = true
)
var (
mux sync.RWMutex
cache cacheStore
// transaction stuff
transactionBuffer []*transactionItem
transactionMux sync.Mutex
transactionON = false
transactionLock = false
dumper *cacheDumper
)
type transactionItem struct {
key string
value interface{}
kind string
}
func CacheSetDumperPath(path string) (err error) {
if dumper == nil {
dumper, err = newCacheDumper(path)
}
return
}
func init() {
if DOUBLE_CACHE {
cache = newDoubleStore()
} else {
cache = newSimpleStore()
}
}
func CacheBeginTransaction() {
transactionMux.Lock()
transactionLock = true
transactionON = true
}
func CacheRollbackTransaction() {
transactionBuffer = nil
transactionLock = false
transactionON = false
transactionMux.Unlock()
}
func CacheCommitTransaction() {
transactionON = false
// apply all transactioned items
mux.Lock()
for _, item := range transactionBuffer {
switch item.kind {
case KIND_REM:
CacheRemKey(item.key)
case KIND_PRF:
CacheRemPrefixKey(item.key)
case KIND_ADD:
CacheSet(item.key, item.value)
case KIND_ADP:
CachePush(item.key, item.value.(string))
case KIND_POP:
CachePop(item.key, item.value.(string))
}
}
mux.Unlock()
transactionBuffer = nil
transactionLock = false
transactionMux.Unlock()
}
func CacheLoad(path string, keys []string) error {
if !transactionLock {
mux.Lock()
defer mux.Unlock()
}
if !transactionON {
return cache.Load(path, keys)
}
return nil
}
// The function to be used to cache a key/value pair when expiration is not needed
func CacheSet(key string, value interface{}) {
if !transactionLock {
mux.Lock()
defer mux.Unlock()
}
if !transactionON {
cache.Put(key, value)
//log.Println("ADD: ", key)
} else {
transactionBuffer = append(transactionBuffer, &transactionItem{key: key, value: value, kind: KIND_ADD})
}
}
// The function to extract a value for a key that never expire
func CacheGet(key string) (v interface{}, err error) {
mux.RLock()
defer mux.RUnlock()
return cache.Get(key)
}
// Appends to an existing slice in the cache key
func CachePush(key string, value string) {
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})
}
}
func CachePop(key string, value string) {
if !transactionLock {
mux.Lock()
defer mux.Unlock()
}
if !transactionON {
cache.Pop(key, value)
} else {
transactionBuffer = append(transactionBuffer, &transactionItem{key: key, value: value, kind: KIND_POP})
}
}
func CacheRemKey(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 CacheRemPrefixKey(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 CacheFlush() {
mux.Lock()
defer mux.Unlock()
if DOUBLE_CACHE {
cache = newDoubleStore()
} else {
cache = newSimpleStore()
}
}
func CacheCountEntries(prefix string) (result int) {
mux.RLock()
defer mux.RUnlock()
return cache.CountEntriesForPrefix(prefix)
}
func CacheGetAllEntries(prefix string) (map[string]interface{}, error) {
mux.RLock()
defer mux.RUnlock()
return cache.GetAllForPrefix(prefix)
}
func CacheGetEntriesKeys(prefix string) (keys []string) {
mux.RLock()
defer mux.RUnlock()
return cache.GetKeysForPrefix(prefix)
}