faster cache counter and unified caches

This commit is contained in:
Radu Ioan Fericean
2014-04-28 12:10:37 +03:00
parent 6497a09ae5
commit 24a2436f81
2 changed files with 64 additions and 41 deletions

View File

@@ -31,11 +31,17 @@ type timestampedValue struct {
value interface{}
}
const (
PREFIX_LEN = 4
)
var (
xcache = make(map[string]expiringCacheEntry)
xMux sync.RWMutex
cache = make(map[string]timestampedValue)
mux sync.RWMutex
xcache = make(map[string]expiringCacheEntry)
xMux sync.RWMutex
cache = make(map[string]timestampedValue)
mux sync.RWMutex
cMux sync.Mutex
counters = make(map[string]int64)
)
// The main function to cache with expiration
@@ -46,6 +52,7 @@ func (xe *XEntry) XCache(key string, expire time.Duration, value expiringCacheEn
xe.timestamp = time.Now()
xMux.Lock()
xcache[key] = value
count(key)
xMux.Unlock()
go xe.expire()
}
@@ -61,6 +68,7 @@ func (xe *XEntry) expire() {
if !xe.keepAlive {
xMux.Lock()
delete(xcache, xe.key)
descount(xe.key)
xMux.Unlock()
}
}
@@ -99,6 +107,7 @@ func Cache(key string, value interface{}) {
mux.Lock()
defer mux.Unlock()
cache[key] = timestampedValue{time.Now(), value}
count(key)
}
// The function to extract a value for a key that never expire
@@ -117,10 +126,6 @@ func GetKeyAge(key string) (time.Duration, error) {
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 {
@@ -133,9 +138,6 @@ func RemKey(key string) {
mux.Lock()
defer mux.Unlock()
delete(cache, key)
}
func XRemKey(key string) {
xMux.Lock()
defer xMux.Unlock()
if r, ok := xcache[key]; ok {
@@ -144,6 +146,7 @@ func XRemKey(key string) {
}
}
delete(xcache, key)
descount(key)
}
func RemPrefixKey(prefix string) {
@@ -152,11 +155,9 @@ func RemPrefixKey(prefix string) {
for key, _ := range cache {
if strings.HasPrefix(key, prefix) {
delete(cache, key)
descount(key)
}
}
}
func XRemPrefixKey(prefix string) {
xMux.Lock()
defer xMux.Unlock()
for key, _ := range xcache {
@@ -167,6 +168,7 @@ func XRemPrefixKey(prefix string) {
}
}
delete(xcache, key)
descount(key)
}
}
}
@@ -178,11 +180,6 @@ func GetAllEntries(prefix string) map[string]interface{} {
result[key] = timestampedValue.value
}
}
return result
}
func XGetAllEntries(prefix string) map[string]interface{} {
result := make(map[string]interface{})
for key, value := range xcache {
if strings.HasPrefix(key, prefix) {
result[key] = value
@@ -191,8 +188,8 @@ func XGetAllEntries(prefix string) map[string]interface{} {
return result
}
// Delete all keys from expiraton cache
func XFlush() {
// Delete all keys from cache
func Flush() {
xMux.Lock()
defer xMux.Unlock()
for _, v := range xcache {
@@ -201,29 +198,44 @@ func XFlush() {
}
}
xcache = make(map[string]expiringCacheEntry)
}
// Delete all keys from cache
func Flush() {
mux.Lock()
defer mux.Unlock()
cache = make(map[string]timestampedValue)
counters = make(map[string]int64)
}
func CountEntries(prefix string) (result int) {
for key, _ := range cache {
if strings.HasPrefix(key, prefix) {
result++
}
func CountEntries(prefix string) (result int64) {
if _, ok := counters[prefix]; ok {
return counters[prefix]
}
return
return 0
}
func XCountEntries(prefix string) (result int) {
for key, _ := range xcache {
if strings.HasPrefix(key, prefix) {
result++
}
// increments the counter for the specified key prefix
func count(key string) {
if len(key) < PREFIX_LEN {
return
}
cMux.Lock()
defer cMux.Unlock()
prefix := key[:PREFIX_LEN]
if _, ok := counters[prefix]; ok {
// increase the value
counters[prefix] += 1
} else {
counters[prefix] = 1
}
}
// decrements the counter for the specified key prefix
func descount(key string) {
if len(key) < PREFIX_LEN {
return
}
cMux.Lock()
defer cMux.Unlock()
prefix := key[:PREFIX_LEN]
if _, ok := counters[prefix]; ok {
counters[prefix] -= 1
}
return
}

View File

@@ -57,7 +57,7 @@ func TestFlush(t *testing.T) {
a := &myStruct{data: "mama are mere"}
a.XCache("mama", 10*time.Second, a)
time.Sleep(1000 * time.Millisecond)
XFlush()
Flush()
b, err := GetXCached("mama")
if err == nil || b != nil {
t.Error("Error expiring data")
@@ -67,7 +67,7 @@ func TestFlush(t *testing.T) {
func TestFlushNoTimout(t *testing.T) {
a := &myStruct{data: "mama are mere"}
a.XCache("mama", 10*time.Second, a)
XFlush()
Flush()
b, err := GetXCached("mama")
if err == nil || b != nil {
t.Error("Error expiring data")
@@ -91,7 +91,7 @@ func TestXRemKey(t *testing.T) {
if t1, err := GetXCached("mama"); err != nil || t1 != a {
t.Error("Error setting xcache")
}
XRemKey("mama")
RemKey("mama")
if t1, err := GetXCached("mama"); err == nil || t1 == a {
t.Error("Error removing xcached key: ", err, t1)
}
@@ -134,10 +134,21 @@ func TestXRemPrefixKey(t *testing.T) {
a.XCache("x_t1", 10*time.Second, a)
a.XCache("y_t1", 10*time.Second, a)
XRemPrefixKey("x_")
RemPrefixKey("x_")
_, errX := GetXCached("x_t1")
_, errY := GetXCached("y_t1")
if errX == nil || errY != nil {
t.Error("Error removing prefix: ", errX, errY)
}
}
func TestCount(t *testing.T) {
Cache("dst_A1", "1")
Cache("dst_A2", "2")
Cache("rpf_A3", "3")
Cache("dst_A4", "4")
Cache("dst_A5", "5")
if CountEntries("dst_") != 4 {
t.Error("Error countiong entries: ", CountEntries("dst_"))
}
}