Skip to content

Commit 3a4eafb

Browse files
committed
Add ability to LRUCache to evict many at once
1 parent bfcb9a1 commit 3a4eafb

File tree

2 files changed

+39
-8
lines changed

2 files changed

+39
-8
lines changed

src/reactor/cache.js

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,15 +93,19 @@ export class BasicCache {
9393
}
9494
}
9595

96+
const DEFAULT_LRU_LIMIT = 1000
97+
const DEFAULT_LRU_EVICT_COUNT = 1
98+
9699
/**
97100
* Implements caching strategy that evicts least-recently-used items in cache
98101
* when an item is being added to a cache that has reached a configured size
99102
* limit.
100103
*/
101104
export class LRUCache {
102105

103-
constructor(limit = 1000, cache = new BasicCache(), lru = OrderedSet()) {
106+
constructor(limit = DEFAULT_LRU_LIMIT, evictCount = DEFAULT_LRU_EVICT_COUNT, cache = new BasicCache(), lru = OrderedSet()) {
104107
this.limit = limit;
108+
this.evictCount = evictCount
105109
this.cache = cache;
106110
this.lru = lru;
107111
}
@@ -145,7 +149,7 @@ export class LRUCache {
145149
}
146150

147151
// remove it first to reorder in lru OrderedSet
148-
return new LRUCache(this.limit, this.cache, this.lru.remove(item).add(item))
152+
return new LRUCache(this.limit, this.evictCount, this.cache, this.lru.remove(item).add(item))
149153
}
150154

151155
/**
@@ -157,17 +161,30 @@ export class LRUCache {
157161
*/
158162
miss(item, entry) {
159163
if (this.lru.size >= this.limit) {
160-
// TODO add options to clear multiple items at once
161-
const evictItem = this.has(item) ? item : this.lru.first()
164+
if (this.has(item)) {
165+
return new LRUCache(
166+
this.limit,
167+
this.evictCount,
168+
this.cache.miss(item, entry),
169+
this.lru.remove(item).add(item)
170+
)
171+
}
172+
173+
const cache = (this.lru
174+
.take(this.evictCount)
175+
.reduce((c, evictItem) => c.evict(evictItem), this.cache)
176+
.miss(item, entry));
162177

163178
return new LRUCache(
164179
this.limit,
165-
this.cache.evict(evictItem).miss(item, entry),
166-
this.lru.remove(evictItem).add(item)
180+
this.evictCount,
181+
cache,
182+
this.lru.skip(this.evictCount).add(item)
167183
)
168184
} else {
169185
return new LRUCache(
170186
this.limit,
187+
this.evictCount,
171188
this.cache.miss(item, entry),
172189
this.lru.add(item)
173190
)
@@ -186,6 +203,7 @@ export class LRUCache {
186203

187204
return new LRUCache(
188205
this.limit,
206+
this.evictCount,
189207
this.cache.evict(item),
190208
this.lru.remove(item)
191209
)

tests/cache-tests.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,14 @@ describe('Cache', () => {
5252

5353
cache = cache.miss('e', 5)
5454

55-
expect(cache.asMap()).toEqual(Map({b: b, d: 4, e: 5}), 'should have have changed')
55+
expect(cache.asMap()).toEqual(Map({b: b, d: 4, e: 5}), 'should have changed')
5656

5757
cache = cache.hit('b')
5858
.hit('e')
5959
.hit('d')
6060
.miss('a', 1)
6161

62-
expect(cache.asMap()).toEqual(Map({a: 1, d: 4, e: 5}), 'should have have changed')
62+
expect(cache.asMap()).toEqual(Map({a: 1, d: 4, e: 5}), 'should have changed')
6363
})
6464

6565
it('should maintain LRU after manual evict', () => {
@@ -122,5 +122,18 @@ describe('Cache', () => {
122122

123123
expect(cache.asMap()).toEqual(Map({x: 4, e: 5}))
124124
})
125+
126+
it('should be able to evict multiple LRU items at once', () => {
127+
cache = new LRUCache(4, 2)
128+
.miss('a', 1)
129+
.miss('b', 2)
130+
.miss('c', 3)
131+
.miss('d', 4)
132+
.miss('e', 5)
133+
134+
expect(cache.asMap()).toEqual(Map({c: 3, d: 4, e: 5}))
135+
expect(cache.miss('f', 6).asMap()).toEqual(Map({c: 3, d: 4, e: 5, f: 6}))
136+
expect(cache.miss('f', 6).miss('g', 7).asMap()).toEqual(Map({e: 5, f: 6, g: 7}))
137+
})
125138
})
126139
})

0 commit comments

Comments
 (0)