work on cache transactions

This commit is contained in:
Radu Ioan Fericean
2014-09-02 20:58:22 +03:00
parent c5fea8ef71
commit fa7b97b5dc
10 changed files with 205 additions and 46 deletions

View File

@@ -10,6 +10,9 @@ import (
const (
PREFIX_LEN = 4
KIND_ADD = "ADD"
KIND_REM = "REM"
KIND_PRF = "PRF"
)
type timestampedValue struct {
@@ -17,21 +20,72 @@ type timestampedValue struct {
value interface{}
}
type transactionItem struct {
key string
value interface{}
kind string
}
var (
cache = make(map[string]timestampedValue)
mux sync.RWMutex
counters = make(map[string]int64)
// 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)
}
}
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{}) {
mux.Lock()
defer mux.Unlock()
if _, ok := cache[key]; !ok {
// only count if the key is not already there
count(key)
if !transactionLock {
mux.Lock()
defer mux.Unlock()
}
if !transactionON {
if _, ok := cache[key]; !ok {
// only count if the key is not already there
count(key)
}
cache[key] = timestampedValue{time.Now(), value}
} else {
transactionBuffer = append(transactionBuffer, transactionItem{key: key, value: value, kind: KIND_ADD})
}
cache[key] = timestampedValue{time.Now(), value}
}
// The function to extract a value for a key that never expire
@@ -54,28 +108,41 @@ func GetKeyAge(key string) (time.Duration, error) {
}
func RemKey(key string) {
mux.Lock()
defer mux.Unlock()
if _, ok := cache[key]; ok {
delete(cache, key)
descount(key)
if !transactionLock {
mux.Lock()
defer mux.Unlock()
}
if !transactionON {
if _, ok := cache[key]; ok {
delete(cache, key)
descount(key)
}
} else {
transactionBuffer = append(transactionBuffer, transactionItem{key: key, kind: KIND_REM})
}
}
func RemPrefixKey(prefix string) {
mux.Lock()
defer mux.Unlock()
if !transactionLock {
mux.Lock()
defer mux.Unlock()
}
for key, _ := range cache {
if strings.HasPrefix(key, prefix) {
delete(cache, key)
descount(key)
if !transactionON {
if strings.HasPrefix(key, prefix) {
delete(cache, key)
descount(key)
}
}
}
if transactionON {
transactionBuffer = append(transactionBuffer, transactionItem{key: prefix, kind: KIND_PRF})
}
}
func GetAllEntries(prefix string) map[string]interface{} {
mux.Lock()
defer mux.Unlock()
mux.RLock()
defer mux.RUnlock()
result := make(map[string]interface{})
for key, timestampedValue := range cache {
if strings.HasPrefix(key, prefix) {

View File

@@ -13,6 +13,53 @@ func TestRemKey(t *testing.T) {
}
}
func TestTransaction(t *testing.T) {
BeginTransaction()
Cache("t11_mm", "test")
if t1, err := GetCached("t11_mm"); err == nil || t1 == "test" {
t.Error("Error in transaction cache")
}
Cache("t12_mm", "test")
RemKey("t11_mm")
CommitTransaction()
if t1, err := GetCached("t12_mm"); err != nil || t1 != "test" {
t.Error("Error commiting transaction")
}
if t1, err := GetCached("t11_mm"); err == nil || t1 == "test" {
t.Error("Error in transaction cache")
}
}
func TestTransactionRem(t *testing.T) {
BeginTransaction()
Cache("t21_mm", "test")
Cache("t21_nn", "test")
RemPrefixKey("t21_")
CommitTransaction()
if t1, err := GetCached("t21_mm"); err == nil || t1 == "test" {
t.Error("Error commiting transaction")
}
if t1, err := GetCached("t21_nn"); err == nil || t1 == "test" {
t.Error("Error in transaction cache")
}
}
func TestTransactionRollback(t *testing.T) {
BeginTransaction()
Cache("t31_mm", "test")
if t1, err := GetCached("t31_mm"); err == nil || t1 == "test" {
t.Error("Error in transaction cache")
}
Cache("t32_mm", "test")
RollbackTransaction()
if t1, err := GetCached("t32_mm"); err == nil || t1 == "test" {
t.Error("Error commiting transaction")
}
if t1, err := GetCached("t31_mm"); err == nil || t1 == "test" {
t.Error("Error in transaction cache")
}
}
func TestRemPrefixKey(t *testing.T) {
Cache("x_t1", "test")
Cache("y_t1", "test")