//Simple caching library with expiration capabilities package cache2go import ( "sync" "time" ) const ( PREFIX_LEN = 4 KIND_ADD = "ADD" KIND_ADP = "ADP" KIND_REM = "REM" KIND_PRF = "PRF" DOUBLE_CACHE = true ) 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 } func init() { if DOUBLE_CACHE { cache = newDoubleStore() } else { cache = newSimpleStore() } } var ( mux sync.RWMutex cache cacheStore // 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() if DOUBLE_CACHE { cache = newDoubleStore() } else { cache = newSimpleStore() } } func CountEntries(prefix string) (result int) { mux.RLock() defer mux.RUnlock() return cache.CountEntriesForPrefix(prefix) } func GetAllEntries(prefix string) (map[string]timestampedValue, error) { mux.RLock() defer mux.RUnlock() return cache.GetAllForPrefix(prefix) } func GetEntriesKeys(prefix string) (keys []string) { mux.RLock() defer mux.RUnlock() return cache.GetKeysForPrefix(prefix) }