Skip to content

Commit

Permalink
Add ability to iterate over keys
Browse files Browse the repository at this point in the history
  • Loading branch information
Mateusz Gajewski committed Oct 12, 2016
1 parent f403062 commit e2823d8
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 0 deletions.
42 changes: 42 additions & 0 deletions bigcache.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ type cacheShard struct {
onRemove func(wrappedEntry []byte)
}

// EntryInfo holds informations about entry in the cache
type EntryInfo struct {
Key string
Hash uint64
Timestamp uint64
}

// KeysIterator allows to iterate over entries in the cache
type KeysIterator chan EntryInfo

// NewBigCache initialize new instance of BigCache
func NewBigCache(config Config) (*BigCache, error) {
return newBigCache(config, &systemClock{})
Expand Down Expand Up @@ -144,6 +154,38 @@ func (c *BigCache) Set(key string, entry []byte) error {
}
}

// Keys returns channel to iterate over EntryInfo's from whole cache
func (c *BigCache) Keys() KeysIterator {
ch := make(KeysIterator, 1024)
var wg sync.WaitGroup
wg.Add(c.config.Shards)

for i := 0; i < c.config.Shards; i++ {
go func(shard *cacheShard) {
defer wg.Done()
shard.lock.RLock()
defer shard.lock.RUnlock()

for _, index := range shard.hashmap {
if entry, err := shard.entries.Get(int(index)); err == nil {
ch <- EntryInfo{
Key: readKeyFromEntry(entry),
Hash: readHashFromEntry(entry),
Timestamp: readTimestampFromEntry(entry),
}
}
}
}(c.shards[i])
}

go func() {
wg.Wait()
close(ch)
}()

return ch
}

func (c *BigCache) onEvict(oldestEntry []byte, currentTimestamp uint64, evict func() error) {
oldestTimestamp := readTimestampFromEntry(oldestEntry)
if currentTimestamp-oldestTimestamp > c.lifeWindow {
Expand Down
44 changes: 44 additions & 0 deletions bigcache_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package bigcache

import (
"fmt"
"sync"
"testing"
"time"

Expand Down Expand Up @@ -113,6 +115,48 @@ func TestEntryUpdate(t *testing.T) {
assert.Equal(t, []byte("value2"), cachedValue)
}

func TestKeysIterator(t *testing.T) {
//t.Parallel()

// given
keysCount := 10000
cache, _ := NewBigCache(Config{8, 6 * time.Second, 1, 256, false, nil, 0, nil})
value := []byte("value")
var wg sync.WaitGroup
wg.Add(1)

for i := 0; i < keysCount; i++ {
cache.Set(fmt.Sprintf("key%d", i), value)
}

// when
ch := cache.Keys()
keys := make(map[string]struct{})

go func() {
loop:
for {
select {
case entryInfo, opened := <-ch:
if !opened {
break loop
}

keys[entryInfo.Key] = struct{}{}

case <-time.After(time.Second * 1):
break loop
}
}

wg.Done()
}()

// then
wg.Wait()
assert.Equal(t, keysCount, len(keys))
}

func TestOldestEntryDeletionWhenMaxCacheSizeIsReached(t *testing.T) {
t.Parallel()

Expand Down

0 comments on commit e2823d8

Please sign in to comment.