Skip to content

Commit

Permalink
feat(freecache): v2 finish (#702)
Browse files Browse the repository at this point in the history
Co-authored-by: 彭业昌 <refrain@douyu.tv>
  • Loading branch information
PengYechang and 彭业昌 authored Feb 17, 2023
1 parent a82bb7f commit 16b9788
Show file tree
Hide file tree
Showing 13 changed files with 1,239 additions and 21 deletions.
33 changes: 12 additions & 21 deletions pkg/cache/xfreecache/cache_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package xfreecache

import (
"fmt"

"encoding/json"
"fmt"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -19,39 +18,33 @@ func TestLocalCache(t *testing.T) {
missCount := 0

tests := []struct {
name string
stu Student
stu Student
}{
{
name: "Student 1",
stu: Student{
Age: 1,
Name: "Student 1",
},
},
{
name: "Student 2",
stu: Student{
Age: 2,
Name: "Student 2",
},
},
{
name: "Student 1",
stu: Student{
Age: 1,
Name: "Student 1",
},
},
{
name: "Student 3",
stu: Student{
Age: 1,
Name: "Student 3",
},
},
{
name: "Student 2",
stu: Student{
Age: 2,
Name: "Student 2",
Expand All @@ -60,19 +53,17 @@ func TestLocalCache(t *testing.T) {
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
key := fmt.Sprintf("%d-%s", tt.stu.Age, tt.stu.Name)
result, _ := oneCache.GetAndSetCacheData(key, func() ([]byte, error) {
missCount++
fmt.Println("local cache miss hit")
ret, _ := json.Marshal(tt.stu)
return ret, nil
})
ret := Student{}
_ = json.Unmarshal(result, &ret)
fmt.Println(ret)
assert.Equalf(t, tt.stu, ret, "GetAndSetCacheData(%v) cache value error", key)
key := fmt.Sprintf("%d-%s", tt.stu.Age, tt.stu.Name)
result, _ := oneCache.GetAndSetCacheData(key, func() ([]byte, error) {
missCount++
fmt.Println("local cache miss hit")
ret, _ := json.Marshal(tt.stu)
return ret, nil
})
ret := Student{}
_ = json.Unmarshal(result, &ret)
fmt.Println(ret)
assert.Equalf(t, tt.stu, ret, "GetAndSetCacheData(%v) cache value error", key)
}
assert.Equalf(t, missCount, 3, "GetAndSetCacheData miss count error")
}
Expand Down
103 changes: 103 additions & 0 deletions pkg/cache/xfreecache/v2/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package xfreecache

import (
"fmt"

"github.com/douyu/jupiter/pkg/xlog"
"github.com/samber/lo"
"go.uber.org/zap"
)

type storage interface {
// SetCacheData 设置缓存数据 key:缓存key data:缓存数据
SetCacheData(key string, data []byte) (err error)
// GetCacheData 存储缓存数据 key:缓存key data:缓存数据
GetCacheData(key string) (data []byte, err error)
}

type cache[K comparable, V any] struct {
storage
}

// GetAndSetCacheData 获取缓存后数据
func (c *cache[K, V]) GetAndSetCacheData(key string, id K, fn func() (V, error)) (value V, err error) {
resMap, err := c.GetAndSetCacheMap(key, []K{id}, func([]K) (map[K]V, error) {
innerVal, innerErr := fn()
return map[K]V{id: innerVal}, innerErr
})
value = resMap[id]
return
}

// GetAndSetCacheMap 获取缓存后数据 map形式
func (c *cache[K, V]) GetAndSetCacheMap(key string, ids []K, fn func([]K) (map[K]V, error)) (v map[K]V, err error) {
args := []zap.Field{zap.Any("key", key), zap.Any("ids", ids)}

v = make(map[K]V)

// id去重
ids = lo.Uniq(ids)
idsNone := make([]K, 0, len(ids))
pool := getPool[V]()
for _, id := range ids {
cacheKey := c.getKey(key, id)
if resT, innerErr := c.GetCacheData(cacheKey); innerErr == nil && resT != nil {
var value V
// 反序列化
value, err = unmarshalWithPool[V](resT, pool)
if err != nil {
return
}
v[id] = value
continue
}
idsNone = append(idsNone, id)
}

if len(idsNone) == 0 {
return
}

// 执行函数
resMap, err := fn(idsNone)
if err != nil {
xlog.Jupiter().Error("GetAndSetCacheMap doMap", append(args, zap.Error(err))...)
return
}

// 填入返回中
for k, value := range resMap {
v[k] = value
}

// 写入缓存
for _, id := range idsNone {
var (
cacheData V
data []byte
)

if val, ok := v[id]; ok {
cacheData = val
}
// 序列化
data, err = marshal(cacheData)

if err != nil {
xlog.Jupiter().Error("GetAndSetCacheMap Marshal", append(args, zap.Error(err))...)
return
}

cacheKey := c.getKey(key, id)
err = c.SetCacheData(cacheKey, data)
if err != nil {
xlog.Jupiter().Error("GetAndSetCacheMap setCacheData", append(args, zap.Error(err))...)
return
}
}
return
}

func (c *cache[K, V]) getKey(key string, id K) string {
return fmt.Sprintf("%s:%v", key, id)
}
65 changes: 65 additions & 0 deletions pkg/cache/xfreecache/v2/cache_bench_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package xfreecache

import (
"strconv"
"testing"
)

func BenchmarkLocalCache_GetCacheData(b *testing.B) {
localCache := New[string, Student](DefaultConfig())

b.Run("read", func(b *testing.B) {
student := Student{10, "student1"}
for i := 0; i < b.N; i++ {
_, _ = localCache.GetAndSetCacheData("mytest", student.Name, func() (Student, error) {
res := student
return res, nil
})
}
})

b.Run("read & write", func(b *testing.B) {
for i := 0; i < b.N; i++ {
student := Student{10, "student" + strconv.Itoa(i)}
_, _ = localCache.GetAndSetCacheData("mytest", student.Name, func() (Student, error) {
res := student
return res, nil
})
}
})
}

func BenchmarkLocalCache_GetCacheMap(b *testing.B) {

localCache := New[int64, int64](DefaultConfig())

b.Run("read", func(b *testing.B) {
uidList := []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
for i := 0; i < b.N; i++ {
_, _ = localCache.GetAndSetCacheMap("mytest2", uidList, func(in []int64) (map[int64]int64, error) {
res := make(map[int64]int64)
for _, uid := range in {
res[uid] = uid
}
return res, nil
})
}
})

b.Run("read & write", func(b *testing.B) {
uidList := []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
for i := 0; i < b.N; i++ {
uidListT := make([]int64, 0, 10)
for _, uid := range uidList {
uidListT = append(uidListT, uid+int64(i))
}
_, _ = localCache.GetAndSetCacheMap("mytest2", uidListT, func(in []int64) (map[int64]int64, error) {
res := make(map[int64]int64)
for _, uid := range in {
res[uid] = uid
}
return res, nil
})
}
})
}
Loading

0 comments on commit 16b9788

Please sign in to comment.