Skip to content

Commit 18ea0dc

Browse files
Merge pull request #66 from hyperledger/cache-tagging
Cache utility needs namespace grouping and reset capability
2 parents 58424e9 + 0b0066c commit 18ea0dc

2 files changed

Lines changed: 76 additions & 31 deletions

File tree

pkg/cache/cache.go

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package cache
1818

1919
import (
2020
"context"
21+
"fmt"
2122
"sync"
2223
"time"
2324

@@ -29,8 +30,9 @@ import (
2930
// Each cache instance has unique name and its own cache size and TTL configuration.
3031
type Manager interface {
3132
// Get a cache by name, if a cache already exists with the same name, it will be returned as is without checking maxSize, ttl and enabled matches
32-
GetCache(ctx context.Context, cacheName string, maxSize int64, ttl time.Duration, enabled bool) (CInterface, error)
33-
ListCacheNames() []string
33+
GetCache(ctx context.Context, namespace, name string, maxSize int64, ttl time.Duration, enabled bool) (CInterface, error)
34+
ListCacheNames(namespace string) []string
35+
ResetCaches(namespace string)
3436
IsEnabled() bool
3537
}
3638

@@ -53,11 +55,12 @@ type CInterface interface {
5355
}
5456

5557
type CCache struct {
56-
enabled bool
57-
ctx context.Context
58-
name string
59-
cache *ccache.Cache
60-
cacheTTL time.Duration
58+
enabled bool
59+
ctx context.Context
60+
namespace string
61+
name string
62+
cache *ccache.Cache
63+
cacheTTL time.Duration
6164
}
6265

6366
func (c *CCache) Set(key string, val interface{}) {
@@ -138,47 +141,64 @@ type cacheManager struct {
138141
enabled bool // global default, when set to true, each cache instance can have an override
139142
ctx context.Context
140143
m sync.Mutex
141-
configuredCaches map[string]CInterface // Cache manager maintain a list of named configured CCache, the names are unique
144+
configuredCaches map[string]*CCache // Cache manager maintain a list of named configured CCache, the names are unique
142145
}
143146

144-
func (cm *cacheManager) GetCache(ctx context.Context, cacheName string, maxSize int64, ttl time.Duration, enabled bool) (CInterface, error) {
147+
func (cm *cacheManager) GetCache(ctx context.Context, namespace, name string, maxSize int64, ttl time.Duration, enabled bool) (CInterface, error) {
145148
cm.m.Lock()
146149
defer cm.m.Unlock()
147-
cache, exists := cm.configuredCaches[cacheName]
150+
fqName := fmt.Sprintf("%s:%s", namespace, name)
151+
cache, exists := cm.configuredCaches[fqName]
148152
enabledValue := enabled
149153
if !cm.IsEnabled() {
150154
// when cache manager is disabled, the enabled toggle doesn't make any difference
151155
enabledValue = false
152156
}
153157
if !exists {
154158
cache = &CCache{
155-
ctx: ctx,
156-
name: cacheName,
157-
cache: ccache.New(ccache.Configure().MaxSize(maxSize)),
158-
cacheTTL: ttl,
159-
enabled: enabledValue,
159+
ctx: ctx,
160+
namespace: namespace,
161+
name: name,
162+
cache: ccache.New(ccache.Configure().MaxSize(maxSize)),
163+
cacheTTL: ttl,
164+
enabled: enabledValue,
160165
}
161-
cm.configuredCaches[cacheName] = cache
166+
cm.configuredCaches[fqName] = cache
162167
}
163168
return cache, nil
164169
}
165170

166-
func (cm *cacheManager) ListCacheNames() []string {
171+
func (cm *cacheManager) ListCacheNames(namespace string) []string {
167172
keys := make([]string, 0, len(cm.configuredCaches))
168-
for k := range cm.configuredCaches {
169-
keys = append(keys, k)
173+
for k, c := range cm.configuredCaches {
174+
if c.namespace == namespace {
175+
keys = append(keys, k)
176+
}
170177
}
171178
return keys
172179
}
173180

181+
func (cm *cacheManager) ResetCaches(namespace string) {
182+
cm.m.Lock()
183+
defer cm.m.Unlock()
184+
for k, c := range cm.configuredCaches {
185+
if c.namespace == namespace {
186+
// Clear the cache to free the memory immediately
187+
c.cache.Clear()
188+
// Remove it from the map, so the next call will generate a new one
189+
delete(cm.configuredCaches, k)
190+
}
191+
}
192+
}
193+
174194
func (cm *cacheManager) IsEnabled() bool {
175195
return cm.enabled
176196
}
177197

178198
func NewCacheManager(ctx context.Context, enabled bool) Manager {
179199
cm := &cacheManager{
180200
ctx: ctx,
181-
configuredCaches: map[string]CInterface{},
201+
configuredCaches: map[string]*CCache{},
182202
enabled: enabled,
183203
}
184204
return cm

pkg/cache/cache_test.go

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,22 @@ import (
2727
func TestGetCacheReturnsSameCacheForSameConfig(t *testing.T) {
2828
ctx := context.Background()
2929
cacheManager := NewCacheManager(ctx, true)
30-
cache0, _ := cacheManager.GetCache(ctx, "cacheA", 85, time.Second, true)
31-
cache1, _ := cacheManager.GetCache(ctx, "cacheA", 85, time.Second, true)
30+
cache0, _ := cacheManager.GetCache(ctx, "ns1", "cacheA", 85, time.Second, true)
31+
cache1, _ := cacheManager.GetCache(ctx, "ns1", "cacheA", 85, time.Second, true)
3232

3333
assert.Equal(t, cache0, cache1)
34-
assert.Equal(t, []string{"cacheA"}, cacheManager.ListCacheNames())
34+
assert.Equal(t, []string{"ns1:cacheA"}, cacheManager.ListCacheNames("ns1"))
3535

36-
cache2, _ := cacheManager.GetCache(ctx, "cacheB", 85, time.Second, true)
36+
cache2, _ := cacheManager.GetCache(ctx, "ns1", "cacheB", 85, time.Second, true)
3737
assert.NotEqual(t, cache0, cache2)
38-
assert.Equal(t, 2, len(cacheManager.ListCacheNames()))
38+
assert.Equal(t, 2, len(cacheManager.ListCacheNames("ns1")))
3939
}
4040

4141
func TestTwoSeparateCacheWorksIndependently(t *testing.T) {
4242
ctx := context.Background()
4343
cacheManager := NewCacheManager(ctx, true)
44-
cache0, _ := cacheManager.GetCache(ctx, "cacheA", 85, time.Second, true)
45-
cache1, _ := cacheManager.GetCache(ctx, "cacheB", 85, time.Second, true)
44+
cache0, _ := cacheManager.GetCache(ctx, "ns1", "cacheA", 85, time.Second, true)
45+
cache1, _ := cacheManager.GetCache(ctx, "ns1", "cacheB", 85, time.Second, true)
4646

4747
cache0.SetInt("int0", 100)
4848
assert.Equal(t, 100, cache0.GetInt("int0"))
@@ -66,29 +66,29 @@ func TestCacheEnablement(t *testing.T) {
6666
var zero int64 = 0
6767
// test global enablement set to false
6868
disabledCacheManager := NewCacheManager(ctx, false)
69-
cache0, _ := disabledCacheManager.GetCache(ctx, "cache0", 85, time.Second, false)
69+
cache0, _ := disabledCacheManager.GetCache(ctx, "ns1", "cache0", 85, time.Second, false)
7070
assert.Equal(t, false, cache0.IsEnabled())
7171

7272
cache0.SetInt64("int0", hundred)
7373
assert.Equal(t, nil, cache0.Get("int0"))
7474

7575
// check individual cache cannot be turned on when the cache manager is disabled
76-
cache1, _ := disabledCacheManager.GetCache(ctx, "cache1", 85, time.Second, true)
76+
cache1, _ := disabledCacheManager.GetCache(ctx, "ns1", "cache1", 85, time.Second, true)
7777
assert.Equal(t, false, cache1.IsEnabled())
7878

7979
// test global enablement set to true
8080

8181
enabledCacheManager := NewCacheManager(ctx, true)
8282
// check individual cache can be turned off when the cache manager is enabled
83-
cache0, _ = enabledCacheManager.GetCache(ctx, "cache0", 85, time.Second, false)
83+
cache0, _ = enabledCacheManager.GetCache(ctx, "ns1", "cache0", 85, time.Second, false)
8484
assert.Equal(t, false, cache0.IsEnabled())
8585

8686
cache0.SetInt64("int0", hundred)
8787
assert.Equal(t, zero, cache0.GetInt64("int0"))
8888
deleted := cache0.Delete("int0")
8989
assert.False(t, deleted)
9090

91-
cache1, _ = enabledCacheManager.GetCache(ctx, "cache1", 85, time.Second, true)
91+
cache1, _ = enabledCacheManager.GetCache(ctx, "ns1", "cache1", 85, time.Second, true)
9292
assert.Equal(t, true, cache1.IsEnabled())
9393

9494
cache1.SetInt64("int0", hundred)
@@ -101,3 +101,28 @@ func TestUmmanagedCacheInstance(t *testing.T) {
101101
uc1 := NewUmanagedCache(context.Background(), 100, 5*time.Minute)
102102
assert.NotEqual(t, uc0, uc1)
103103
}
104+
105+
func TestResetCachesForNamespace(t *testing.T) {
106+
ctx := context.Background()
107+
cacheManager := NewCacheManager(ctx, true)
108+
cacheNS1, _ := cacheManager.GetCache(ctx, "ns1", "cache1", 85, time.Second, true)
109+
cacheNS1.Set("key1", "value1")
110+
111+
cacheNS2, _ := cacheManager.GetCache(ctx, "ns2", "cache1", 85, time.Second, true)
112+
cacheNS2.Set("key2", "value2")
113+
114+
cacheNS1_a, _ := cacheManager.GetCache(ctx, "ns1", "cache1", 85, time.Second, true)
115+
assert.Equal(t, cacheNS1, cacheNS1_a)
116+
assert.Equal(t, "value1", cacheNS1_a.Get("key1"))
117+
118+
cacheManager.ResetCaches("ns1")
119+
120+
cacheNS2_a, _ := cacheManager.GetCache(ctx, "ns2", "cache1", 85, time.Second, true)
121+
assert.Equal(t, cacheNS2, cacheNS2_a)
122+
assert.Equal(t, "value2", cacheNS2_a.Get("key2"))
123+
124+
cacheNS1_b, _ := cacheManager.GetCache(ctx, "ns1", "cache1", 85, time.Second, true)
125+
assert.NotEqual(t, cacheNS1, cacheNS1_b)
126+
assert.Nil(t, cacheNS1_b.Get("key1"))
127+
128+
}

0 commit comments

Comments
 (0)