Skip to content

Commit d38a813

Browse files
committed
Make rueidis store to be more user-friendly and be more performant,
1. Make Get() and GetWithTTL() return go string instead of rueidis.RedisResult to be more user-friendly. 2. Make Set() only accept go string value, since Get() also returns go string. 3. Make GetWithTTL() retrive client-side TTL without additional network roundtrip. 4. Pipeline SADD and EXPIRE while setting key tags to reduce network roundtrips. 5. Not to cache SMEMBERS while doing Invalidate(), since it will also be invalidated soon.
1 parent 4635b6a commit d38a813

File tree

5 files changed

+43
-46
lines changed

5 files changed

+43
-46
lines changed

store/rueidis/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ go 1.19
55
require (
66
github.com/eko/gocache/lib/v4 v4.1.1
77
github.com/golang/mock v1.6.0
8-
github.com/rueian/rueidis v0.0.86
8+
github.com/rueian/rueidis v0.0.89
99
github.com/stretchr/testify v1.8.1
1010
)
1111

store/rueidis/go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY=
77
github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
88
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
99
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
10-
github.com/rueian/rueidis v0.0.86 h1:RdzZzYnECg27zwdBHL2JN1XPVfaZclSjx6gzAQuCF/o=
11-
github.com/rueian/rueidis v0.0.86/go.mod h1:LiKWMM/QnILwRfDZIhSIXi4vQqZ/UZy4+/aNkSCt8XA=
10+
github.com/rueian/rueidis v0.0.89 h1:Q2TbuNXMJ2d2NegQ47uOoGOGPZLQwRuL0oX/dAlCh6k=
11+
github.com/rueian/rueidis v0.0.89/go.mod h1:LiKWMM/QnILwRfDZIhSIXi4vQqZ/UZy4+/aNkSCt8XA=
1212
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
1313
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
1414
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=

store/rueidis/rueidis.go

Lines changed: 27 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,8 @@ const (
2121

2222
// RueidisStore is a store for Redis
2323
type RueidisStore struct {
24-
client rueidis.Client
25-
options *lib_store.Options
26-
cacheCompat rueidiscompat.CacheCompat
27-
compat rueidiscompat.Cmdable
24+
client rueidis.Client
25+
options *lib_store.Options
2826
}
2927

3028
// NewRueidis creates a new store to Redis instance(s)
@@ -37,43 +35,39 @@ func NewRueidis(client rueidis.Client, options ...lib_store.Option) *RueidisStor
3735
}
3836

3937
return &RueidisStore{
40-
client: client,
41-
cacheCompat: rueidiscompat.NewAdapter(client).Cache(appliedOptions.ClientSideCacheExpiration),
42-
compat: rueidiscompat.NewAdapter(client),
43-
options: appliedOptions,
38+
client: client,
39+
options: appliedOptions,
4440
}
4541
}
4642

