Skip to content

Commit d549a84

Browse files
dwindsorkkourt
authored andcommitted
fix(process/cache): balance parent refcount ops during LRU eviction
Update process.Cache to properly perform refcount operations in the eviction path. When a process tracked by process.Cache gets LRU evicted due to pressure before its exit event arrives, we currently only update metrics and move on without doing any refcount operations. When the child's exit event later arrives, the exit handler cannot find the child in the cache, so GetParentProcessInternal returns nil and the parent-- is skipped. This leads to an imbalance as process.cacheGarbageCollector will only clean those entries with balanced refcounts (refcnt=0). The entries remain in the cache longer than they should, flooding the cache with invalid entries and increasing eviction pressure. To fix this, we decrement the parent refcount in the eviction callback, but only for entries still marked inUse. An unconditional decrement in the callback would double-count parent-- for these normally-exiting processes, driving the still-live parent's refcount to zero prematurely and causing it to be garbage-collected while still running. Signed-off-by: David Windsor <dwindsor@gmail.com>
1 parent 9564909 commit d549a84

1 file changed

Lines changed: 27 additions & 5 deletions

File tree

pkg/process/cache.go

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,19 +145,41 @@ func NewCache(
145145
processCacheSize int,
146146
GCInterval time.Duration,
147147
) (*Cache, error) {
148+
// Stash a reference to the Cache to refer to later in the eviction closure.
149+
pm := &Cache{
150+
size: processCacheSize,
151+
}
152+
148153
lruCache, err := lru.NewWithEvict(
149154
processCacheSize,
150-
func(_ string, _ *ProcessInternal) {
155+
func(_ string, evicted *ProcessInternal) {
151156
processCacheEvictions.Inc()
157+
158+
// Perform parent-- for LRU-evicted entries that will never
159+
// reach the exit handler.
160+
161+
// Skip non-inUse entries whose exit path already performed parent--
162+
if evicted.color != inUse {
163+
return
164+
}
165+
166+
// Is the parent still in the cache?
167+
if evicted.process == nil {
168+
return
169+
}
170+
parent, ok := pm.cache.Peek(evicted.process.ParentExecId)
171+
if !ok {
172+
return
173+
}
174+
175+
pm.refDec(parent, "parent--")
152176
},
153177
)
154178
if err != nil {
155179
return nil, err
156180
}
157-
pm := &Cache{
158-
cache: lruCache,
159-
size: processCacheSize,
160-
}
181+
182+
pm.cache = lruCache
161183
pm.cacheGarbageCollector(GCInterval)
162184
return pm, nil
163185
}

0 commit comments

Comments
 (0)