mirror of https://github.com/k3s-io/k3s
parent
2c933695fa
commit
a2cc1b1a20
|
@ -35,6 +35,9 @@ 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.
|
||||||
//
|
//
|
||||||
|
@ -42,13 +45,17 @@ import (
|
||||||
// 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 {
|
||||||
// i.e. map[string]*NodeCache
|
// NOTE(harry): Theoretically sync.Map has better performance in machine with 8+ CPUs, while
|
||||||
sync.Map
|
// the reality is lock contention in first level cache is rare.
|
||||||
|
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 new(Cache)
|
return &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
|
||||||
|
@ -76,8 +83,12 @@ 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) {
|
||||||
v, exists := c.LoadOrStore(name, newNodeCache())
|
c.mu.Lock()
|
||||||
nodeCache = v.(*NodeCache)
|
defer c.mu.Unlock()
|
||||||
|
if nodeCache, exists = c.nodeToCache[name]; !exists {
|
||||||
|
nodeCache = newNodeCache()
|
||||||
|
c.nodeToCache[name] = nodeCache
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,13 +97,12 @@ func (c *Cache) InvalidatePredicates(predicateKeys sets.String) {
|
||||||
if len(predicateKeys) == 0 {
|
if len(predicateKeys) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.Range(func(k, v interface{}) bool {
|
c.mu.RLock()
|
||||||
n := v.(*NodeCache)
|
defer c.mu.RUnlock()
|
||||||
|
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.
|
||||||
|
@ -100,8 +110,9 @@ func (c *Cache) InvalidatePredicatesOnNode(nodeName string, predicateKeys sets.S
|
||||||
if len(predicateKeys) == 0 {
|
if len(predicateKeys) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if v, ok := c.Load(nodeName); ok {
|
c.mu.RLock()
|
||||||
n := v.(*NodeCache)
|
defer c.mu.RUnlock()
|
||||||
|
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)
|
||||||
|
@ -109,7 +120,9 @@ 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.Delete(nodeName)
|
c.mu.Lock()
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.GetNodeCache(test.nodeName); exist {
|
if nodeCache, exist := ecache.nodeToCache[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)
|
||||||
|
|
Loading…
Reference in New Issue