4743
// Get returns data stored from a given key
4844
func (s *RueidisStore) Get(ctx context.Context, key any) (any, error) {
49-
object := s.client.DoCache(ctx, s.client.B().Get().Key(key.(string)).Cache(), s.options.ClientSideCacheExpiration)
50-
if object.RedisError() != nil && object.RedisError().IsNil() {
51-
return nil, lib_store.NotFoundWithCause(object.Error())
45+
cmd := s.client.B().Get().Key(key.(string)).Cache()
46+
res := s.client.DoCache(ctx, cmd, s.options.ClientSideCacheExpiration)
47+
str, err := res.ToString()
48+
if rueidis.IsRedisNil(err) {
49+
err = lib_store.NotFoundWithCause(err)
5250
}
53-
return object, object.Error()
51+
return str, err
5452
}
5553

5654
// GetWithTTL returns data stored from a given key and its corresponding TTL
5755
func (s *RueidisStore) GetWithTTL(ctx context.Context, key any) (any, time.Duration, error) {
58-
// get object first
59-
object, err := s.Get(ctx, key)
60-
if err != nil {
61-
return nil, 0, err
56+
cmd := s.client.B().Get().Key(key.(string)).Cache()
57+
res := s.client.DoCache(ctx, cmd, s.options.ClientSideCacheExpiration)
58+
str, err := res.ToString()
59+
if rueidis.IsRedisNil(err) {
60+
err = lib_store.NotFoundWithCause(err)
6261
}
63-
64-
// get TTL and return
65-
ttl, err := s.cacheCompat.TTL(ctx, key.(string)).Result()
66-
if err != nil {
67-
return nil, 0, err
68-
}
69-
70-
return object, ttl, err
62+
return str, time.Duration(res.CacheTTL()) * time.Second, err
7163
}
7264

7365
// Set defines data in Redis for given key identifier
7466
func (s *RueidisStore) Set(ctx context.Context, key any, value any, options ...lib_store.Option) error {
7567
opts := lib_store.ApplyOptionsWithDefault(s.options, options...)
76-
err := s.compat.Set(ctx, key.(string), value, opts.Expiration).Err()
68+
ttl := int64(opts.Expiration.Seconds())
69+
cmd := s.client.B().Set().Key(key.(string)).Value(value.(string)).ExSeconds(ttl).Build()
70+
err := s.client.Do(ctx, cmd).Error()
7771
if err != nil {
7872
return err
7973
}
@@ -86,17 +80,19 @@ func (s *RueidisStore) Set(ctx context.Context, key any, value any, options ...l
8680
}
8781

8882
func (s *RueidisStore) setTags(ctx context.Context, key any, tags []string) {
83+
ttl := 720 * time.Hour
8984
for _, tag := range tags {
9085
tagKey := fmt.Sprintf(RueidisTagPattern, tag)
91-
s.compat.SAdd(ctx, tagKey, key.(string))
92-
s.compat.Expire(ctx, tagKey, 720*time.Hour)
86+
s.client.DoMulti(ctx,
87+
s.client.B().Sadd().Key(tagKey).Member(key.(string)).Build(),
88+
s.client.B().Expire().Key(tagKey).Seconds(int64(ttl.Seconds())).Build(),
89+
)
9390
}
9491
}
9592

9693
// Delete removes data from Redis for given key identifier
9794
func (s *RueidisStore) Delete(ctx context.Context, key any) error {
98-
_, err := s.compat.Del(ctx, key.(string)).Result()
99-
return err
95+
return s.client.Do(ctx, s.client.B().Del().Key(key.(string)).Build()).Error()
10096
}
10197

10298
// Invalidate invalidates some cache data in Redis for given options
@@ -107,7 +103,7 @@ func (s *RueidisStore) Invalidate(ctx context.Context, options ...lib_store.Inva
107103
for _, tag := range tags {
108104
tagKey := fmt.Sprintf(RueidisTagPattern, tag)
109105

110-
cacheKeys, err := s.cacheCompat.SMembers(ctx, tagKey).Result()
106+
cacheKeys, err := s.client.Do(ctx, s.client.B().Smembers().Key(tagKey).Build()).AsStrSlice()
111107
if err != nil {
112108
continue
113109
}
@@ -130,9 +126,5 @@ func (s *RueidisStore) GetType() string {
130126

131127
// Clear resets all data in the store
132128
func (s *RueidisStore) Clear(ctx context.Context) error {
133-
if err := s.compat.FlushAll(ctx).Err(); err != nil {
134-
return err
135-
}
136-
137-
return nil
129+
return rueidiscompat.NewAdapter(s.client).FlushAll(ctx).Err()
138130
}

store/rueidis/rueidis_bench_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func BenchmarkRueidisSet(b *testing.B) {
2929
b.Run(fmt.Sprintf("%d", n), func(b *testing.B) {
3030
for i := 0; i < b.N*n; i++ {
3131
key := fmt.Sprintf("test-%d", n)
32-
value := []byte(fmt.Sprintf("value-%d", n))
32+
value := fmt.Sprintf("value-%d", n)
3333

3434
store.Set(ctx, key, value, lib_store.WithTags([]string{fmt.Sprintf("tag-%d", n)}))
3535
}
@@ -51,7 +51,7 @@ func BenchmarkRueidisGet(b *testing.B) {
5151
store := NewRueidis(ruedisClient, lib_store.WithExpiration(time.Hour*4))
5252

5353
key := "test"
54-
value := []byte("value")
54+
value := "value"
5555

5656
_ = store.Set(ctx, key, value)
5757

store/rueidis/rueidis_test.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func TestRueidisGet(t *testing.T) {
3737

3838
// rueidis mock client
3939
client := mock.NewClient(ctrl)
40-
client.EXPECT().DoCache(ctx, mock.Match("GET", "my-key"), defaultClientSideCacheExpiration).Return(mock.Result(mock.RedisString("")))
40+
client.EXPECT().DoCache(ctx, mock.Match("GET", "my-key"), defaultClientSideCacheExpiration).Return(mock.Result(mock.RedisString("my-value")))
4141

4242
store := NewRueidis(client)
4343

@@ -46,7 +46,7 @@ func TestRueidisGet(t *testing.T) {
4646

4747
// Then
4848
assert.Nil(t, err)
49-
assert.NotNil(t, value)
49+
assert.Equal(t, value, "my-value")
5050
}
5151

5252
func TestRueidisGetNotFound(t *testing.T) {
@@ -66,7 +66,7 @@ func TestRueidisGetNotFound(t *testing.T) {
6666

6767
// Then
6868
assert.NotNil(t, err)
69-
assert.Nil(t, value)
69+
assert.Equal(t, value, "")
7070
}
7171

7272
func TestRueidisSet(t *testing.T) {
@@ -123,8 +123,13 @@ func TestRedisSetWithTags(t *testing.T) {
123123

124124
client := mock.NewClient(ctrl)
125125
client.EXPECT().Do(ctx, mock.Match("SET", cacheKey, cacheValue, "EX", "10")).Return(mock.Result(mock.RedisString("")))
126-
client.EXPECT().Do(ctx, mock.Match("SADD", "gocache_tag_tag1", "my-key")).Return(mock.Result(mock.RedisString("")))
127-
client.EXPECT().Do(ctx, mock.Match("EXPIRE", "gocache_tag_tag1", "2592000")).Return(mock.Result(mock.RedisString("")))
126+
client.EXPECT().DoMulti(ctx,
127+
mock.Match("SADD", "gocache_tag_tag1", "my-key"),
128+
mock.Match("EXPIRE", "gocache_tag_tag1", "2592000"),
129+
).Return([]rueidis.RedisResult{
130+
mock.Result(mock.RedisString("")),
131+
mock.Result(mock.RedisString("")),
132+
})
128133

129134
store := NewRueidis(client, lib_store.WithExpiration(time.Second*10))
130135

@@ -162,7 +167,7 @@ func TestRedisInvalidate(t *testing.T) {
162167
ctx := context.Background()
163168

164169
client := mock.NewClient(ctrl)
165-
client.EXPECT().DoCache(ctx, mock.Match("SMEMBERS", "gocache_tag_tag1"), defaultClientSideCacheExpiration).Return(mock.Result(mock.RedisArray()))
170+
client.EXPECT().Do(ctx, mock.Match("SMEMBERS", "gocache_tag_tag1")).Return(mock.Result(mock.RedisArray()))
166171
client.EXPECT().Do(ctx, mock.Match("DEL", "gocache_tag_tag1")).Return(mock.Result(mock.RedisInt64(1)))
167172

168173
store := NewRueidis(client)

0 commit comments

Comments
 (0)