Use sync.map to scale ecache better

This commit is contained in:
Harry Zhang 2018-07-27 22:13:50 +08:00
parent 007bf90e32
commit 17d0190706
2 changed files with 14 additions and 27 deletions

View File

@ -33,9 +33,6 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
) )
// nodeMap stores a *Cache for each node.
type nodeMap map[string]*NodeCache
// Cache is a thread safe map saves and reuses the output of predicate functions, // Cache is a thread safe map saves and reuses the output of predicate functions,
// it uses node name as key to access those cached results. // it uses node name as key to access those cached results.
// //
@ -43,17 +40,13 @@ type nodeMap map[string]*NodeCache
// class". (Equivalence class is defined in the `Class` type.) Saved results // class". (Equivalence class is defined in the `Class` type.) Saved results
// will be reused until an appropriate invalidation function is called. // will be reused until an appropriate invalidation function is called.
type Cache struct { type Cache struct {
// NOTE(harry): Theoretically sync.Map has better performance in machine with 8+ CPUs, while // i.e. map[string]*NodeCache
// the reality is lock contention in first level cache is rare. sync.Map
mu sync.RWMutex
nodeToCache nodeMap
} }
// NewCache create an empty equiv class cache. // NewCache create an empty equiv class cache.
func NewCache() *Cache { func NewCache() *Cache {
return &Cache{ return new(Cache)
nodeToCache: make(nodeMap),
}
} }
// NodeCache saves and reuses the output of predicate functions. Use RunPredicate to // NodeCache saves and reuses the output of predicate functions. Use RunPredicate to
@ -81,12 +74,8 @@ func newNodeCache() *NodeCache {
// it creates the NodeCache and returns it. // it creates the NodeCache and returns it.
// The boolean flag is true if the value was loaded, false if created. // The boolean flag is true if the value was loaded, false if created.
func (c *Cache) GetNodeCache(name string) (nodeCache *NodeCache, exists bool) { func (c *Cache) GetNodeCache(name string) (nodeCache *NodeCache, exists bool) {
c.mu.Lock() v, exists := c.LoadOrStore(name, newNodeCache())
defer c.mu.Unlock() nodeCache = v.(*NodeCache)
if nodeCache, exists = c.nodeToCache[name]; !exists {
nodeCache = newNodeCache()
c.nodeToCache[name] = nodeCache
}
return return
} }
@ -95,12 +84,13 @@ func (c *Cache) InvalidatePredicates(predicateKeys sets.String) {
if len(predicateKeys) == 0 { if len(predicateKeys) == 0 {
return return
} }
c.mu.RLock() c.Range(func(k, v interface{}) bool {
defer c.mu.RUnlock() n := v.(*NodeCache)
for _, n := range c.nodeToCache {
n.invalidatePreds(predicateKeys) n.invalidatePreds(predicateKeys)
} return true
})
glog.V(5).Infof("Cache invalidation: node=*,predicates=%v", predicateKeys) glog.V(5).Infof("Cache invalidation: node=*,predicates=%v", predicateKeys)
} }
// InvalidatePredicatesOnNode clears cached results for the given predicates on one node. // InvalidatePredicatesOnNode clears cached results for the given predicates on one node.
@ -108,9 +98,8 @@ func (c *Cache) InvalidatePredicatesOnNode(nodeName string, predicateKeys sets.S
if len(predicateKeys) == 0 { if len(predicateKeys) == 0 {
return return
} }
c.mu.RLock() if v, ok := c.Load(nodeName); ok {
defer c.mu.RUnlock() n := v.(*NodeCache)
if n, ok := c.nodeToCache[nodeName]; ok {
n.invalidatePreds(predicateKeys) n.invalidatePreds(predicateKeys)
} }
glog.V(5).Infof("Cache invalidation: node=%s,predicates=%v", nodeName, predicateKeys) glog.V(5).Infof("Cache invalidation: node=%s,predicates=%v", nodeName, predicateKeys)
@ -118,9 +107,7 @@ func (c *Cache) InvalidatePredicatesOnNode(nodeName string, predicateKeys sets.S
// InvalidateAllPredicatesOnNode clears all cached results for one node. // InvalidateAllPredicatesOnNode clears all cached results for one node.
func (c *Cache) InvalidateAllPredicatesOnNode(nodeName string) { func (c *Cache) InvalidateAllPredicatesOnNode(nodeName string) {
c.mu.Lock() c.Delete(nodeName)
defer c.mu.Unlock()
delete(c.nodeToCache, nodeName)
glog.V(5).Infof("Cache invalidation: node=%s,predicates=*", nodeName) glog.V(5).Infof("Cache invalidation: node=%s,predicates=*", nodeName)
} }

View File

@ -731,7 +731,7 @@ func TestInvalidateCachedPredicateItemOfAllNodes(t *testing.T) {
// there should be no cached predicate any more // there should be no cached predicate any more
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
if nodeCache, exist := ecache.nodeToCache[test.nodeName]; exist { if nodeCache, exist := ecache.GetNodeCache(test.nodeName); exist {
if _, exist := nodeCache.cache[testPredicate]; exist { if _, exist := nodeCache.cache[testPredicate]; exist {
t.Errorf("Failed: cached item for predicate key: %v on node: %v should be invalidated", t.Errorf("Failed: cached item for predicate key: %v on node: %v should be invalidated",
testPredicate, test.nodeName) testPredicate, test.nodeName)