Merge pull request #5001 from ktalg/develop

fix: nil offset function of RandomExpireCache instance
This commit is contained in:
Ming Deng 2022-06-29 21:19:39 +08:00 committed by GitHub
commit 3eb35c710c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 44 additions and 10 deletions

View File

@ -17,12 +17,20 @@ package cache
import ( import (
"context" "context"
"math/rand" "math/rand"
"sync/atomic"
"time" "time"
) )
// 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
func WithOffsetFunc(fn func() time.Duration) RandomExpireCacheOption {
return func(cache *RandomExpireCache) {
cache.offset = fn
}
}
// RandomExpireCache prevent cache batch invalidation // RandomExpireCache prevent cache batch invalidation
// Cache random time offset expired // Cache random time offset expired
type RandomExpireCache struct { type RandomExpireCache struct {
@ -38,15 +46,30 @@ func (rec *RandomExpireCache) Put(ctx context.Context, key string, val interface
// NewRandomExpireCache return random expire cache struct // NewRandomExpireCache return random expire cache struct
func NewRandomExpireCache(adapter Cache, opts ...RandomExpireCacheOption) Cache { func NewRandomExpireCache(adapter Cache, opts ...RandomExpireCacheOption) Cache {
var rec RandomExpireCache rec := RandomExpireCache{
rec.Cache = adapter Cache: adapter,
offset: defaultExpiredFunc(),
}
for _, fn := range opts { for _, fn := range opts {
fn(&rec) fn(&rec)
} }
return &rec return &rec
} }
// defaultExpiredFunc genreate random time offset expired // defaultExpiredFunc return a func that used to generate random time offset (range: [3s,8s)) expired
func defaultExpiredFunc() time.Duration { func defaultExpiredFunc() func() time.Duration {
return time.Duration(rand.Intn(5)+3) * time.Second const size = 5
var randTimes [size]time.Duration
for i := range randTimes {
randTimes[i] = time.Duration(i+3) * time.Second
}
// shuffle values
for i := range randTimes {
n := rand.Intn(size)
randTimes[i], randTimes[n] = randTimes[n], randTimes[i]
}
var i uint64
return func() time.Duration {
return randTimes[atomic.AddUint64(&i, 1)%size]
}
} }

View File

@ -16,6 +16,7 @@ package cache
import ( import (
"context" "context"
"math/rand"
"strings" "strings"
"testing" "testing"
"time" "time"
@ -27,10 +28,9 @@ func TestRandomExpireCache(t *testing.T) {
bm, err := NewCache("memory", `{"interval":20}`) bm, err := NewCache("memory", `{"interval":20}`)
assert.Nil(t, err) assert.Nil(t, err)
// cache := NewRandomExpireCache(bm) cache := NewRandomExpireCache(bm)
cache := NewRandomExpireCache(bm, func(opt *RandomExpireCache) { // should not be nil
opt.offset = defaultExpiredFunc assert.NotNil(t, cache.(*RandomExpireCache).offset)
})
timeoutDuration := 3 * time.Second timeoutDuration := 3 * time.Second
@ -84,5 +84,16 @@ func TestRandomExpireCache(t *testing.T) {
assert.NotNil(t, err) assert.NotNil(t, err)
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) {
bm, err := NewCache("memory", `{"interval":20}`)
assert.Nil(t, err)
magic := -time.Duration(rand.Int())
cache := NewRandomExpireCache(bm, WithOffsetFunc(func() time.Duration {
return magic
}))
// offset should return the magic value
assert.Equal(t, magic, cache.(*RandomExpireCache).offset())
} }