-
Notifications
You must be signed in to change notification settings - Fork 699
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
13 changed files
with
1,239 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
}) | ||
} | ||
}) | ||
} |
Oops, something went wrong.