From 4f8e984df652a78473d11934d88e2c41f3a3e391 Mon Sep 17 00:00:00 2001 From: kevinzeng Date: Tue, 28 Jun 2022 12:45:37 +0800 Subject: [PATCH 1/4] fix: expose the Offset property to allow external modifications --- client/cache/random_expired_cache.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/client/cache/random_expired_cache.go b/client/cache/random_expired_cache.go index eeebf880..59b3d2ad 100644 --- a/client/cache/random_expired_cache.go +++ b/client/cache/random_expired_cache.go @@ -27,12 +27,12 @@ type RandomExpireCacheOption func(*RandomExpireCache) // Cache random time offset expired type RandomExpireCache struct { Cache - offset func() time.Duration + Offset func() time.Duration } // Put random time offset expired func (rec *RandomExpireCache) Put(ctx context.Context, key string, val interface{}, timeout time.Duration) error { - timeout += rec.offset() + timeout += rec.Offset() return rec.Cache.Put(ctx, key, val, timeout) } @@ -43,6 +43,9 @@ func NewRandomExpireCache(adapter Cache, opts ...RandomExpireCacheOption) Cache for _, fn := range opts { fn(&rec) } + if rec.Offset == nil { + rec.Offset = defaultExpiredFunc + } return &rec } From 6edee6c9c97a51411e64deb8ab2a9bc6fad8b89c Mon Sep 17 00:00:00 2001 From: kevinzeng Date: Tue, 28 Jun 2022 13:17:48 +0800 Subject: [PATCH 2/4] improving the concurrency performance of random value calculation --- client/cache/random_expired_cache.go | 22 ++++++++++++++++++---- client/cache/random_expired_cache_test.go | 2 +- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/client/cache/random_expired_cache.go b/client/cache/random_expired_cache.go index 59b3d2ad..afa2e9b9 100644 --- a/client/cache/random_expired_cache.go +++ b/client/cache/random_expired_cache.go @@ -17,6 +17,7 @@ package cache import ( "context" "math/rand" + "sync/atomic" "time" ) @@ -44,12 +45,25 @@ func NewRandomExpireCache(adapter Cache, opts ...RandomExpireCacheOption) Cache fn(&rec) } if rec.Offset == nil { - rec.Offset = defaultExpiredFunc + rec.Offset = defaultExpiredFunc() } return &rec } -// defaultExpiredFunc genreate random time offset expired -func defaultExpiredFunc() time.Duration { - return time.Duration(rand.Intn(5)+3) * time.Second +// defaultExpiredFunc return a func that used to generate random time offset (range: [3s,8s)) expired +func defaultExpiredFunc() func() time.Duration { + const size = 5 + var randTimes [size]time.Duration + for i := range randTimes { + randTimes[i] = time.Duration(i + 3) + } + // 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] + } } diff --git a/client/cache/random_expired_cache_test.go b/client/cache/random_expired_cache_test.go index b1af5840..924db5f3 100644 --- a/client/cache/random_expired_cache_test.go +++ b/client/cache/random_expired_cache_test.go @@ -29,7 +29,7 @@ func TestRandomExpireCache(t *testing.T) { // cache := NewRandomExpireCache(bm) cache := NewRandomExpireCache(bm, func(opt *RandomExpireCache) { - opt.offset = defaultExpiredFunc + opt.Offset = defaultExpiredFunc() }) timeoutDuration := 3 * time.Second From 178440bcdd04d632c7997599df9dfa773dc142d7 Mon Sep 17 00:00:00 2001 From: Kevin Tsang <39397413+ktalg@users.noreply.github.com> Date: Wed, 29 Jun 2022 14:11:42 +0800 Subject: [PATCH 3/4] add WithOffsetFunc to define private RandomExpireCache.offset field --- client/cache/random_expired_cache.go | 20 +++++++++++++------- client/cache/random_expired_cache_test.go | 21 ++++++++++++++++----- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/client/cache/random_expired_cache.go b/client/cache/random_expired_cache.go index afa2e9b9..e69d2dd8 100644 --- a/client/cache/random_expired_cache.go +++ b/client/cache/random_expired_cache.go @@ -24,29 +24,35 @@ import ( // RandomExpireCacheOption implement genreate random time offset expired option 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 // Cache random time offset expired type RandomExpireCache struct { Cache - Offset func() time.Duration + offset func() time.Duration } // Put random time offset expired func (rec *RandomExpireCache) Put(ctx context.Context, key string, val interface{}, timeout time.Duration) error { - timeout += rec.Offset() + timeout += rec.offset() return rec.Cache.Put(ctx, key, val, timeout) } // NewRandomExpireCache return random expire cache struct func NewRandomExpireCache(adapter Cache, opts ...RandomExpireCacheOption) Cache { - var rec RandomExpireCache - rec.Cache = adapter + rec := RandomExpireCache{ + Cache: adapter, + offset: defaultExpiredFunc(), + } for _, fn := range opts { fn(&rec) } - if rec.Offset == nil { - rec.Offset = defaultExpiredFunc() - } return &rec } diff --git a/client/cache/random_expired_cache_test.go b/client/cache/random_expired_cache_test.go index 924db5f3..1e3bb935 100644 --- a/client/cache/random_expired_cache_test.go +++ b/client/cache/random_expired_cache_test.go @@ -16,6 +16,7 @@ package cache import ( "context" + "math/rand" "strings" "testing" "time" @@ -27,10 +28,9 @@ func TestRandomExpireCache(t *testing.T) { bm, err := NewCache("memory", `{"interval":20}`) assert.Nil(t, err) - // cache := NewRandomExpireCache(bm) - cache := NewRandomExpireCache(bm, func(opt *RandomExpireCache) { - opt.Offset = defaultExpiredFunc() - }) + cache := NewRandomExpireCache(bm) + // should not be nil + assert.NotNil(t, cache.(*RandomExpireCache).offset) timeoutDuration := 3 * time.Second @@ -84,5 +84,16 @@ func TestRandomExpireCache(t *testing.T) { assert.NotNil(t, err) 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()) } From fa4cc95fd454b2b07cb30ac951f7915ba57ea4b8 Mon Sep 17 00:00:00 2001 From: Kevin Tsang <39397413+ktalg@users.noreply.github.com> Date: Wed, 29 Jun 2022 14:13:52 +0800 Subject: [PATCH 4/4] fix: add seconds definition --- client/cache/random_expired_cache.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/cache/random_expired_cache.go b/client/cache/random_expired_cache.go index e69d2dd8..26200112 100644 --- a/client/cache/random_expired_cache.go +++ b/client/cache/random_expired_cache.go @@ -61,7 +61,7 @@ func defaultExpiredFunc() func() time.Duration { const size = 5 var randTimes [size]time.Duration for i := range randTimes { - randTimes[i] = time.Duration(i + 3) + randTimes[i] = time.Duration(i+3) * time.Second } // shuffle values for i := range randTimes {