Skip to content

Commit

Permalink
Add GetOrSet method to fallback non existent or expired keys
Browse files Browse the repository at this point in the history
  • Loading branch information
Gleb Vasylenko committed Feb 10, 2022
1 parent 77bbae4 commit d92b26b
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 0 deletions.
20 changes: 20 additions & 0 deletions bigcache.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,26 @@ func (c *BigCache) Get(key string) ([]byte, error) {
return shard.get(key, hashedKey)
}

// Get reads entry for the key and if it is not exists
// call second argument callback function to resolve actual value.
func (c *BigCache) GetOrSet(key string, fn func() ([]byte, error)) ([]byte, error) {
entry, err := c.Get(key)
if err == nil {
return entry, nil
}

if err != ErrEntryNotFound {
return nil, err
}

entry, err = fn()
if err != nil {
return nil, err
}

return entry, nil
}

// GetWithInfo reads entry for the key with Response info.
// It returns an ErrEntryNotFound when
// no entry exists for the given key.
Expand Down
34 changes: 34 additions & 0 deletions bigcache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package bigcache

import (
"bytes"
"errors"
"fmt"
"math"
"math/rand"
Expand All @@ -28,6 +29,39 @@ func TestWriteAndGetOnCache(t *testing.T) {
assertEqual(t, value, cachedValue)
}

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

// given
cache, _ := NewBigCache(DefaultConfig(5 * time.Second))
value := []byte("value")

// when
cachedValue, err := cache.GetOrSet("key", func() ([]byte, error) {
return value, nil
})

// then
noError(t, err)
assertEqual(t, value, cachedValue)
}

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

// given
cache, _ := NewBigCache(DefaultConfig(5 * time.Second))
errStub := errors.New("some error")

// when
_, err := cache.GetOrSet("key", func() ([]byte, error) {
return nil, errStub
})

// then
assertEqual(t, errStub, err)
}

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

Expand Down
12 changes: 12 additions & 0 deletions examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@ func Example() {
// Output: value
}

func Example_getOrSet() {
cache, _ := bigcache.NewBigCache(bigcache.DefaultConfig(10 * time.Minute))

entry, _ := cache.GetOrSet("my-unique-key", func() ([]byte, error) {
/* Some amount of code for resolving value... */
return []byte("value"), nil
})

fmt.Println(string(entry))
// Output: value
}

func Example_custom() {
// When cache load can be predicted in advance then it is better to use custom initialization
// because additional memory allocation can be avoided in that way.
Expand Down

0 comments on commit d92b26b

Please sign in to comment.