Skip to content

Commit d851586

Browse files
velotingmgaffney
authored andcommitted
add a Resize method to 2Q
1 parent d46c1d9 commit d851586

File tree

2 files changed

+103
-2
lines changed

2 files changed

+103
-2
lines changed

2q.go

+34-2
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ const (
3030
// head. The ARCCache is similar, but does not require setting any
3131
// parameters.
3232
type TwoQueueCache[K comparable, V any] struct {
33-
size int
34-
recentSize int
33+
size int
34+
recentSize int
35+
recentRatio float64
36+
ghostRatio float64
3537

3638
recent simplelru.LRUCache[K, V]
3739
frequent simplelru.LRUCache[K, V]
@@ -80,6 +82,8 @@ func New2QParams[K comparable, V any](size int, recentRatio, ghostRatio float64)
8082
c := &TwoQueueCache[K, V]{
8183
size: size,
8284
recentSize: recentSize,
85+
recentRatio: recentRatio,
86+
ghostRatio: ghostRatio,
8387
recent: recent,
8488
frequent: frequent,
8589
recentEvict: recentEvict,
@@ -171,6 +175,34 @@ func (c *TwoQueueCache[K, V]) Len() int {
171175
return c.recent.Len() + c.frequent.Len()
172176
}
173177

178+
// Resize changes the cache size.
179+
func (c *TwoQueueCache[K, V]) Resize(size int) (evicted int) {
180+
c.lock.Lock()
181+
defer c.lock.Unlock()
182+
183+
// Recalculate the sub-sizes
184+
recentSize := int(float64(size) * c.recentRatio)
185+
evictSize := int(float64(size) * c.ghostRatio)
186+
c.size = size
187+
c.recentSize = recentSize
188+
189+
// ensureSpace
190+
diff := c.recent.Len() + c.frequent.Len() - size
191+
if diff < 0 {
192+
diff = 0
193+
}
194+
for i := 0; i < diff; i++ {
195+
c.ensureSpace(true)
196+
}
197+
198+
// Reallocate the LRUs
199+
c.recent.Resize(size)
200+
c.frequent.Resize(size)
201+
c.recentEvict.Resize(evictSize)
202+
203+
return diff
204+
}
205+
174206
// Keys returns a slice of the keys in the cache.
175207
// The frequently used keys are first in the returned slice.
176208
func (c *TwoQueueCache[K, V]) Keys() []K {

2q_test.go

+69
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,75 @@ func Test2Q_Add_RecentEvict(t *testing.T) {
218218
}
219219
}
220220

221+
func Test2Q_Resize(t *testing.T) {
222+
l, err := New2Q[int, int](100)
223+
if err != nil {
224+
t.Fatalf("err: %v", err)
225+
}
226+
227+
// Touch all the entries, should be in t1
228+
for i := 0; i < 100; i++ {
229+
l.Add(i, i)
230+
}
231+
232+
evicted := l.Resize(50)
233+
if evicted != 50 {
234+
t.Fatalf("bad: %d", evicted)
235+
}
236+
237+
if n := l.recent.Len(); n != 50 {
238+
t.Fatalf("bad: %d", n)
239+
}
240+
if n := l.frequent.Len(); n != 0 {
241+
t.Fatalf("bad: %d", n)
242+
}
243+
244+
l, err = New2Q[int, int](100)
245+
if err != nil {
246+
t.Fatalf("err: %v", err)
247+
}
248+
for i := 0; i < 100; i++ {
249+
l.Add(i, i)
250+
}
251+
252+
for i := 0; i < 50; i++ {
253+
l.Add(i, i)
254+
}
255+
256+
evicted = l.Resize(50)
257+
if evicted != 50 {
258+
t.Fatalf("bad: %d", evicted)
259+
}
260+
261+
if n := l.recent.Len(); n != 12 {
262+
t.Fatalf("bad: %d", n)
263+
}
264+
if n := l.frequent.Len(); n != 38 {
265+
t.Fatalf("bad: %d", n)
266+
}
267+
268+
l, err = New2Q[int, int](100)
269+
if err != nil {
270+
t.Fatalf("err: %v", err)
271+
}
272+
for i := 0; i < 100; i++ {
273+
l.Add(i, i)
274+
l.Add(i, i)
275+
}
276+
277+
evicted = l.Resize(50)
278+
if evicted != 50 {
279+
t.Fatalf("bad: %d", evicted)
280+
}
281+
282+
if n := l.recent.Len(); n != 0 {
283+
t.Fatalf("bad: %d", n)
284+
}
285+
if n := l.frequent.Len(); n != 50 {
286+
t.Fatalf("bad: %d", n)
287+
}
288+
}
289+
221290
func Test2Q(t *testing.T) {
222291
l, err := New2Q[int, int](128)
223292
if err != nil {

0 commit comments

Comments
 (0)