Skip to content

Commit

Permalink
Merge pull request #2 from fmyxyz/forked
Browse files Browse the repository at this point in the history
Forked
  • Loading branch information
fmyxyz committed Mar 20, 2021
2 parents 39e232c + afb1aba commit b2e7114
Show file tree
Hide file tree
Showing 12 changed files with 865 additions and 110 deletions.
1 change: 1 addition & 0 deletions Makefile
Expand Up @@ -8,6 +8,7 @@ mocks:
mockgen -source=store/bigcache.go -destination=test/mocks/store/clients/bigcache_interface.go -package=mocks
mockgen -source=store/memcache.go -destination=test/mocks/store/clients/memcache_interface.go -package=mocks
mockgen -source=store/redis.go -destination=test/mocks/store/clients/redis_interface.go -package=mocks
mockgen -source=store/rediscluster.go -destination=test/mocks/store/clients/rediscluster_interface.go -package=mocks
mockgen -source=store/ristretto.go -destination=test/mocks/store/clients/ristretto_interface.go -package=mocks
mockgen -source=store/freecache.go -destination=test/mocks/store/clients/freecache_interface.go -package=mocks
mockgen -source=store/go_cache.go -destination=test/mocks/store/clients/go_cache_interface.go -package=mocks
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -26,7 +26,7 @@ Here is what it brings in detail:
* [Memory (bigcache)](https://github.com/allegro/bigcache) (allegro/bigcache)
* [Memory (ristretto)](https://github.com/dgraph-io/ristretto) (dgraph-io/ristretto)
* [Memcache](https://github.com/bradfitz/gomemcache) (bradfitz/memcache)
* [Redis](https://github.com/go-redis/redis/v7) (go-redis/redis)
* [Redis](https://github.com/go-redis/redis/v8) (go-redis/redis)
* [Freecache](https://github.com/coocood/freecache) (coocood/freecache)
* More to come soon

Expand Down
6 changes: 3 additions & 3 deletions go.mod
@@ -1,16 +1,16 @@
module github.com/eko/gocache

go 1.15
go 1.16

require (
github.com/allegro/bigcache/v2 v2.2.5
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b
github.com/coocood/freecache v1.1.1
github.com/dgraph-io/ristretto v0.0.3
github.com/go-redis/redis/v7 v7.4.0
github.com/go-redis/redis/v8 v8.7.1
github.com/golang/mock v1.5.0
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/prometheus/client_golang v1.9.0
github.com/prometheus/client_golang v1.10.0
github.com/stretchr/testify v1.7.0
github.com/vmihailenco/msgpack v4.0.4+incompatible
google.golang.org/appengine v1.6.7 // indirect
Expand Down
253 changes: 232 additions & 21 deletions go.sum

Large diffs are not rendered by default.

57 changes: 29 additions & 28 deletions store/redis.go
@@ -1,22 +1,23 @@
package store

import (
"context"
"fmt"
"time"

redis "github.com/go-redis/redis/v7"
redis "github.com/go-redis/redis/v8"
)

// RedisClientInterface represents a go-redis/redis client
type RedisClientInterface interface {
Get(key string) *redis.StringCmd
TTL(key string) *redis.DurationCmd
Expire(key string, expiration time.Duration) *redis.BoolCmd
Set(key string, values interface{}, expiration time.Duration) *redis.StatusCmd
Del(keys ...string) *redis.IntCmd
FlushAll() *redis.StatusCmd
SAdd(key string, members ...interface{}) *redis.IntCmd
SMembers(key string) *redis.StringSliceCmd
Get(ctx context.Context, key string) *redis.StringCmd
TTL(ctx context.Context, key string) *redis.DurationCmd
Expire(ctx context.Context, key string, expiration time.Duration) *redis.BoolCmd
Set(ctx context.Context, key string, values interface{}, expiration time.Duration) *redis.StatusCmd
Del(ctx context.Context, keys ...string) *redis.IntCmd
FlushAll(ctx context.Context) *redis.StatusCmd
SAdd(ctx context.Context, key string, members ...interface{}) *redis.IntCmd
SMembers(ctx context.Context, key string) *redis.StringSliceCmd
}

const (
Expand Down Expand Up @@ -45,18 +46,18 @@ func NewRedis(client RedisClientInterface, options *Options) *RedisStore {
}

// Get returns data stored from a given key
func (s *RedisStore) Get(key interface{}) (interface{}, error) {
return s.client.Get(key.(string)).Result()
func (s *RedisStore) Get(ctx context.Context, key interface{}) (interface{}, error) {
return s.client.Get(ctx, key.(string)).Result()
}

// GetWithTTL returns data stored from a given key and its corresponding TTL
func (s *RedisStore) GetWithTTL(key interface{}) (interface{}, time.Duration, error) {
object, err := s.client.Get(key.(string)).Result()
func (s *RedisStore) GetWithTTL(ctx context.Context, key interface{}) (interface{}, time.Duration, error) {
object, err := s.client.Get(ctx, key.(string)).Result()
if err != nil {
return nil, 0, err
}

ttl, err := s.client.TTL(key.(string)).Result()
ttl, err := s.client.TTL(ctx, key.(string)).Result()
if err != nil {
return nil, 0, err
}
Expand All @@ -65,52 +66,52 @@ func (s *RedisStore) GetWithTTL(key interface{}) (interface{}, time.Duration, er
}

// Set defines data in Redis for given key identifier
func (s *RedisStore) Set(key interface{}, value interface{}, options *Options) error {
func (s *RedisStore) Set(ctx context.Context, key interface{}, value interface{}, options *Options) error {
if options == nil {
options = s.options
}

err := s.client.Set(key.(string), value, options.ExpirationValue()).Err()
err := s.client.Set(ctx, key.(string), value, options.ExpirationValue()).Err()
if err != nil {
return err
}

if tags := options.TagsValue(); len(tags) > 0 {
s.setTags(key, tags)
s.setTags(ctx, key, tags)
}

return nil
}

func (s *RedisStore) setTags(key interface{}, tags []string) {
func (s *RedisStore) setTags(ctx context.Context, key interface{}, tags []string) {
for _, tag := range tags {
tagKey := fmt.Sprintf(RedisTagPattern, tag)
s.client.SAdd(tagKey, key.(string))
s.client.Expire(tagKey, 720*time.Hour)
s.client.SAdd(ctx, tagKey, key.(string))
s.client.Expire(ctx, tagKey, 720*time.Hour)
}
}

// Delete removes data from Redis for given key identifier
func (s *RedisStore) Delete(key interface{}) error {
_, err := s.client.Del(key.(string)).Result()
func (s *RedisStore) Delete(ctx context.Context, key interface{}) error {
_, err := s.client.Del(ctx, key.(string)).Result()
return err
}

// Invalidate invalidates some cache data in Redis for given options
func (s *RedisStore) Invalidate(options InvalidateOptions) error {
func (s *RedisStore) Invalidate(ctx context.Context, options InvalidateOptions) error {
if tags := options.TagsValue(); len(tags) > 0 {
for _, tag := range tags {
tagKey := fmt.Sprintf(RedisTagPattern, tag)
cacheKeys, err := s.client.SMembers(tagKey).Result()
cacheKeys, err := s.client.SMembers(ctx, tagKey).Result()
if err != nil {
continue
}

for _, cacheKey := range cacheKeys {
s.Delete(cacheKey)
s.Delete(ctx, cacheKey)
}

s.Delete(tagKey)
s.Delete(ctx, tagKey)
}
}

Expand All @@ -123,8 +124,8 @@ func (s *RedisStore) GetType() string {
}

// Clear resets all data in the store
func (s *RedisStore) Clear() error {
if err := s.client.FlushAll().Err(); err != nil {
func (s *RedisStore) Clear(ctx context.Context) error {
if err := s.client.FlushAll(ctx).Err(); err != nil {
return err
}

Expand Down
13 changes: 7 additions & 6 deletions store/redis_bench_test.go
@@ -1,16 +1,17 @@
package store

import (
"context"
"fmt"
"math"
"testing"

redis "github.com/go-redis/redis/v7"
redis "github.com/go-redis/redis/v8"
)

func BenchmarkRedisSet(b *testing.B) {
store := NewRedis(redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379",
Addr: "redis:6379",
}), nil)

for k := 0.; k <= 10; k++ {
Expand All @@ -20,7 +21,7 @@ func BenchmarkRedisSet(b *testing.B) {
key := fmt.Sprintf("test-%d", n)
value := []byte(fmt.Sprintf("value-%d", n))

store.Set(key, value, &Options{
store.Set(context.TODO(), key, value, &Options{
Tags: []string{fmt.Sprintf("tag-%d", n)},
})
}
Expand All @@ -30,19 +31,19 @@ func BenchmarkRedisSet(b *testing.B) {

func BenchmarkRedisGet(b *testing.B) {
store := NewRedis(redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379",
Addr: "redis:6379",
}), nil)

key := "test"
value := []byte("value")

store.Set(key, value, nil)
store.Set(context.TODO(), key, value, nil)

for k := 0.; k <= 10; k++ {
n := int(math.Pow(2, k))
b.Run(fmt.Sprintf("%d", n), func(b *testing.B) {
for i := 0; i < b.N*n; i++ {
_, _ = store.Get(key)
_, _ = store.Get(context.TODO(), key)
}
})
}
Expand Down
37 changes: 19 additions & 18 deletions store/redis_test.go
@@ -1,11 +1,12 @@
package store

import (
"context"
"testing"
"time"

mocksStore "github.com/eko/gocache/test/mocks/store/clients"
"github.com/go-redis/redis/v7"
"github.com/go-redis/redis/v8"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
)
Expand Down Expand Up @@ -35,12 +36,12 @@ func TestRedisGet(t *testing.T) {
defer ctrl.Finish()

client := mocksStore.NewMockRedisClientInterface(ctrl)
client.EXPECT().Get("my-key").Return(&redis.StringCmd{})
client.EXPECT().Get(context.TODO(), "my-key").Return(&redis.StringCmd{})

store := NewRedis(client, nil)

// When
value, err := store.Get("my-key")
value, err := store.Get(context.TODO(), "my-key")

// Then
assert.Nil(t, err)
Expand All @@ -59,12 +60,12 @@ func TestRedisSet(t *testing.T) {
}

client := mocksStore.NewMockRedisClientInterface(ctrl)
client.EXPECT().Set("my-key", cacheValue, 5*time.Second).Return(&redis.StatusCmd{})
client.EXPECT().Set(context.TODO(), "my-key", cacheValue, 5*time.Second).Return(&redis.StatusCmd{})

store := NewRedis(client, options)

// When
err := store.Set(cacheKey, cacheValue, &Options{
err := store.Set(context.TODO(), cacheKey, cacheValue, &Options{
Expiration: 5 * time.Second,
})

Expand All @@ -84,12 +85,12 @@ func TestRedisSetWhenNoOptionsGiven(t *testing.T) {
}

client := mocksStore.NewMockRedisClientInterface(ctrl)
client.EXPECT().Set("my-key", cacheValue, 6*time.Second).Return(&redis.StatusCmd{})
client.EXPECT().Set(context.TODO(), "my-key", cacheValue, 6*time.Second).Return(&redis.StatusCmd{})

store := NewRedis(client, options)

// When
err := store.Set(cacheKey, cacheValue, nil)
err := store.Set(context.TODO(), cacheKey, cacheValue, nil)

// Then
assert.Nil(t, err)
Expand All @@ -104,14 +105,14 @@ func TestRedisSetWithTags(t *testing.T) {
cacheValue := "my-cache-value"

client := mocksStore.NewMockRedisClientInterface(ctrl)
client.EXPECT().Set(cacheKey, cacheValue, time.Duration(0)).Return(&redis.StatusCmd{})
client.EXPECT().SAdd("gocache_tag_tag1", "my-key").Return(&redis.IntCmd{})
client.EXPECT().Expire("gocache_tag_tag1", 720*time.Hour).Return(&redis.BoolCmd{})
client.EXPECT().Set(context.TODO(), cacheKey, cacheValue, time.Duration(0)).Return(&redis.StatusCmd{})
client.EXPECT().SAdd(context.TODO(), "gocache_tag_tag1", "my-key").Return(&redis.IntCmd{})
client.EXPECT().Expire(context.TODO(), "gocache_tag_tag1", 720*time.Hour).Return(&redis.BoolCmd{})

store := NewRedis(client, nil)

// When
err := store.Set(cacheKey, cacheValue, &Options{Tags: []string{"tag1"}})
err := store.Set(context.TODO(), cacheKey, cacheValue, &Options{Tags: []string{"tag1"}})

// Then
assert.Nil(t, err)
Expand All @@ -125,12 +126,12 @@ func TestRedisDelete(t *testing.T) {
cacheKey := "my-key"

client := mocksStore.NewMockRedisClientInterface(ctrl)
client.EXPECT().Del("my-key").Return(&redis.IntCmd{})
client.EXPECT().Del(context.TODO(), "my-key").Return(&redis.IntCmd{})

store := NewRedis(client, nil)

// When
err := store.Delete(cacheKey)
err := store.Delete(context.TODO(), cacheKey)

// Then
assert.Nil(t, err)
Expand All @@ -148,13 +149,13 @@ func TestRedisInvalidate(t *testing.T) {
cacheKeys := &redis.StringSliceCmd{}

client := mocksStore.NewMockRedisClientInterface(ctrl)
client.EXPECT().SMembers("gocache_tag_tag1").Return(cacheKeys)
client.EXPECT().Del("gocache_tag_tag1").Return(&redis.IntCmd{})
client.EXPECT().SMembers(context.TODO(), "gocache_tag_tag1").Return(cacheKeys)
client.EXPECT().Del(context.TODO(), "gocache_tag_tag1").Return(&redis.IntCmd{})

store := NewRedis(client, nil)

// When
err := store.Invalidate(options)
err := store.Invalidate(context.TODO(), options)

// Then
assert.Nil(t, err)
Expand All @@ -166,12 +167,12 @@ func TestRedisClear(t *testing.T) {
defer ctrl.Finish()

client := mocksStore.NewMockRedisClientInterface(ctrl)
client.EXPECT().FlushAll().Return(&redis.StatusCmd{})
client.EXPECT().FlushAll(context.TODO()).Return(&redis.StatusCmd{})

store := NewRedis(client, nil)

// When
err := store.Clear()
err := store.Clear(context.TODO())

// Then
assert.Nil(t, err)
Expand Down

0 comments on commit b2e7114

Please sign in to comment.