@@ -46,9 +46,13 @@ type Item[K comparable, V any] struct {
4646 InitialReferenceCount int
4747}
4848
49+ func (item * Item [K , V ]) hasExpiration () bool {
50+ return ! item .Expiration .IsZero ()
51+ }
52+
4953// Expired returns true if the item has expired.
5054func (item * Item [K , V ]) Expired () bool {
51- if item .Expiration . IsZero () {
55+ if ! item .hasExpiration () {
5256 return false
5357 }
5458 return nowFunc ().After (item .Expiration )
@@ -107,8 +111,9 @@ func newItem[K comparable, V any](key K, val V, opts ...ItemOption) *Item[K, V]
107111type Cache [K comparable , V any ] struct {
108112 cache Interface [K , * Item [K , V ]]
109113 // mu is used to do lock in some method process.
110- mu sync.Mutex
111- janitor * janitor
114+ mu sync.Mutex
115+ janitor * janitor
116+ expManager * expirationManager [K ]
112117}
113118
114119// Option is an option for cache.
@@ -190,15 +195,16 @@ func NewContext[K comparable, V any](ctx context.Context, opts ...Option[K, V])
190195 optFunc (o )
191196 }
192197 cache := & Cache [K , V ]{
193- cache : o .cache ,
194- janitor : newJanitor (ctx , o .janitorInterval ),
198+ cache : o .cache ,
199+ janitor : newJanitor (ctx , o .janitorInterval ),
200+ expManager : newExpirationManager [K ](),
195201 }
196202 cache .janitor .run (cache .DeleteExpired )
197203 return cache
198204}
199205
200206// Get looks up a key's value from the cache.
201- func (c * Cache [K , V ]) Get (key K ) (value V , ok bool ) {
207+ func (c * Cache [K , V ]) Get (key K ) (zero V , ok bool ) {
202208 c .mu .Lock ()
203209 defer c .mu .Unlock ()
204210 item , ok := c .cache .Get (key )
@@ -210,7 +216,7 @@ func (c *Cache[K, V]) Get(key K) (value V, ok bool) {
210216 // Returns nil if the item has been expired.
211217 // Do not delete here and leave it to an external process such as Janitor.
212218 if item .Expired () {
213- return value , false
219+ return zero , false
214220 }
215221
216222 return item .Value , true
@@ -219,17 +225,30 @@ func (c *Cache[K, V]) Get(key K) (value V, ok bool) {
219225// DeleteExpired all expired items from the cache.
220226func (c * Cache [K , V ]) DeleteExpired () {
221227 c .mu .Lock ()
222- keys := c .cache . Keys ()
228+ l := c .expManager . len ()
223229 c .mu .Unlock ()
224230
225- for _ , key := range keys {
226- c . mu . Lock ()
231+ evict := func () bool {
232+ key := c . expManager . pop ()
227233 // if is expired, delete it and return nil instead
228234 item , ok := c .cache .Get (key )
229- if ok && item .Expired () {
230- c .cache .Delete (key )
235+ if ok {
236+ if item .Expired () {
237+ c .cache .Delete (key )
238+ return false
239+ }
240+ c .expManager .update (key , item .Expiration )
231241 }
242+ return true
243+ }
244+
245+ for i := 0 ; i < l ; i ++ {
246+ c .mu .Lock ()
247+ shouldBreak := evict ()
232248 c .mu .Unlock ()
249+ if shouldBreak {
250+ break
251+ }
233252 }
234253}
235254
@@ -238,6 +257,9 @@ func (c *Cache[K, V]) Set(key K, val V, opts ...ItemOption) {
238257 c .mu .Lock ()
239258 defer c .mu .Unlock ()
240259 item := newItem (key , val , opts ... )
260+ if item .hasExpiration () {
261+ c .expManager .update (key , item .Expiration )
262+ }
241263 c .cache .Set (key , item )
242264}
243265
@@ -253,6 +275,7 @@ func (c *Cache[K, V]) Delete(key K) {
253275 c .mu .Lock ()
254276 defer c .mu .Unlock ()
255277 c .cache .Delete (key )
278+ c .expManager .remove (key )
256279}
257280
258281// Len returns the number of items in the cache.
0 commit comments