1
0
mirror of https://github.com/charlienet/go-mixed.git synced 2025-07-18 00:22:41 +08:00
This commit is contained in:
2023-08-25 15:31:00 +08:00
parent 04aecd4abc
commit b0a97978d8
58 changed files with 1330 additions and 476 deletions

View File

@ -1,4 +1,4 @@
package cache
package bigcache
import (
"errors"
@ -8,8 +8,6 @@ import (
"github.com/charlienet/go-mixed/logx"
)
var _ MemCache = &bigCacheClient{}
type BigCacheConfig struct {
Shards int
LifeWindow time.Duration
@ -49,8 +47,13 @@ func NewBigCache(c BigCacheConfig) (*bigCacheClient, error) {
}, nil
}
func (c *bigCacheClient) Get(key string) ([]byte, error) {
return c.cache.Get(key)
func (c *bigCacheClient) Get(key string) ([]byte, bool) {
b, err := c.cache.Get(key)
if err == nil {
return b, false
}
return b, true
}
func (c *bigCacheClient) Set(key string, entry []byte, expire time.Duration) error {
@ -68,9 +71,23 @@ func (c *bigCacheClient) Delete(keys ...string) error {
return nil
}
func (c *bigCacheClient) Exist(key string) {
func (c *bigCacheClient) Exist(key string) bool {
_, err := c.cache.Get(key)
if err == nil {
return true
}
return !errors.Is(err, bigcache.ErrEntryNotFound)
}
func (c *bigCacheClient) Clear() {
}
func (c *bigCacheClient) IsNotFound(err error) bool {
return errors.Is(err, bigcache.ErrEntryNotFound)
if err == nil {
return true
}
return !errors.Is(err, bigcache.ErrEntryNotFound)
}

27
cache/bigcache/big_cache_test.go vendored Normal file
View File

@ -0,0 +1,27 @@
package bigcache
import (
"testing"
"time"
"github.com/stretchr/testify/require"
)
func TestBigCache(t *testing.T) {
r := require.New(t)
c, err := NewBigCache(BigCacheConfig{})
r.Nil(err)
cacheKey := "a"
cacheValue := "bbb"
c.Set(cacheKey, []byte(cacheValue), time.Second*5)
r.True(c.Exist(cacheKey))
r.False(c.Exist("abb"))
b, ok := c.Get(cacheKey)
r.True(ok)
r.Equal(cacheValue, string(b))
}

170
cache/cache.go vendored
View File

@ -6,62 +6,73 @@ import (
"fmt"
"time"
"github.com/charlienet/go-mixed/bytesconv"
"github.com/charlienet/go-mixed/json"
"github.com/charlienet/go-mixed/locker"
"github.com/charlienet/go-mixed/logx"
"golang.org/x/sync/singleflight"
)
var ErrNotFound = errors.New("key not found")
// 数据加载函数定义
type LoadFunc func(context.Context) (any, error)
type Cache struct {
prefix string // 键前缀
retry int // 资源获取时的重试次数
mem MemCache // 内存缓存
distributdCache DistributdCache // 分布式缓存
publishSubscribe PublishSubscribe // 发布订阅
lock locker.ChanLocker // 资源锁
stats *Stats // 缓存命中计数
qps *qps // 访问计数
logger logx.Logger // 日志记录
type ICache interface {
}
func NewCache(opts ...option) *Cache {
type Cache struct {
prefix string // 键前缀
retry int // 资源获取时的重试次数
mem MemCache // 内存缓存
rds DistributedCache // 远程缓存
publishSubscribe PublishSubscribe // 发布订阅
group singleflight.Group // singleflight.Group
lock locker.ChanLocker // 资源锁
stats *Stats // 缓存命中计数
qps *qps // 访问计数
logger logx.Logger // 日志记录
}
func New(opts ...option) (*Cache, error) {
c := acquireDefaultCache()
for _, f := range opts {
if err := f(c); err != nil {
return c
return c, nil
}
}
go c.subscribe()
// 未设置内存缓存时,添加默认缓存
if c.mem == nil {
c.mem = NewTinyLFU(1<<12, time.Second*30)
}
return c
return c, nil
}
func (c *Cache) Set(key string, value any, expiration time.Duration) error {
if c.mem != nil {
bytes, err := bytesconv.Encode(value)
if err != nil {
return err
}
func (c *Cache) Set(ctx context.Context, key string, value any, expiration time.Duration) error {
buf, err := Marshal(value)
if err != nil {
return err
}
c.mem.Set(key, bytes, expiration)
if c.mem != nil {
c.mem.Set(key, buf, expiration)
}
if c.rds != nil {
c.rds.Set(ctx, key, buf, expiration)
}
return nil
}
func (c *Cache) Get(key string, out any) error {
func (c *Cache) Get(ctx context.Context, key string, out any) error {
if c.mem != nil {
c.getFromMem(key, out)
c.getFromMem(key)
}
if c.distributdCache != nil {
if err := c.distributdCache.Get(key, out); err != nil {
if c.rds != nil {
if err := c.rds.Get(ctx, key, out); err != nil {
}
}
@ -70,7 +81,7 @@ func (c *Cache) Get(key string, out any) error {
}
func (c *Cache) GetFn(ctx context.Context, key string, out any, fn LoadFunc, expiration time.Duration) (bool, error) {
c.Get(key, out)
c.Get(ctx, key, out)
// 多级缓存中未找到时,放置缓存对象
ret, err := fn(ctx)
@ -78,7 +89,7 @@ func (c *Cache) GetFn(ctx context.Context, key string, out any, fn LoadFunc, exp
return false, err
}
c.Set(key, ret, expiration)
c.Set(ctx, key, ret, expiration)
return false, nil
}
@ -87,32 +98,69 @@ func (c *Cache) Exist(key string) (bool, error) {
return false, nil
}
func (c *Cache) Delete(key ...string) error {
func (c *Cache) Delete(ctx context.Context, key ...string) error {
if c.mem != nil {
c.mem.Delete(key...)
}
if c.distributdCache != nil {
c.distributdCache.Delete(key...)
if c.rds != nil {
c.rds.Delete(ctx, key...)
}
for _, k := range key {
c.group.Forget(k)
}
return nil
}
func (c *Cache) subscribe() {
// 清除本地缓存
func (c *Cache) ClearMem() {
if c.mem != nil {
c.mem.Clear()
}
}
func (c *Cache) getFromMem(key string, out any) error {
bytes, err := c.mem.Get(key)
if err != nil {
return err
}
func (c *Cache) Clear() {
if err := bytesconv.Decode(bytes, out); err != nil {
return err
}
}
return nil
func (c *Cache) Disable() {
}
func (c *Cache) Enable() {
}
func (c *Cache) getOnce(ctx context.Context, key string) (b []byte, cached bool, err error) {
if c.mem != nil {
b, ok := c.mem.Get(key)
if ok {
return b, true, nil
}
}
c.group.Do(key, func() (any, error) {
if c.mem != nil {
b, ok := c.mem.Get(key)
if ok {
return b, nil
}
}
if c.rds != nil {
c.rds.Get(ctx, key, nil)
}
return nil, nil
})
return
}
func (c *Cache) getFromMem(key string) ([]byte, bool) {
bytes, cached := c.mem.Get(key)
return bytes, cached
}
// 从缓存加载数据
@ -125,8 +173,6 @@ func (c *Cache) getFromCache() {
// 从数据源加载数据
func (c *Cache) getFromSource(ctx context.Context, key string, fn LoadFunc) error {
// 1. 尝试获取资源锁,如成功获取到锁加载数据
// 2. 未获取到锁,等待从缓存中获取
ch, ok := c.lock.Get(key)
if ok {
defer c.lock.Release(key)
@ -150,39 +196,3 @@ func (c *Cache) getFromSource(ctx context.Context, key string, fn LoadFunc) erro
return c.getFromSource(ctx, key, fn)
}
}
func (c *Cache) marshal(value any) ([]byte, error) {
switch value := value.(type) {
case nil:
return nil, nil
case []byte:
return value, nil
case string:
return []byte(value), nil
}
b, err := json.Marshal(value)
return b, err
}
func (c *Cache) unmarshal(b []byte, value any) error {
if len(b) == 0 {
return nil
}
switch value := value.(type) {
case nil:
return nil
case *[]byte:
clone := make([]byte, len(b))
copy(clone, b)
*value = clone
return nil
case *string:
*value = string(b)
return nil
}
err := json.Unmarshal(b, value)
return err
}

128
cache/cache_builder.go vendored
View File

@ -1,99 +1,81 @@
package cache
import "github.com/charlienet/go-mixed/logx"
import (
"context"
"time"
"github.com/charlienet/go-mixed/cache/bigcache"
"github.com/charlienet/go-mixed/cache/freecache"
"github.com/charlienet/go-mixed/logx"
)
const defaultPrefix = "cache"
type option func(*Cache) error
type options struct {
Prefix string
}
func acquireDefaultCache() *Cache {
return &Cache{
prefix: defaultPrefix,
qps: NewQps(),
func WithRedis(opts RedisConfig) option {
return func(c *Cache) error {
if len(opts.Prefix) == 0 {
opts.Prefix = defaultPrefix
}
rds := NewRedis(opts)
c.rds = rds
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
defer cancel()
return rds.Ping(ctx)
}
}
type cacheBuilder struct {
prefix string
redisOptions RedisConfig
bigCacheConfig BigCacheConfig
freeSize int
publishSubscribe PublishSubscribe
log logx.Logger
func WithBigCache(opts bigcache.BigCacheConfig) option {
return func(c *Cache) error {
mem, err := bigcache.NewBigCache(opts)
c.mem = mem
return err
}
}
func NewCacheBuilder() *cacheBuilder {
return &cacheBuilder{}
}
func WithFreeCache(size int) option {
return func(c *Cache) error {
mem := freecache.NewFreeCache(size)
c.mem = mem
func (b *cacheBuilder) WithLogger(log logx.Logger) *cacheBuilder {
b.log = log
return b
}
func (b *cacheBuilder) WithPrefix(prefix string) *cacheBuilder {
b.prefix = prefix
return b
}
func (b *cacheBuilder) WithRedis(opts RedisConfig) *cacheBuilder {
b.redisOptions = opts
return b
}
func (b *cacheBuilder) WithBigCache(opts BigCacheConfig) *cacheBuilder {
b.bigCacheConfig = opts
return b
}
func (b *cacheBuilder) WithFreeCache(size int) *cacheBuilder {
b.freeSize = size
return b
return nil
}
}
// 使用自定义分布式缓存
func WithDistributedCache(c DistributdCache) {
func WithDistributedCache(rds DistributedCache) option {
return func(c *Cache) error {
c.rds = rds
return nil
}
}
func (b *cacheBuilder) WithPublishSubscribe(p PublishSubscribe) *cacheBuilder {
b.publishSubscribe = p
return b
func WithPublishSubscribe(p PublishSubscribe) option {
return func(c *Cache) error {
return nil
}
}
func (b cacheBuilder) Build() (*Cache, error) {
var err error
cache := acquireDefaultCache()
if len(b.prefix) > 0 {
cache.prefix = b.prefix
func WithLogger(log logx.Logger) option {
return func(c *Cache) error {
c.logger = log
return nil
}
}
func acquireDefaultCache() *Cache {
return &Cache{
qps: NewQps(),
}
b.redisOptions.Prefix = cache.prefix
redis := NewRedis(b.redisOptions)
if err := redis.Ping(); err != nil {
return cache, err
}
var mem MemCache
if b.freeSize > 0 {
mem = NewFreeCache(b.freeSize)
} else {
if b.log != nil {
b.bigCacheConfig.log = b.log
}
mem, err = NewBigCache(b.bigCacheConfig)
}
cache.distributdCache = redis
cache.mem = mem
cache.publishSubscribe = b.publishSubscribe
cache.logger = b.log
return cache, err
}

View File

@ -3,27 +3,38 @@ package cache
import (
"testing"
"time"
"github.com/charlienet/go-mixed/logx"
)
func TestBuilder(t *testing.T) {
cache, err := NewCacheBuilder().
WithLogger(logx.NewLogrus(logx.WithFormatter(logx.NewNestedFormatter(logx.NestedFormatterOption{
Color: true,
})))).
WithRedis(RedisConfig{
Addrs: []string{"192.168.2.222:6379"},
Password: "123456",
}).
WithBigCache(BigCacheConfig{}).
// WithFreeCache(10 * 1024 * 1024).
Build()
now := time.Now()
t.Log(now)
t1, _ := time.ParseDuration("9h27m")
t1 += time.Hour * 24
t2, _ := time.ParseDuration("16h28m")
t.Log(t1)
t.Log(t2)
if err != nil {
t.Fatal(err)
}
f := time.Date(2022, time.December, 12, 8, 0, 0, 0, time.Local)
t.Log(f.Sub(time.Now()))
u := SimpleUser{FirstName: "Radomir", LastName: "Sohlich"}
t.Log(cache.Set(defaultKey, u, time.Minute*10))
// cache, err := New(
// WithLogger(logx.NewLogrus(logx.WithNestedFormatter(logx.NestedFormatterOption{
// Color: true,
// }))).
// UseRedis(RedisConfig{
// Addrs: []string{"192.168.2.222:6379"},
// Password: "123456",
// }).
// UseBigCache(bigcache.BigCacheConfig{}).
// Build()
// if err != nil {
// t.Fatal(err)
// }
// ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
// defer cancel()
// u := SimpleUser{FirstName: "Radomir", LastName: "Sohlich"}
// t.Log(cache.Set(ctx, defaultKey, u, time.Minute*10))
}

12
cache/cache_preload.go vendored Normal file
View File

@ -0,0 +1,12 @@
package cache
import "context"
// PreLoadItem 预加载数据项
type PreLoadItem struct {
Key string
Value any
}
// PreloadFunc 数据预加载函数定义
type PreloadFunc func(context.Context) ([]PreLoadItem, error)

85
cache/cache_test.go vendored
View File

@ -6,9 +6,6 @@ import (
"sync/atomic"
"testing"
"time"
"github.com/charlienet/go-mixed/bytesconv"
"github.com/charlienet/go-mixed/logx"
)
var (
@ -16,25 +13,26 @@ var (
)
func TestNewCache(t *testing.T) {
c, err := NewCacheBuilder().
WithRedis(RedisConfig{
Addrs: []string{"192.168.2.222:6379"},
Password: "123456",
}).
WithPrefix("cache_test").
WithLogger(logx.NewLogrus()).
Build()
// c, err := NewCacheBuilder().
// UseRedis(RedisConfig{
// Addrs: []string{"192.168.2.222:6379"},
// Password: "123456",
// }).
// WithPrefix("cache_test").
// WithLogger(logx.NewLogrus()).
// Build()
if err != nil {
t.Fatal(err)
}
// if err != nil {
// t.Fatal(err)
// }
c.Set("abc", "value", time.Minute*10)
// ctx := context.Background()
// c.Set(ctx, "abc", "value", time.Minute*10)
var s string
c.Get("abc", &s)
// var s string
// c.Get(ctx, "abc", &s)
t.Log(s)
// t.Log(s)
}
type SimpleUser struct {
@ -43,45 +41,43 @@ type SimpleUser struct {
}
func TestMemCache(t *testing.T) {
b, _ := NewBigCache(BigCacheConfig{})
var mems = []MemCache{
NewFreeCache(10 * 1024 * 1024),
b,
}
// b, _ := bigcache.NewBigCache(bigcache.BigCacheConfig{})
// var mems = []MemCache{
// NewFreeCache(10 * 1024 * 1024),
// b,
// }
u := SimpleUser{FirstName: "Radomir", LastName: "Sohlich"}
encoded, _ := bytesconv.Encode(u)
for _, m := range mems {
m.Set(defaultKey, encoded, time.Second)
ret, err := m.Get(defaultKey)
if err != nil {
t.Fatal(err)
}
// u := SimpleUser{FirstName: "Radomir", LastName: "Sohlich"}
// encoded, _ := bytesconv.Encode(u)
// for _, m := range mems {
// m.Set(defaultKey, encoded, time.Second)
// ret, _ := m.Get(defaultKey)
var u2 SimpleUser
bytesconv.Decode(ret, &u2)
t.Log(u2)
}
// var u2 SimpleUser
// bytesconv.Decode(ret, &u2)
// t.Log(u2)
// }
}
func TestDistributedCache(t *testing.T) {
c := NewRedis(RedisConfig{Addrs: []string{"192.168.2.222:6379"}, DB: 6, Password: "123456", Prefix: "abcdef"})
if err := c.Ping(); err != nil {
ctx := context.Background()
if err := c.Ping(ctx); err != nil {
t.Fatal(err)
}
t.Log(c.Exist(defaultKey))
t.Log(c.Exist(ctx, defaultKey))
u := SimpleUser{FirstName: "redis client"}
var u2 SimpleUser
c.Get(defaultKey, &u2)
c.Get(ctx, defaultKey, &u2)
c.Set(defaultKey, u, time.Minute*10)
t.Log(c.Exist(defaultKey))
c.Set(ctx, defaultKey, u, time.Minute*10)
t.Log(c.Exist(ctx, defaultKey))
if err := c.Get(defaultKey, &u2); err != nil {
if err := c.Get(ctx, defaultKey, &u2); err != nil {
t.Fatal("err:", err)
}
t.Logf("%+v", u2)
@ -136,10 +132,9 @@ func load() (any, error) {
}
func buildCache() *Cache {
c, err := NewCacheBuilder().
WithFreeCache(10 * 1024 * 1024).
WithRedis(RedisConfig{Addrs: []string{"192.168.2.222:6379"}, DB: 6, Password: "123456"}).
Build()
c, err := New(
WithFreeCache(10*1024*1024),
WithRedis(RedisConfig{Addrs: []string{"192.168.2.222:6379"}, DB: 6, Password: "123456"}))
if err != nil {
panic(err)

View File

@ -1,10 +0,0 @@
package cache
import "time"
type DistributdCache interface {
Get(key string, out any) error
Set(key string, value any, expiration time.Duration) error
Delete(key ...string) error
Ping() error
}

14
cache/distributed_cache.go vendored Normal file
View File

@ -0,0 +1,14 @@
package cache
import (
"context"
"time"
)
// 分布式缓存接口
type DistributedCache interface {
Get(ctx context.Context, key string, out any) error
Set(ctx context.Context, key string, value any, expiration time.Duration) error
Delete(ctx context.Context, key ...string) error
Ping(ctx context.Context) error
}

10
cache/empty_cache_adaper.go vendored Normal file
View File

@ -0,0 +1,10 @@
package cache
import "context"
// var emptyCache DistributedCache = &emptyCacheAdapter{}
type emptyCacheAdapter struct {
}
func (*emptyCacheAdapter) Delete(ctx context.Context, keys ...string) {}

View File

@ -1,4 +1,4 @@
package cache
package freecache
import (
"errors"
@ -10,8 +10,6 @@ import (
const defaultSize = 10 * 1024 * 1024 // 10M
var _ MemCache = &freeCache{}
type freeCache struct {
cache *freecache.Cache
}
@ -29,8 +27,12 @@ func NewFreeCache(size int) *freeCache {
}
}
func (c *freeCache) Get(key string) ([]byte, error) {
return c.cache.Get([]byte(key))
func (c *freeCache) Get(key string) ([]byte, bool) {
b, err := c.cache.Get([]byte(key))
if err != nil {
return b, false
}
return b, true
}
func (c *freeCache) Set(key string, value []byte, d time.Duration) error {
@ -54,6 +56,10 @@ func (c *freeCache) Exist(key string) error {
return nil
}
func (c *freeCache) Clear() {
}
func (c *freeCache) IsNotFound(err error) bool {
return errors.Is(err, freecache.ErrNotFound)
}

1
cache/freecache/free_cache_test.go vendored Normal file
View File

@ -0,0 +1 @@
package freecache

View File

@ -1,7 +0,0 @@
package cache
type LocalCache interface {
Set(key string, data []byte)
Get(key string) ([]byte, bool)
Del(key string)
}

2
cache/lru.go vendored Normal file
View File

@ -0,0 +1,2 @@
package cache

5
cache/mem.go vendored
View File

@ -3,7 +3,8 @@ package cache
import "time"
type MemCache interface {
Get(key string) ([]byte, error)
Set(key string, entry []byte, expire time.Duration) error
Get(key string) ([]byte, bool)
Set(key string, b []byte, expire time.Duration) error
Delete(key ...string) error
Clear()
}

43
cache/msg_pack.go vendored Normal file
View File

@ -0,0 +1,43 @@
package cache
import (
"github.com/vmihailenco/msgpack/v5"
)
func Marshal(v any) ([]byte, error) {
switch v := v.(type) {
case nil:
return nil, nil
case []byte:
return v, nil
case string:
return []byte(v), nil
}
b, err := msgpack.Marshal(v)
if err != nil {
return nil, err
}
return b, err
}
func Unmarshal(b []byte, v any) error {
if len(b) == 0 {
return nil
}
switch v := v.(type) {
case nil:
return nil
case *[]byte:
clone := make([]byte, len(b))
copy(clone, b)
*v = clone
case *string:
*v = string(b)
return nil
}
return msgpack.Unmarshal(b, v)
}

6
cache/qps.go vendored
View File

@ -31,7 +31,9 @@ func (q *qps) statisticsTotal() {
}
}()
ticker := time.NewTicker(time.Second)
ticker := time.NewTicker(time.Minute)
defer ticker.Stop()
for range ticker.C {
q.all.viewTotal = atomic.SwapInt64(&q.all.total, 0)
q.memoryTotal.viewTotal = atomic.SwapInt64(&q.memoryTotal.total, 0)
@ -39,5 +41,7 @@ func (q *qps) statisticsTotal() {
q.redisTotal.viewTotal = atomic.SwapInt64(&q.redisTotal.total, 0)
q.redisHit.viewTotal = atomic.SwapInt64(&q.redisHit.total, 0)
q.sourceTotal.viewTotal = atomic.SwapInt64(&q.sourceTotal.total, 0)
// percnt := 0
}
}

8
cache/readme.md vendored
View File

@ -14,6 +14,14 @@
## 使用方式
创建
```go
cache.New().UseRedis().UseBigCache().Build()
```
```go
Cache.Get(key, dist, func() (bool,error){}, options func(){})
Cache.GetFn(context, key, dist, func() (bool, error))
```

14
cache/redis.go vendored
View File

@ -54,7 +54,7 @@ func NewRedis(c RedisConfig) *redisClient {
}
}
func (c *redisClient) Get(key string, out any) error {
func (c *redisClient) Get(cxt context.Context, key string, out any) error {
val, err := c.client.Get(context.Background(), c.getKey(key)).Result()
if errors.Is(err, redis.Nil) {
return ErrNotFound
@ -72,23 +72,23 @@ func (c *redisClient) Get(key string, out any) error {
return json.Unmarshal(bytesconv.StringToBytes(val), out)
}
func (c *redisClient) Set(key string, value any, expiration time.Duration) error {
func (c *redisClient) Set(ctx context.Context, key string, value any, expiration time.Duration) error {
j, _ := json.Marshal(value)
return c.client.Set(context.Background(), c.getKey(key), j, expiration).Err()
}
func (c *redisClient) Exist(key string) (bool, error) {
func (c *redisClient) Exist(ctx context.Context, key string) (bool, error) {
val, err := c.client.Exists(context.Background(), c.getKey(key)).Result()
return val > 0, err
}
func (c *redisClient) Delete(key ...string) error {
func (c *redisClient) Delete(ctx context.Context, key ...string) error {
keys := make([]string, 0, len(key))
for _, k := range key {
keys = append(keys, c.getKey(k))
}
_ , err := c.client.Del(context.Background(), keys...).Result()
_, err := c.client.Del(context.Background(), keys...).Result()
if err != nil {
return err
}
@ -96,8 +96,8 @@ func (c *redisClient) Delete(key ...string) error {
return nil
}
func (c *redisClient) Ping() error {
_, err := c.client.Ping(context.Background()).Result()
func (c *redisClient) Ping(ctx context.Context) error {
_, err := c.client.Ping(ctx).Result()
return err
}

4
cache/stats.go vendored
View File

@ -7,11 +7,11 @@ type Stats struct {
Misses uint64
}
func (s *Stats) AddHits() {
func (s *Stats) IncrementHits() {
atomic.AddUint64(&s.Hits, 1)
}
func (s *Stats) AddMisses() {
func (s *Stats) IncrementMisses() {
atomic.AddUint64(&s.Misses, 1)
}

22
cache/tiny_lfu.go vendored
View File

@ -7,6 +7,8 @@ import (
"github.com/vmihailenco/go-tinylfu"
)
var _ MemCache = &TinyLFU{}
type TinyLFU struct {
mu locker.Locker
lfu *tinylfu.T
@ -21,15 +23,17 @@ func NewTinyLFU(size int, ttl time.Duration) *TinyLFU {
}
}
func (c *TinyLFU) Set(key string, b []byte, expire time.Duration) {
func (c *TinyLFU) Set(key string, b []byte, expire time.Duration) error {
c.mu.Lock()
defer c.mu.Unlock()
c.lfu.Set(&tinylfu.Item{
Key: key,
Value: b,
Key: key,
Value: b,
ExpireAt: time.Now().Add(c.ttl),
})
return nil
}
func (c *TinyLFU) Get(key string) ([]byte, bool) {
@ -44,9 +48,17 @@ func (c *TinyLFU) Get(key string) ([]byte, bool) {
return val.([]byte), true
}
func (c *TinyLFU) Del(key string) {
func (c *TinyLFU) Delete(keys ...string) error {
c.mu.Lock()
defer c.mu.Unlock()
c.lfu.Del(key)
for _, k := range keys {
c.lfu.Del(k)
}
return nil
}
func (c *TinyLFU) Clear() {
}