From 984f1132442cdee6eb94a0d4936676a8ee726e9b Mon Sep 17 00:00:00 2001 From: Haytham AbuelFutuh Date: Thu, 11 Jul 2019 19:14:37 -0700 Subject: [PATCH 1/5] WIP --- utils/auto_refresh_cache_test.go | 51 ++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/utils/auto_refresh_cache_test.go b/utils/auto_refresh_cache_test.go index c30dcde7..e5044955 100644 --- a/utils/auto_refresh_cache_test.go +++ b/utils/auto_refresh_cache_test.go @@ -3,6 +3,8 @@ package utils import ( "context" "fmt" + "strconv" + "sync" "testing" "time" @@ -34,6 +36,55 @@ func syncFakeItemAlwaysDelete(_ context.Context, obj CacheItem) (CacheItem, Cach return obj, Delete, nil } +func BenchmarkCache(b *testing.B) { + testResyncPeriod := time.Millisecond + rateLimiter := NewRateLimiter("mockLimiter", 100, 1) + // the size of the cache is at least as large as the number of items we're storing + itemCount := b.N + cache, err := NewAutoRefreshCache(syncFakeItem, rateLimiter, testResyncPeriod, itemCount*2, nil) + assert.NoError(b, err) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + cache.Start(ctx) + + startIdx := 1 + + wg := sync.WaitGroup{} + for n := 0; n < b.N; n++ { + wg.Add(itemCount) + // Create items in the cache + for i := 1; i <= itemCount; i++ { + go func(itemId int) { + defer wg.Done() + _, err := cache.GetOrCreate(fakeCacheItem{ + id: fmt.Sprintf("%d", itemId), + val: itemId, + }) + + assert.NoError(b, err) + }(i + startIdx) + } + + wg.Wait() + + // Wait half a second for all resync periods to complete + wg.Add(itemCount) + for i := 1; i <= itemCount; i++ { + go func(itemId int) { + defer wg.Done() + item := cache.Get(fmt.Sprintf("%d", itemId)) + assert.NotNil(b, item, "item #%v", itemId) + if item != nil { + assert.Equal(b, strconv.Itoa(itemId), item.(fakeCacheItem).ID()) + } + }(i + startIdx) + } + wg.Wait() + startIdx += itemCount + } +} + func TestCacheTwo(t *testing.T) { testResyncPeriod := time.Millisecond rateLimiter := NewRateLimiter("mockLimiter", 100, 1) From 3832064359033bb00e97c2b5678e4a238a17fdbc Mon Sep 17 00:00:00 2001 From: Haytham AbuelFutuh Date: Thu, 11 Jul 2019 19:27:43 -0700 Subject: [PATCH 2/5] disable sync loop in test --- utils/auto_refresh_cache.go | 1 + utils/auto_refresh_cache_test.go | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/utils/auto_refresh_cache.go b/utils/auto_refresh_cache.go index 34534839..f1ed79ad 100644 --- a/utils/auto_refresh_cache.go +++ b/utils/auto_refresh_cache.go @@ -129,6 +129,7 @@ func (w *autoRefreshCache) GetOrCreate(item CacheItem) (CacheItem, error) { // * Sync loop updates item 2, repeat func (w *autoRefreshCache) sync(ctx context.Context) { keys := w.lruMap.Keys() + //logger.Infof(ctx, "Keys count: %v", len(keys)) for _, k := range keys { // If not ok, it means evicted between the item was evicted between getting the keys and this update loop // which is fine, we can just ignore. diff --git a/utils/auto_refresh_cache_test.go b/utils/auto_refresh_cache_test.go index e5044955..50cb09ed 100644 --- a/utils/auto_refresh_cache_test.go +++ b/utils/auto_refresh_cache_test.go @@ -44,9 +44,9 @@ func BenchmarkCache(b *testing.B) { cache, err := NewAutoRefreshCache(syncFakeItem, rateLimiter, testResyncPeriod, itemCount*2, nil) assert.NoError(b, err) - ctx, cancel := context.WithCancel(context.Background()) + _, cancel := context.WithCancel(context.Background()) defer cancel() - cache.Start(ctx) + //cache.Start(ctx) startIdx := 1 @@ -75,6 +75,14 @@ func BenchmarkCache(b *testing.B) { defer wg.Done() item := cache.Get(fmt.Sprintf("%d", itemId)) assert.NotNil(b, item, "item #%v", itemId) + if item == nil { + _, err = cache.GetOrCreate(fakeCacheItem{ + id: fmt.Sprintf("%d", itemId), + val: itemId, + }) + + assert.NoError(b, err) + } if item != nil { assert.Equal(b, strconv.Itoa(itemId), item.(fakeCacheItem).ID()) } From b4ed059455ee20a9770dd7d11c8c724c7d22df3a Mon Sep 17 00:00:00 2001 From: Haytham AbuelFutuh Date: Thu, 11 Jul 2019 19:30:18 -0700 Subject: [PATCH 3/5] disable sync loop in test --- utils/auto_refresh_cache_test.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/utils/auto_refresh_cache_test.go b/utils/auto_refresh_cache_test.go index 50cb09ed..b4e1f090 100644 --- a/utils/auto_refresh_cache_test.go +++ b/utils/auto_refresh_cache_test.go @@ -75,14 +75,6 @@ func BenchmarkCache(b *testing.B) { defer wg.Done() item := cache.Get(fmt.Sprintf("%d", itemId)) assert.NotNil(b, item, "item #%v", itemId) - if item == nil { - _, err = cache.GetOrCreate(fakeCacheItem{ - id: fmt.Sprintf("%d", itemId), - val: itemId, - }) - - assert.NoError(b, err) - } if item != nil { assert.Equal(b, strconv.Itoa(itemId), item.(fakeCacheItem).ID()) } From 67ca25491a13d6562e5443f92d47f2d45d33443d Mon Sep 17 00:00:00 2001 From: Haytham AbuelFutuh Date: Fri, 12 Jul 2019 09:44:45 -0700 Subject: [PATCH 4/5] wip --- utils/auto_refresh_cache_test.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/utils/auto_refresh_cache_test.go b/utils/auto_refresh_cache_test.go index b4e1f090..53b51670 100644 --- a/utils/auto_refresh_cache_test.go +++ b/utils/auto_refresh_cache_test.go @@ -36,17 +36,21 @@ func syncFakeItemAlwaysDelete(_ context.Context, obj CacheItem) (CacheItem, Cach return obj, Delete, nil } +func noopSync(_ context.Context, obj CacheItem) (CacheItem, CacheSyncAction, error) { + return obj, Unchanged, nil +} + func BenchmarkCache(b *testing.B) { testResyncPeriod := time.Millisecond rateLimiter := NewRateLimiter("mockLimiter", 100, 1) // the size of the cache is at least as large as the number of items we're storing itemCount := b.N - cache, err := NewAutoRefreshCache(syncFakeItem, rateLimiter, testResyncPeriod, itemCount*2, nil) + cache, err := NewAutoRefreshCache(noopSync, rateLimiter, testResyncPeriod, itemCount*2, nil) assert.NoError(b, err) - _, cancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancel(context.Background()) defer cancel() - //cache.Start(ctx) + cache.Start(ctx) startIdx := 1 @@ -80,6 +84,7 @@ func BenchmarkCache(b *testing.B) { } }(i + startIdx) } + wg.Wait() startIdx += itemCount } From 0bf16f704d699b9b257c37760e756ea88753fc5e Mon Sep 17 00:00:00 2001 From: Haytham AbuelFutuh Date: Fri, 12 Jul 2019 13:41:04 -0700 Subject: [PATCH 5/5] WIP --- utils/auto_refresh_cache_test.go | 39 ++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/utils/auto_refresh_cache_test.go b/utils/auto_refresh_cache_test.go index 53b51670..598774fd 100644 --- a/utils/auto_refresh_cache_test.go +++ b/utils/auto_refresh_cache_test.go @@ -3,6 +3,8 @@ package utils import ( "context" "fmt" + "math" + rand2 "math/rand" "strconv" "sync" "testing" @@ -40,12 +42,45 @@ func noopSync(_ context.Context, obj CacheItem) (CacheItem, CacheSyncAction, err return obj, Unchanged, nil } +func sometimesUpdateOnSync(percentage float32) CacheSyncItem { + r := rand2.New(rand2.NewSource(time.Now().Unix())) + p := int(percentage * 100) + return func(_ context.Context, obj CacheItem) (CacheItem, CacheSyncAction, error) { + if r.Int()%100 < p { + return obj, Update, nil + } + + return obj, Unchanged, nil + } +} + +func TestSometimesUpdateOnSync(t *testing.T) { + for expected := 1.0; expected <= 10; expected++ { + perc := float32(expected / 100.0) + f := sometimesUpdateOnSync(perc) + updateCount := 0 + for i := 0; i < 10000; i++ { + for j := 0; j < 100; j++ { + _, action, err := f(nil, nil) + assert.NoError(t, err) + if action == Update { + updateCount++ + } + } + } + + actual := float64(updateCount / 10000.0) + assert.True(t, expected <= math.Ceil(actual)+1 && expected >= math.Floor(actual)-1, + "Expected: %v, Actual: %v", expected, actual) + } +} + func BenchmarkCache(b *testing.B) { - testResyncPeriod := time.Millisecond + testResyncPeriod := time.Second rateLimiter := NewRateLimiter("mockLimiter", 100, 1) // the size of the cache is at least as large as the number of items we're storing itemCount := b.N - cache, err := NewAutoRefreshCache(noopSync, rateLimiter, testResyncPeriod, itemCount*2, nil) + cache, err := NewAutoRefreshCache(sometimesUpdateOnSync(1), rateLimiter, testResyncPeriod, itemCount*2, nil) assert.NoError(b, err) ctx, cancel := context.WithCancel(context.Background())