feat(cache/unstable): add Cache - #7236
Conversation
Introduces a single `Cache` class that subsumes both `LruCache` and `TtlCache` into a configuration-driven API (maxSize, ttl, sliding expiration, stale-while-revalidate refresh, and onRemove). The new implementation delegates expiration tracking to `IndexedHeap` from `@std/data-structures/unstable-indexed-heap` for O(log n) evictions. - Add cache/cache.ts and cache/cache_test.ts - Remove cache/lru_cache.ts, cache/ttl_cache.ts and their tests - Update cache/memoize.ts doc to reference Cache - Update cache/mod.ts and cache/deno.json exports Made-with: Cursor
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #7236 +/- ##
==========================================
+ Coverage 95.03% 95.07% +0.04%
==========================================
Files 618 619 +1
Lines 51596 52095 +499
Branches 9340 9465 +125
==========================================
+ Hits 49035 49531 +496
- Misses 2021 2022 +1
- Partials 540 542 +2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
The engineering here is high quality and the motivation is sound — both My main request is about how this is packaged rather than what it does. As it stands, one PR removes Could you split the removals into their own commit ahead of the addition? Landing the deletion of the old classes separately, then adding Four things I'd want fixed regardless of how it's split:
One last naming thought: Note this also depends on #7245 landing, since the timer imports |
CacheCache
|
Thanks for the thorough review. All four fixes are in, and the PR is restructured the way you asked:
On Merge order: #7265, then #7245 (the import switches to the stable |
Adds
Cache<K, V>: one composition-based class covering LRU eviction, TTL expiration, stale-while-revalidate, and load-through (getOrLoad).The old
LruCacheandTtlCacheextendMap, so inherited methods bypass the eviction and expiry logic, and two separate subclasses mean LRU and TTL can't be combined.Cacheowns aMapfor storage and delegates deadline ordering toIndexedHeap, replacing per-entrysetTimeouts with a single timer. Mode is determined by options, not class choice, and a discriminated union onCacheOptionsmakes illegal combinations compile-time errors.New capabilities:
getOrLoad(key, loader)with automatic in-flight deduplicationSymbol.disposeCacheLikereplacesMemoizationCacheas the structural cache type.MemoizationCachestays as a deprecated alias, so nothing is removed here.Bonus: in my benchmarks, write-heavy workloads (set, eviction) are 4-22x faster than the old classes, and hot-key reads are 55x faster thanks to the linked list.
Changes since the review:
LruCache/TtlCachemoved to BREAKING(cache/unstable): removeLruCacheandTtlCache#7265, as requested.sizecounts only live entries and always agrees with the iterators.onRemoveerrors are contained where a throw would be uncatchable (timer sweep, refresh microtask). Synchronous paths still throw.Depends on #7245: the heap import switches to
@std/data-structures/indexed-heaponce that lands. Merge order is #7265, then #7245, then this.