pkg/cache: fix race in Add() and Evict() (#3013)
* pkg/cache: fix race in Add() and Evict() This fixes a race in Add() when the shard is at max capacity and the key being added is already stored. Previously, the shard would evict a random value - when all it needed to do was replace an existing value. There was a race in how Evict() picked which key to remove, which would cause concurrent calls to Evict() to remove the same key. Additionally, this commit removes a lot of the lock contention and a race around Add() and Evict() by changing them to immediately hold the write lock. Previously, they would check conditions with the read lock held and not re-check those conditions once the write lock was acquired (this is a race). * pkg/cache: code review comments * pkg/cache: simplify Add() logic
This commit is contained in:
parent
c928dbd754
commit
031dfede90
3 changed files with 116 additions and 23 deletions
31
plugin/pkg/cache/cache.go
vendored
31
plugin/pkg/cache/cache.go
vendored
|
@ -76,12 +76,15 @@ func newShard(size int) *shard { return &shard{items: make(map[uint64]interface{
|
|||
|
||||
// Add adds element indexed by key into the cache. Any existing element is overwritten
|
||||
func (s *shard) Add(key uint64, el interface{}) {
|
||||
l := s.Len()
|
||||
if l+1 > s.size {
|
||||
s.Evict()
|
||||
}
|
||||
|
||||
s.Lock()
|
||||
if len(s.items) >= s.size {
|
||||
if _, ok := s.items[key]; !ok {
|
||||
for k := range s.items {
|
||||
delete(s.items, k)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
s.items[key] = el
|
||||
s.Unlock()
|
||||
}
|
||||
|
@ -95,24 +98,12 @@ func (s *shard) Remove(key uint64) {
|
|||
|
||||
// Evict removes a random element from the cache.
|
||||
func (s *shard) Evict() {
|
||||
hasKey := false
|
||||
var key uint64
|
||||
|
||||
s.RLock()
|
||||
s.Lock()
|
||||
for k := range s.items {
|
||||
key = k
|
||||
hasKey = true
|
||||
delete(s.items, k)
|
||||
break
|
||||
}
|
||||
s.RUnlock()
|
||||
|
||||
if !hasKey {
|
||||
// empty cache
|
||||
return
|
||||
}
|
||||
|
||||
// If this item is gone between the RUnlock and Lock race we don't care.
|
||||
s.Remove(key)
|
||||
s.Unlock()
|
||||
}
|
||||
|
||||
// Get looks up the element indexed under key.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue