Skip to content

Commit 3daf7e9

Browse files
committed
Fix single-item cache bug by adding explicit inList flag
The intrinsic linked list change used next==nil && prev==nil to detect items not in the list. This fails for the first/only item, which has both pointers nil while legitimately being in the list. Add an inList boolean to Item, set by Insert/Remove, and use it in doPromote/doDelete instead of checking pointer state. Fixes size double-counting on promotion and missing cleanup on delete. The item struct already uses two cache-lines, adding the inList field does not have any significant performance impact.
1 parent 6d8fbe4 commit 3daf7e9

File tree

4 files changed

+7
-6
lines changed

4 files changed

+7
-6
lines changed

cache.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ doAllDeletes:
331331
}
332332

333333
func (c *Cache[T]) doDelete(item *Item[T]) {
334-
if item.next == nil && item.prev == nil {
334+
if !item.inList {
335335
item.promotions = -2
336336
} else {
337337
c.size -= item.size
@@ -344,12 +344,11 @@ func (c *Cache[T]) doDelete(item *Item[T]) {
344344
}
345345

346346
func (c *Cache[T]) doPromote(item *Item[T]) bool {
347-
//already deleted
348347
if item.promotions == -2 {
349348
return false
350349
}
351350

352-
if item.next != nil || item.prev != nil { // not a new item
351+
if item.inList {
353352
if item.shouldPromote(c.getsPerPromote) {
354353
c.list.MoveToFront(item)
355354
item.promotions = 0

item.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ type Item[T any] struct {
2929
value T
3030
next *Item[T]
3131
prev *Item[T]
32+
inList bool
3233
}
3334

3435
func newItem[T any](key string, value T, expires int64, track bool) *Item[T] {

layeredcache.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ drain:
293293
}
294294

295295
func (c *LayeredCache[T]) doDelete(item *Item[T]) {
296-
if item.prev == nil && item.next == nil {
296+
if !item.inList {
297297
item.promotions = -2
298298
} else {
299299
c.size -= item.size
@@ -306,12 +306,11 @@ func (c *LayeredCache[T]) doDelete(item *Item[T]) {
306306
}
307307

308308
func (c *LayeredCache[T]) doPromote(item *Item[T]) bool {
309-
// deleted before it ever got promoted
310309
if item.promotions == -2 {
311310
return false
312311
}
313312

314-
if item.next != nil || item.prev != nil { // not a new item
313+
if item.inList {
315314
if item.shouldPromote(c.getsPerPromote) {
316315
c.list.MoveToFront(item)
317316
item.promotions = 0

list.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ func (l *List[T]) Remove(item *Item[T]) {
2626
}
2727
item.next = nil
2828
item.prev = nil
29+
item.inList = false
2930
}
3031

3132
func (l *List[T]) MoveToFront(item *Item[T]) {
@@ -36,6 +37,7 @@ func (l *List[T]) MoveToFront(item *Item[T]) {
3637
func (l *List[T]) Insert(item *Item[T]) {
3738
head := l.Head
3839
l.Head = item
40+
item.inList = true
3941
if head == nil {
4042
l.Tail = item
4143
return

0 commit comments

Comments
 (0)