Skip to content

Commit

Permalink
Merge pull request #370 from sljeff/cache
Browse files Browse the repository at this point in the history
remove cacheNil support, may add it back if we can find a better way to support this feature in the future
  • Loading branch information
fenngwd authored Jan 7, 2022
2 parents 9b8aaa2 + 8e25c87 commit 3ca7455
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 81 deletions.
9 changes: 9 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
# 1.0.0 (2022-01-05)

- 删除 cachext 的 cacheNil 逻辑

**BREAKING CHANGE**:

- 去掉 WithCacheNil 配置
- 以前判断了 cachext.Nil 的地方,应该改为判断响应后 out 值是否为空值

# 0.16.3 (2021-10-09)

- 修正 `DialOptions` 拼写
Expand Down
55 changes: 7 additions & 48 deletions extensions/cachext/cached.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,9 @@ import (
"github.com/prometheus/client_golang/prometheus"
)

const Nil = cacheNil("cache result is nil")

type cacheNil string

func (e cacheNil) Error() string { return string(e) }

// CachedConfig save the param and config for a cached func
type CachedConfig struct {
cache *CacheExt
cacheNil bool
ttl time.Duration
version int64
funcName string
Expand Down Expand Up @@ -72,46 +65,22 @@ func (c *CachedConfig) GetResult(ctx context.Context, out interface{}, strArgs [
// Increment hit counter.
c.cache.hitCounter.With(labels).Inc()
}
if c.cacheNil && decodeIsNil(data) {
// 无法直接把out设置为nil,这里通过返回特殊的错误来表示nil。调用方需要判断
return Nil
}
return decode(data, out)
}
res, err := c.getResult(ctx, strArgs, intArgs)
if err != nil {
return err
}
// 函数返回值与cacheNil需要设置的值相同,报错
if c.cacheNil && decodeIsNil(res) {
return errors.New("Your response is conflict with cacheNil value")
}

status := [2]bool{res == nil, c.cacheNil} // 函数返回值与是否cacheNil状态判断
cacheNilHited := [2]bool{true, true} // 函数返回值是nil,同时cacheNil。
noNeedCacheNil := [2]bool{true, false} // 函数返回值是nil,不cacheNil。

switch status {
case cacheNilHited:
// Set nil 会保存一个[]byte{192}的结构到backend中
nilBytes, _ := encode(nil)
if err = c.cache.backend.Set(ctx, c.cache.transKey(cacheKey), nilBytes, c.ttl); err != nil {
return err
}
return Nil
case noNeedCacheNil:
return Nil
default:
// 函数返回值非空,把结果放入缓存。不管是否cacheNil
if encodedBytes, err := encode(res); err != nil {
// 把结果放入缓存
if encodedBytes, err := encode(res); err != nil {
return err
} else {
err = c.cache.backend.Set(ctx, c.cache.transKey(cacheKey), encodedBytes, c.ttl)
if err != nil {
return err
} else {
err = c.cache.backend.Set(ctx, c.cache.transKey(cacheKey), encodedBytes, c.ttl)
if err != nil {
return err
}
return decode(encodedBytes, out)
}
return decode(encodedBytes, out)
}
}

Expand All @@ -125,7 +94,6 @@ func (c *CacheExt) Cached(funcName string, f cachedFunc, options ...cacheOption)
c.cachedFuncName[funcName] = void{}
cacheFuncConf := &CachedConfig{
ttl: 24 * 2 * time.Hour,
cacheNil: false,
version: 1,
cache: c,
getResult: f,
Expand Down Expand Up @@ -160,15 +128,6 @@ func WithVersion(version int64) cacheOption {
}
}

// WithCacheNil set whether cacheNil to cacheFuncConfig, if cacheNil seted and function returns nil, GetResult will return Nil
// cacheNil stored in redis with []byte{192} 0xC0
func WithCacheNil(cacheNil bool) cacheOption {
return func(config *CachedConfig) error {
config.cacheNil = cacheNil
return nil
}
}

// WithMakeCacheKey you can write your own makeCacheKey, use this func to change the default makeCacheKey.
// first param means funcName, the second param means version, next params mean real function input param.
func WithMakeCacheKey(f makeCacheKeyFunc) cacheOption {
Expand Down
9 changes: 0 additions & 9 deletions extensions/cachext/ext.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package cachext

import (
"bytes"
"context"
"errors"
"fmt"
Expand Down Expand Up @@ -248,14 +247,6 @@ func decode(data []byte, out interface{}) error {
return msgpack.Unmarshal(data, out)
}

func decodeIsNil(data interface{}) bool {
if byteData, ok := data.([]byte); ok {
err := msgpack.NewDecoder(bytes.NewReader(byteData)).DecodeNil()
return (err == nil)
}
return false
}

// Create a collector for total cache request counter
func newCacheRequestCounter() *prometheus.CounterVec {
return promauto.NewCounterVec(
Expand Down
37 changes: 13 additions & 24 deletions extensions/cachext/ext_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ func TestCacheExt_Operation(t *testing.T) {
mydata := myData{}
mydata.Value1 = 100
mydata.Value2 = "thre si a verty conplex data {}{}"
mydata.Value3 = []node{node{"这是第一个node", []string{"id1", "id2", "id3"}}, node{"这是第二个node", []string{"id4", "id5", "id6"}}}
mydata.Value3 = []node{{"这是第一个node", []string{"id1", "id2", "id3"}}, {"这是第二个node", []string{"id4", "id5", "id6"}}}
if err := cache.Set(context.Background(), "cache_key_2", mydata, 10*time.Second); err != nil {
t.Log(err)
t.Errorf("Cache Set Failed")
Expand Down Expand Up @@ -392,45 +392,34 @@ func TestCacheExt_Cached_Common(t *testing.T) {
// nil
f_nil := func(_ context.Context, names []string, arg []int64) (interface{}, error) {
call_times += 1
return nil, nil
return func() (*string, error) {
return nil, nil
}()
}
c_f_nil := cache.Cached("f_nil", f_nil, cachext.WithVersion(2), cachext.WithTTL(10*time.Second), cachext.WithCacheNil(false))
nil_res := ""
c_f_nil := cache.Cached("f_nil", f_nil, cachext.WithVersion(2), cachext.WithTTL(10*time.Second))
nil_res := "content"
call_times = 0
for i := 0; i <= 3; i++ {
err := c_f_nil.GetResult(context.Background(), &nil_res, []string{}, []int64{})
if err != cachext.Nil {
t.Errorf("Not Cache Nil failed")
if err != nil || nil_res != "" {
t.Errorf(err.Error())
}
}
if call_times != 4 {
t.Log(nil_res, call_times)
}
cn_f_nil := cache.Cached("cn_f_nil", f_nil, cachext.WithVersion(5), cachext.WithTTL(10*time.Second), cachext.WithCacheNil(true))
nil_res = "content"
cn_f_nil := cache.Cached("cn_f_nil", f_nil, cachext.WithVersion(5), cachext.WithTTL(10*time.Second))
call_times = 0
for i := 0; i <= 3; i++ {
err := cn_f_nil.GetResult(context.Background(), &nil_res, []string{}, []int64{})
if err != cachext.Nil {
t.Errorf("Cache Nil failed")
if err != nil || nil_res != "" {
t.Errorf(err.Error())
}
}
if call_times != 1 {
t.Log(nil_res, call_times)
}
// nil 测试函数返回值与cacheNil预设值冲突时,报错情况
f_evil_nil := func(_ context.Context, names []string, arg []int64) (interface{}, error) {
return []byte{192}, nil
}
c_f_evil_nil := cache.Cached("f_evil_nil", f_evil_nil, cachext.WithTTL(10*time.Second), cachext.WithVersion(2), cachext.WithCacheNil(true))
if err := c_f_evil_nil.GetResult(context.Background(), &nil_res, []string{}, []int64{}); err == nil {
t.Log(nil_res, err, call_times)
t.Errorf("Evil Cache Nil happened")
}
c_f_kind_nil := cache.Cached("c_f_kind_nil", f_evil_nil, cachext.WithTTL(10*time.Second), cachext.WithVersion(2))
if err := c_f_kind_nil.GetResult(context.Background(), &nil_res, []string{}, []int64{}); err != nil {
t.Log(nil_res, err, call_times)
t.Errorf("Evil Cache Nil happened")
}
}

func TestCacheExt_Cached_Struct(t *testing.T) {
Expand Down Expand Up @@ -463,7 +452,7 @@ func TestCacheExt_Cached_Struct(t *testing.T) {
mydata.Value2 = "thre si a verty conplex data {}{}"
some_str := "some str"
mydata.Value4 = some_str
mydata.Value3 = []node{node{"这是第一个node", []string{"id1", "id2", "id3"}}, node{"这是第二个node", []string{"id4", "id5", "id6"}}}
mydata.Value3 = []node{{"这是第一个node", []string{"id1", "id2", "id3"}}, {"这是第二个node", []string{"id4", "id5", "id6"}}}
return mydata, nil
}
cached_complex_ff := cache.Cached("complex_ff", complex_ff, cachext.WithTTL(10*time.Second))
Expand Down

0 comments on commit 3ca7455

Please sign in to comment.