From c882629607b10487777240d94b9b754c96c9b13f Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 29 Mar 2023 21:03:11 -0600 Subject: containers: Fix comments --- lib/containers/lrucache.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'lib/containers/lrucache.go') diff --git a/lib/containers/lrucache.go b/lib/containers/lrucache.go index d2aff41..2ea1989 100644 --- a/lib/containers/lrucache.go +++ b/lib/containers/lrucache.go @@ -60,12 +60,14 @@ type lruCache[K comparable, V any] struct { // Blocking primitives ///////////////////////////////////////////////////////// -// Because of pinning, there might not actually be an available entry -// for us to use/evict. If we need an entry to use or evict, we'll -// call waitForAvail to block until there is en entry that is either -// unused or evictable. We'll give waiters FIFO priority. +// waitForAvail is called before storing something into the cache. +// This is nescessary because if the cache is full and all entries are +// pinned, then we won't have to store the entry until something gets +// unpinned ("Release()d"). func (c *lruCache[K, V]) waitForAvail() { if !(c.unused.IsEmpty() && c.evictable.IsEmpty()) { + // There is already an available `lruEntry` that we + // can either use or evict. return } ch := make(chan struct{}) -- cgit v1.2.3-2-g168b From ab6f5d5d783f7fb211aa759a0e01ec716b58ccef Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 29 Mar 2023 21:03:37 -0600 Subject: containers: Fix some issues with ARCache --- lib/containers/lrucache.go | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'lib/containers/lrucache.go') diff --git a/lib/containers/lrucache.go b/lib/containers/lrucache.go index 2ea1989..5c51435 100644 --- a/lib/containers/lrucache.go +++ b/lib/containers/lrucache.go @@ -73,19 +73,24 @@ func (c *lruCache[K, V]) waitForAvail() { ch := make(chan struct{}) c.waiters.Store(&LinkedListEntry[chan struct{}]{Value: ch}) c.mu.Unlock() - <-ch - c.mu.Lock() + <-ch // receive the lock from .Release() + if c.unused.IsEmpty() && c.evictable.IsEmpty() { + panic(fmt.Errorf("should not happen: waitForAvail is returning, but nothing is available")) + } } -// notifyAvail is called when an entry becomes unused or evictable, -// and wakes up the highest-priority .waitForAvail() waiter (if there -// is one). -func (c *lruCache[K, V]) notifyAvail() { +// unlockAndNotifyAvail is called when an entry becomes unused or +// evictable, and wakes up the highest-priority .waitForAvail() waiter +// (if there is one). +func (c *lruCache[K, V]) unlockAndNotifyAvail() { waiter := c.waiters.Oldest if waiter == nil { + c.mu.Unlock() return } c.waiters.Delete(waiter) + // We don't actually unlock, we're "transferring" the lock to + // the waiter. close(waiter.Value) } @@ -171,8 +176,8 @@ func (c *lruCache[K, V]) Delete(k K) { c.evictable.Delete(entry) c.unused.Store(entry) - // No need to call c.notifyAvail(); if we were able to delete - // it, it was already available. + // No need to call c.unlockAndNotifyAvail(); if we were able + // to delete it, it was already available. c.mu.Unlock() } @@ -180,7 +185,6 @@ func (c *lruCache[K, V]) Delete(k K) { // Release implements the 'Cache' interface. func (c *lruCache[K, V]) Release(k K) { c.mu.Lock() - defer c.mu.Unlock() entry := c.byName[k] if entry == nil || entry.Value.refs <= 0 { @@ -196,7 +200,9 @@ func (c *lruCache[K, V]) Release(k K) { } else { c.evictable.Store(entry) } - c.notifyAvail() + c.unlockAndNotifyAvail() + } else { + c.mu.Unlock() } } -- cgit v1.2.3-2-g168b