Added function GetNotExpiredItems to get all not expired items in a threadsafe manner

This commit is contained in:
Christoph Petrausch 2016-08-31 08:35:59 +02:00
parent 1881a9bccb
commit c193f8a44d
2 changed files with 55 additions and 0 deletions

View File

@ -1009,6 +1009,22 @@ func (c *cache) Items() map[string]Item {
return c.items return c.items
} }
// Returns all not expired items in the cache. This method is save to use with
// an active janitor since it copies the underlying map. Therefore method is
// costly in terms of time and memory. You can read while using this method but
// not write. Use with caution.
func (c *cache) GetNotExpiredItems() map[string]Item {
retMap := make(map[string]Item, c.ItemCount())
c.mu.RLock()
for key, item := range c.items{
if !item.Expired() {
retMap[key] = item
}
}
c.mu.RUnlock()
return retMap
}
// Returns the number of items in the cache. This may include items that have // Returns the number of items in the cache. This may include items that have
// expired, but have not yet been cleaned up. Equivalent to len(c.Items()). // expired, but have not yet been cleaned up. Equivalent to len(c.Items()).
func (c *cache) ItemCount() int { func (c *cache) ItemCount() int {

View File

@ -8,6 +8,7 @@ import (
"sync" "sync"
"testing" "testing"
"time" "time"
"fmt"
) )
type TestStruct struct { type TestStruct struct {
@ -1247,6 +1248,29 @@ func TestOnEvicted(t *testing.T) {
} }
} }
func TestCacheGetAllNotExpiredItems(t *testing.T) {
tc := New(time.Minute*1, 0)
tc.Set("a", "a", DefaultExpiration)
tc.Set("b", "b", DefaultExpiration)
tc.Set("c", "c", time.Millisecond*1)
time.Sleep(time.Millisecond*2)
allNotExpiredItems := tc.GetNotExpiredItems()
if len(allNotExpiredItems) != 2 {
t.Error("There are more or less items in the result than the two unexpired.")
}
for _, key := range []string{"a", "b"} {
if _, ok := tc.Get(key); !ok{
t.Error("Could not find unexpired item %s", key)
}
}
if _, ok := tc.Get("c"); ok {
t.Error("Found expired item c.")
}
if &allNotExpiredItems == &tc.cache.items {
t.Error("Returned map is equal to internal map.")
}
}
func TestCacheSerialization(t *testing.T) { func TestCacheSerialization(t *testing.T) {
tc := New(DefaultExpiration, 0) tc := New(DefaultExpiration, 0)
testFillAndSerialize(t, tc) testFillAndSerialize(t, tc)
@ -1676,3 +1700,18 @@ func BenchmarkDeleteExpiredLoop(b *testing.B) {
tc.DeleteExpired() tc.DeleteExpired()
} }
} }
func BenchmarkGetAllNotExpiredItems(b *testing.B) {
for i:= 0; i < 20; i++ {
b.Run(fmt.Sprintf("BenchmarkGetAllNotExpiredItemsWith %d000 Items", i), func(b *testing.B){
tc := New(20*time.Minute, 0)
for j:= 0; j < i*1000; j++{
tc.Set(strconv.Itoa(i), "bar", DefaultExpiration)
}
b.ResetTimer()
for j:= 0; j < b.N; j++{
tc.GetNotExpiredItems()
}
})
}
}