77 "github.com/lightninglabs/neutrino/cache"
88)
99
10- // elementMap is an alias for a map from a generic interface to a list.Element.
11- type elementMap [K comparable , V any ] map [K ]V
12-
1310// entry represents a (key,value) pair entry in the Cache. The Cache's list
1411// stores entries which let us get the cache key when an entry is evicted.
1512type entry [K comparable , V cache.Value ] struct {
@@ -33,7 +30,7 @@ type Cache[K comparable, V cache.Value] struct {
3330
3431 // cache is a generic cache which allows us to find an elements position
3532 // in the ll list from a given key.
36- cache elementMap [K , * Element [entry [K , V ]]]
33+ cache syncMap [K , * Element [entry [K , V ]]]
3734
3835 // mtx is used to make sure the Cache is thread-safe.
3936 mtx sync.RWMutex
@@ -45,7 +42,7 @@ func NewCache[K comparable, V cache.Value](capacity uint64) *Cache[K, V] {
4542 return & Cache [K , V ]{
4643 capacity : capacity ,
4744 ll : NewList [entry [K , V ]](),
48- cache : make ( map [ K ] * Element [entry [K , V ]]) ,
45+ cache : syncMap [ K , * Element [entry [K , V ]]]{} ,
4946 }
5047}
5148
@@ -84,7 +81,7 @@ func (c *Cache[K, V]) evict(needed uint64) (bool, error) {
8481
8582 // Remove the element from the cache.
8683 c .ll .Remove (elr )
87- delete ( c .cache , ce .key )
84+ c .cache . Delete ( ce .key )
8885 evicted = true
8986 }
9087 }
@@ -108,17 +105,22 @@ func (c *Cache[K, V]) Put(key K, value V) (bool, error) {
108105 "cache with capacity %v" , vs , c .capacity )
109106 }
110107
108+ // Load the element.
109+ el , ok := c .cache .Load (key )
110+
111+ // Update the internal list inside a lock.
111112 c .mtx .Lock ()
112- defer c .mtx .Unlock ()
113113
114114 // If the element already exists, remove it and decrease cache's size.
115- el , ok := c .cache [key ]
116115 if ok {
117116 es , err := el .Value .value .Size ()
118117 if err != nil {
118+ c .mtx .Unlock ()
119+
119120 return false , fmt .Errorf ("couldn't determine size of " +
120121 "existing cache value %v" , err )
121122 }
123+
122124 c .ll .Remove (el )
123125 c .size -= es
124126 }
@@ -132,26 +134,31 @@ func (c *Cache[K, V]) Put(key K, value V) (bool, error) {
132134
133135 // We have made enough space in the cache, so just insert it.
134136 el = c .ll .PushFront (entry [K , V ]{key , value })
135- c .cache [key ] = el
136137 c .size += vs
137138
139+ // Release the lock.
140+ c .mtx .Unlock ()
141+
142+ // Update the cache.
143+ c .cache .Store (key , el )
144+
138145 return evicted , nil
139146}
140147
141148// Get will return value for a given key, making the element the most recently
142149// accessed item in the process. Will return nil if the key isn't found.
143150func (c * Cache [K , V ]) Get (key K ) (V , error ) {
144- c .mtx .Lock ()
145- defer c .mtx .Unlock ()
146-
147151 var defaultVal V
148152
149- el , ok := c .cache [ key ]
153+ el , ok := c .cache . Load ( key )
150154 if ! ok {
151155 // Element not found in the cache.
152156 return defaultVal , cache .ErrElementNotFound
153157 }
154158
159+ c .mtx .Lock ()
160+ defer c .mtx .Unlock ()
161+
155162 // When the cache needs to evict a element to make space for another
156163 // one, it starts eviction from the back, so by moving this element to
157164 // the front, it's eviction is delayed because it's recently accessed.
@@ -166,3 +173,45 @@ func (c *Cache[K, V]) Len() int {
166173
167174 return c .ll .Len ()
168175}
176+
177+ // Delete removes an item from the cache.
178+ func (c * Cache [K , V ]) Delete (key K ) {
179+ c .LoadAndDelete (key )
180+ }
181+
182+ // LoadAndDelete queries an item and deletes it from the cache using the
183+ // specified key.
184+ func (c * Cache [K , V ]) LoadAndDelete (key K ) (V , bool ) {
185+ var defaultVal V
186+
187+ // Noop if the element doesn't exist.
188+ el , ok := c .cache .LoadAndDelete (key )
189+ if ! ok {
190+ return defaultVal , false
191+ }
192+
193+ c .mtx .Lock ()
194+ defer c .mtx .Unlock ()
195+
196+ // Get its size.
197+ vs , err := el .Value .value .Size ()
198+ if err != nil {
199+ return defaultVal , false
200+ }
201+
202+ // Remove the element from the list and update the cache's size.
203+ c .ll .Remove (el )
204+ c .size -= vs
205+
206+ return el .Value .value , true
207+ }
208+
209+ // Range iterates the cache.
210+ func (c * Cache [K , V ]) Range (visitor func (K , V ) bool ) {
211+ // valueVisitor is a closure to help unwrap the value from the cache.
212+ valueVisitor := func (key K , value * Element [entry [K , V ]]) bool {
213+ return visitor (key , value .Value .value )
214+ }
215+
216+ c .cache .Range (valueVisitor )
217+ }
0 commit comments