@@ -46,9 +46,13 @@ type Item[K comparable, V any] struct {
46
46
InitialReferenceCount int
47
47
}
48
48
49
+ func (item * Item [K , V ]) hasExpiration () bool {
50
+ return ! item .Expiration .IsZero ()
51
+ }
52
+
49
53
// Expired returns true if the item has expired.
50
54
func (item * Item [K , V ]) Expired () bool {
51
- if item .Expiration . IsZero () {
55
+ if ! item .hasExpiration () {
52
56
return false
53
57
}
54
58
return nowFunc ().After (item .Expiration )
@@ -107,8 +111,9 @@ func newItem[K comparable, V any](key K, val V, opts ...ItemOption) *Item[K, V]
107
111
type Cache [K comparable , V any ] struct {
108
112
cache Interface [K , * Item [K , V ]]
109
113
// 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 ]
112
117
}
113
118
114
119
// Option is an option for cache.
@@ -190,15 +195,16 @@ func NewContext[K comparable, V any](ctx context.Context, opts ...Option[K, V])
190
195
optFunc (o )
191
196
}
192
197
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 ](),
195
201
}
196
202
cache .janitor .run (cache .DeleteExpired )
197
203
return cache
198
204
}
199
205
200
206
// 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 ) {
202
208
c .mu .Lock ()
203
209
defer c .mu .Unlock ()
204
210
item , ok := c .cache .Get (key )
@@ -210,7 +216,7 @@ func (c *Cache[K, V]) Get(key K) (value V, ok bool) {
210
216
// Returns nil if the item has been expired.
211
217
// Do not delete here and leave it to an external process such as Janitor.
212
218
if item .Expired () {
213
- return value , false
219
+ return zero , false
214
220
}
215
221
216
222
return item .Value , true
@@ -219,17 +225,30 @@ func (c *Cache[K, V]) Get(key K) (value V, ok bool) {
219
225
// DeleteExpired all expired items from the cache.
220
226
func (c * Cache [K , V ]) DeleteExpired () {
221
227
c .mu .Lock ()
222
- keys := c .cache . Keys ()
228
+ l := c .expManager . len ()
223
229
c .mu .Unlock ()
224
230
225
- for _ , key := range keys {
226
- c . mu . Lock ()
231
+ evict := func () bool {
232
+ key := c . expManager . pop ()
227
233
// if is expired, delete it and return nil instead
228
234
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 )
231
241
}
242
+ return true
243
+ }
244
+
245
+ for i := 0 ; i < l ; i ++ {
246
+ c .mu .Lock ()
247
+ shouldBreak := evict ()
232
248
c .mu .Unlock ()
249
+ if shouldBreak {
250
+ break
251
+ }
233
252
}
234
253
}
235
254
@@ -238,6 +257,9 @@ func (c *Cache[K, V]) Set(key K, val V, opts ...ItemOption) {
238
257
c .mu .Lock ()
239
258
defer c .mu .Unlock ()
240
259
item := newItem (key , val , opts ... )
260
+ if item .hasExpiration () {
261
+ c .expManager .update (key , item .Expiration )
262
+ }
241
263
c .cache .Set (key , item )
242
264
}
243
265
@@ -253,6 +275,7 @@ func (c *Cache[K, V]) Delete(key K) {
253
275
c .mu .Lock ()
254
276
defer c .mu .Unlock ()
255
277
c .cache .Delete (key )
278
+ c .expManager .remove (key )
256
279
}
257
280
258
281
// Len returns the number of items in the cache.
0 commit comments