cache: fix typo and optimize the naming
This commit is contained in:
parent
d8ffaffb78
commit
d216cb76fa
@ -10,6 +10,7 @@
|
|||||||
- [Fix 4435: Controller SaveToFile remove all temp file](https://github.com/beego/beego/pull/5138)
|
- [Fix 4435: Controller SaveToFile remove all temp file](https://github.com/beego/beego/pull/5138)
|
||||||
- [Fix 5079: Split signalChan into flushChan and closeChan](https://github.com/beego/beego/pull/5139)
|
- [Fix 5079: Split signalChan into flushChan and closeChan](https://github.com/beego/beego/pull/5139)
|
||||||
- [Fix 5172: protect field access with lock to avoid possible data race](https://github.com/beego/beego/pull/5210)
|
- [Fix 5172: protect field access with lock to avoid possible data race](https://github.com/beego/beego/pull/5210)
|
||||||
|
- [cache: fix typo and optimize the naming]()
|
||||||
|
|
||||||
# v2.0.7
|
# v2.0.7
|
||||||
- [Upgrade github.com/go-kit/kit, CVE-2022-24450](https://github.com/beego/beego/pull/5121)
|
- [Upgrade github.com/go-kit/kit, CVE-2022-24450](https://github.com/beego/beego/pull/5121)
|
||||||
|
|||||||
14
client/cache/bloom_filter_cache.go
vendored
14
client/cache/bloom_filter_cache.go
vendored
@ -24,7 +24,7 @@ import (
|
|||||||
|
|
||||||
type BloomFilterCache struct {
|
type BloomFilterCache struct {
|
||||||
Cache
|
Cache
|
||||||
BloomFilter
|
blm BloomFilter
|
||||||
loadFunc func(ctx context.Context, key string) (any, error)
|
loadFunc func(ctx context.Context, key string) (any, error)
|
||||||
expiration time.Duration // set cache expiration, default never expire
|
expiration time.Duration // set cache expiration, default never expire
|
||||||
}
|
}
|
||||||
@ -34,7 +34,7 @@ type BloomFilter interface {
|
|||||||
Add(data string)
|
Add(data string)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBloomFilterCache(cache Cache, ln func(context.Context, string) (any, error), blm BloomFilter,
|
func NewBloomFilterCache(cache Cache, ln func(ctx context.Context, key string) (any, error), blm BloomFilter,
|
||||||
expiration time.Duration,
|
expiration time.Duration,
|
||||||
) (*BloomFilterCache, error) {
|
) (*BloomFilterCache, error) {
|
||||||
if cache == nil || ln == nil || blm == nil {
|
if cache == nil || ln == nil || blm == nil {
|
||||||
@ -42,10 +42,10 @@ func NewBloomFilterCache(cache Cache, ln func(context.Context, string) (any, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &BloomFilterCache{
|
return &BloomFilterCache{
|
||||||
Cache: cache,
|
Cache: cache,
|
||||||
BloomFilter: blm,
|
blm: blm,
|
||||||
loadFunc: ln,
|
loadFunc: ln,
|
||||||
expiration: expiration,
|
expiration: expiration,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ func (bfc *BloomFilterCache) Get(ctx context.Context, key string) (any, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if errors.Is(err, ErrKeyNotExist) {
|
if errors.Is(err, ErrKeyNotExist) {
|
||||||
exist := bfc.BloomFilter.Test(key)
|
exist := bfc.blm.Test(key)
|
||||||
if exist {
|
if exist {
|
||||||
val, err = bfc.loadFunc(ctx, key)
|
val, err = bfc.loadFunc(ctx, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
55
client/cache/bloom_filter_cache_test.go
vendored
55
client/cache/bloom_filter_cache_test.go
vendored
@ -18,6 +18,7 @@ package cache
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -175,29 +176,31 @@ func TestBloomFilterCache_Get(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This implementation of Bloom filters cache is NOT safe for concurrent use.
|
func ExampleNewBloomFilterCache() {
|
||||||
// Uncomment the following method.
|
c := NewMemoryCache()
|
||||||
// func TestBloomFilterCache_Get_Concurrency(t *testing.T) {
|
c, err := NewBloomFilterCache(c, func(ctx context.Context, key string) (any, error) {
|
||||||
// bfc, err := NewBloomFilterCache(cacheUnderlying, loadFunc, mockBloom, time.Minute)
|
return fmt.Sprintf("hello, %s", key), nil
|
||||||
// assert.Nil(t, err)
|
}, &AlwaysExist{}, time.Minute)
|
||||||
//
|
if err != nil {
|
||||||
// _ = mockDB.Db.ClearAll(context.Background())
|
panic(err)
|
||||||
// _ = mockDB.Db.Put(context.Background(), "key_11", "value_11", 0)
|
}
|
||||||
// mockBloom.AddString("key_11")
|
|
||||||
//
|
val, err := c.Get(context.Background(), "Beego")
|
||||||
// var wg sync.WaitGroup
|
if err != nil {
|
||||||
// wg.Add(100000)
|
panic(err)
|
||||||
// for i := 0; i < 100000; i++ {
|
}
|
||||||
// key := fmt.Sprintf("key_%d", i)
|
fmt.Println(val)
|
||||||
// go func(key string) {
|
// Output:
|
||||||
// defer wg.Done()
|
// hello, Beego
|
||||||
// val, _ := bfc.Get(context.Background(), key)
|
}
|
||||||
//
|
|
||||||
// if val != nil {
|
type AlwaysExist struct {
|
||||||
// assert.Equal(t, "value_11", val)
|
}
|
||||||
// }
|
|
||||||
// }(key)
|
func (*AlwaysExist) Test(string) bool {
|
||||||
// }
|
return true
|
||||||
// wg.Wait()
|
}
|
||||||
// assert.Equal(t, int64(1), mockDB.loadCnt)
|
|
||||||
// }
|
func (*AlwaysExist) Add(string) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
4
client/cache/random_expired_cache.go
vendored
4
client/cache/random_expired_cache.go
vendored
@ -24,8 +24,8 @@ import (
|
|||||||
// RandomExpireCacheOption implement genreate random time offset expired option
|
// RandomExpireCacheOption implement genreate random time offset expired option
|
||||||
type RandomExpireCacheOption func(*RandomExpireCache)
|
type RandomExpireCacheOption func(*RandomExpireCache)
|
||||||
|
|
||||||
// WithOffsetFunc returns a RandomExpireCacheOption that configures the offset function
|
// WithRandomExpireOffsetFunc returns a RandomExpireCacheOption that configures the offset function
|
||||||
func WithOffsetFunc(fn func() time.Duration) RandomExpireCacheOption {
|
func WithRandomExpireOffsetFunc(fn func() time.Duration) RandomExpireCacheOption {
|
||||||
return func(cache *RandomExpireCache) {
|
return func(cache *RandomExpireCache) {
|
||||||
cache.offset = fn
|
cache.offset = fn
|
||||||
}
|
}
|
||||||
|
|||||||
33
client/cache/random_expired_cache_test.go
vendored
33
client/cache/random_expired_cache_test.go
vendored
@ -16,6 +16,7 @@ package cache
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@ -86,14 +87,42 @@ func TestRandomExpireCache(t *testing.T) {
|
|||||||
assert.True(t, strings.Contains(err.Error(), "key isn't exist"))
|
assert.True(t, strings.Contains(err.Error(), "key isn't exist"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWithOffsetFunc(t *testing.T) {
|
func TestWithRandomExpireOffsetFunc(t *testing.T) {
|
||||||
bm, err := NewCache("memory", `{"interval":20}`)
|
bm, err := NewCache("memory", `{"interval":20}`)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
magic := -time.Duration(rand.Int())
|
magic := -time.Duration(rand.Int())
|
||||||
cache := NewRandomExpireCache(bm, WithOffsetFunc(func() time.Duration {
|
cache := NewRandomExpireCache(bm, WithRandomExpireOffsetFunc(func() time.Duration {
|
||||||
return magic
|
return magic
|
||||||
}))
|
}))
|
||||||
// offset should return the magic value
|
// offset should return the magic value
|
||||||
assert.Equal(t, magic, cache.(*RandomExpireCache).offset())
|
assert.Equal(t, magic, cache.(*RandomExpireCache).offset())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleNewRandomExpireCache() {
|
||||||
|
mc := NewMemoryCache()
|
||||||
|
// use the default strategy which will generate random time offset (range: [3s,8s)) expired
|
||||||
|
c := NewRandomExpireCache(mc)
|
||||||
|
// so the expiration will be [1m3s, 1m8s)
|
||||||
|
err := c.Put(context.Background(), "hello", "world", time.Minute)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c = NewRandomExpireCache(mc,
|
||||||
|
// based on the expiration
|
||||||
|
WithRandomExpireOffsetFunc(func() time.Duration {
|
||||||
|
val := rand.Int31n(100)
|
||||||
|
fmt.Printf("calculate offset")
|
||||||
|
return time.Duration(val) * time.Second
|
||||||
|
}))
|
||||||
|
|
||||||
|
// so the expiration will be [1m0s, 1m100s)
|
||||||
|
err = c.Put(context.Background(), "hello", "world", time.Minute)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// calculate offset
|
||||||
|
}
|
||||||
|
|||||||
26
client/cache/read_through_test.go
vendored
26
client/cache/read_through_test.go
vendored
@ -17,6 +17,7 @@ package cache
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -143,3 +144,28 @@ func (m *MockOrm) Load(key string) (any, error) {
|
|||||||
}
|
}
|
||||||
return m.kvs[key], nil
|
return m.kvs[key], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleNewReadThroughCache() {
|
||||||
|
c := NewMemoryCache()
|
||||||
|
var err error
|
||||||
|
c, err = NewReadThroughCache(c,
|
||||||
|
// expiration, same as the expiration of key
|
||||||
|
time.Minute,
|
||||||
|
// load func, how to load data if the key is absent.
|
||||||
|
// in general, you should load data from database.
|
||||||
|
func(ctx context.Context, key string) (any, error) {
|
||||||
|
return fmt.Sprintf("hello, %s", key), nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
val, err := c.Get(context.Background(), "Beego")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fmt.Print(val)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// hello, Beego
|
||||||
|
}
|
||||||
|
|||||||
18
client/cache/singleflight_test.go
vendored
18
client/cache/singleflight_test.go
vendored
@ -16,6 +16,7 @@ package cache
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -70,3 +71,20 @@ func testSingleflightCacheConcurrencyGet(t *testing.T, bm Cache) {
|
|||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleNewSingleflightCache() {
|
||||||
|
c := NewMemoryCache()
|
||||||
|
c, err := NewSingleflightCache(c, time.Minute, func(ctx context.Context, key string) (any, error) {
|
||||||
|
return fmt.Sprintf("hello, %s", key), nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
val, err := c.Get(context.Background(), "Beego")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fmt.Print(val)
|
||||||
|
// Output:
|
||||||
|
// hello, Beego
|
||||||
|
}
|
||||||
|
|||||||
10
client/cache/write_through.go
vendored
10
client/cache/write_through.go
vendored
@ -22,24 +22,26 @@ import (
|
|||||||
"github.com/beego/beego/v2/core/berror"
|
"github.com/beego/beego/v2/core/berror"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WriteThoughCache struct {
|
type WriteThroughCache struct {
|
||||||
Cache
|
Cache
|
||||||
storeFunc func(ctx context.Context, key string, val any) error
|
storeFunc func(ctx context.Context, key string, val any) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWriteThoughCache(cache Cache, fn func(ctx context.Context, key string, val any) error) (*WriteThoughCache, error) {
|
// NewWriteThroughCache creates a write through cache pattern decorator.
|
||||||
|
// The fn is the function that persistent the key and val.
|
||||||
|
func NewWriteThroughCache(cache Cache, fn func(ctx context.Context, key string, val any) error) (*WriteThroughCache, error) {
|
||||||
if fn == nil || cache == nil {
|
if fn == nil || cache == nil {
|
||||||
return nil, berror.Error(InvalidInitParameters, "cache or storeFunc can not be nil")
|
return nil, berror.Error(InvalidInitParameters, "cache or storeFunc can not be nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
w := &WriteThoughCache{
|
w := &WriteThroughCache{
|
||||||
Cache: cache,
|
Cache: cache,
|
||||||
storeFunc: fn,
|
storeFunc: fn,
|
||||||
}
|
}
|
||||||
return w, nil
|
return w, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WriteThoughCache) Set(ctx context.Context, key string, val any, expiration time.Duration) error {
|
func (w *WriteThroughCache) Set(ctx context.Context, key string, val any, expiration time.Duration) error {
|
||||||
err := w.storeFunc(ctx, key, val)
|
err := w.storeFunc(ctx, key, val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return berror.Wrap(err, PersistCacheFailed, fmt.Sprintf("key: %s, val: %v", key, val))
|
return berror.Wrap(err, PersistCacheFailed, fmt.Sprintf("key: %s, val: %v", key, val))
|
||||||
|
|||||||
26
client/cache/write_through_test.go
vendored
26
client/cache/write_through_test.go
vendored
@ -60,7 +60,7 @@ func TestWriteThoughCache_Set(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range testCases {
|
for _, tt := range testCases {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
w, err := NewWriteThoughCache(tt.cache, tt.storeFunc)
|
w, err := NewWriteThroughCache(tt.cache, tt.storeFunc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
assert.EqualError(t, tt.wantErr, err.Error())
|
assert.EqualError(t, tt.wantErr, err.Error())
|
||||||
return
|
return
|
||||||
@ -94,7 +94,7 @@ func TestNewWriteThoughCache(t *testing.T) {
|
|||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
args args
|
args args
|
||||||
wantRes *WriteThoughCache
|
wantRes *WriteThroughCache
|
||||||
wantErr error
|
wantErr error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@ -119,7 +119,7 @@ func TestNewWriteThoughCache(t *testing.T) {
|
|||||||
cache: underlyingCache,
|
cache: underlyingCache,
|
||||||
fn: storeFunc,
|
fn: storeFunc,
|
||||||
},
|
},
|
||||||
wantRes: &WriteThoughCache{
|
wantRes: &WriteThroughCache{
|
||||||
Cache: underlyingCache,
|
Cache: underlyingCache,
|
||||||
storeFunc: storeFunc,
|
storeFunc: storeFunc,
|
||||||
},
|
},
|
||||||
@ -127,7 +127,7 @@ func TestNewWriteThoughCache(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
_, err := NewWriteThoughCache(tt.args.cache, tt.args.fn)
|
_, err := NewWriteThroughCache(tt.args.cache, tt.args.fn)
|
||||||
assert.Equal(t, tt.wantErr, err)
|
assert.Equal(t, tt.wantErr, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -135,3 +135,21 @@ func TestNewWriteThoughCache(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleNewWriteThroughCache() {
|
||||||
|
c := NewMemoryCache()
|
||||||
|
wtc, err := NewWriteThroughCache(c, func(ctx context.Context, key string, val any) error {
|
||||||
|
fmt.Printf("write data to somewhere key %s, val %v \n", key, val)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
err = wtc.Set(context.Background(),
|
||||||
|
"/biz/user/id=1", "I am user 1", time.Minute)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
// Output:
|
||||||
|
// write data to somewhere key /biz/user/id=1, val I am user 1
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user