From 8866b55fb9b78162c6876c4c8c72cc9f1396cde1 Mon Sep 17 00:00:00 2001 From: Ferit Date: Thu, 15 Oct 2026 18:16:36 +0300 Subject: [PATCH] fix: preserve cleanup list links across TTL expiry --- src/lru.js | 37 ------------------------------------- tests/unit/lru.test.js | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 37 deletions(-) diff --git a/src/lru.js b/src/lru.js index 33b78d8..e82a76b 100644 --- a/src/lru.js +++ b/src/lru.js @@ -580,10 +580,6 @@ export class LRU { x = next; } - if (removed > 0) { - this.#rebuildList(); - } - return removed; } @@ -706,39 +702,6 @@ export class LRU { return { valid, expired, noTTL: [] }; } - - /** - * Rebuild the doubly-linked list after cleanup by deleting expired items. - * This removes nodes that were deleted during cleanup. - * - * @private - */ - #rebuildList() { - if (this.size === 0) { - this.first = null; - this.last = null; - return; - } - - const keys = this.keys(); - this.first = null; - this.last = null; - - for (let i = 0; i < keys.length; i++) { - const item = this.items[keys[i]]; - if (item !== null && item !== undefined) { - if (this.first === null) { - this.first = item; - item.prev = null; - } else { - item.prev = this.last; - this.last.next = item; - } - item.next = null; - this.last = item; - } - } - } } /** diff --git a/tests/unit/lru.test.js b/tests/unit/lru.test.js index 9113aaa..df0c485 100644 --- a/tests/unit/lru.test.js +++ b/tests/unit/lru.test.js @@ -999,6 +999,22 @@ describe("LRU Cache", function () { cache = new LRU(5, 100); }); + it("should keep the list intact when an item expires during cleanup", function (t) { + const times = [0, 50, 100, 149, 150]; + let index = 0; + t.mock.method(Date, "now", () => times[index++] ?? 150); + cache.set("a", 1); + cache.set("b", 2); + + assert.equal(cache.cleanup(), 1); + assert.equal(cache.size, 1); + assert.equal(cache.first, cache.items.b); + assert.equal(cache.last, cache.items.b); + assert.doesNotThrow(() => cache.evict()); + assert.equal(cache.size, 0); + assert.deepEqual(Object.keys(cache.items), []); + }); + it("should remove expired items", async function () { cache.set("a", 1); cache.set("b", 2);