-
Notifications
You must be signed in to change notification settings - Fork 2
/
tinylfu_test.go
119 lines (108 loc) · 2.95 KB
/
tinylfu_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package cache
import (
"fmt"
"testing"
)
type tinyLFUTest struct {
c cache
lfu tinyLFU
t *testing.T
}
func (t *tinyLFUTest) assertCap(n int) {
if t.lfu.lru.cap+t.lfu.slru.protectedCap+t.lfu.slru.probationCap != n {
t.t.Helper()
t.t.Fatalf("unexpected lru.cap: %d, slru.cap: %d/%d",
t.lfu.lru.cap, t.lfu.slru.protectedCap, t.lfu.slru.probationCap)
}
}
func (t *tinyLFUTest) assertLen(admission, protected, probation int) {
sz := cacheSize(&t.c)
az := t.lfu.lru.ls.Len()
tz := t.lfu.slru.protectedLs.Len()
bz := t.lfu.slru.probationLs.Len()
if sz != admission+protected+probation || az != admission || tz != protected || bz != probation {
t.t.Helper()
t.t.Fatalf("unexpected data length: cache=%d admission=%d protected=%d probation=%d, want: %d %d %d",
sz, az, tz, bz, admission, protected, probation)
}
}
func (t *tinyLFUTest) assertEntry(en *entry, k int, v string, id uint8) {
ak := en.key.(int)
av := en.getValue().(string)
if ak != k || av != v || en.listID != id {
t.t.Helper()
t.t.Fatalf("unexpected entry: %+v, want: {key: %d, value: %s, listID: %d}",
en, k, v, id)
}
}
func (t *tinyLFUTest) assertLRUEntry(k int, id uint8) {
en := t.c.get(k, sum(k))
if en == nil {
t.t.Helper()
t.t.Fatalf("entry not found in cache: key=%v", k)
}
ak := en.key.(int)
av := en.getValue().(string)
v := fmt.Sprintf("%d", k)
if ak != k || av != v || en.listID != id {
t.t.Helper()
t.t.Fatalf("unexpected entry: %+v, want: {key: %d, value: %s, listID: %d}",
en, k, v, id)
}
}
func TestTinyLFU(t *testing.T) {
s := tinyLFUTest{t: t}
s.lfu.init(&s.c, 200)
s.assertCap(200)
s.lfu.slru.protectedCap = 2
s.lfu.slru.probationCap = 1
en := make([]*entry, 10)
for i := range en {
en[i] = newEntry(i, fmt.Sprintf("%d", i), sum(i))
}
for i := 0; i < 5; i++ {
remEn := s.lfu.write(en[i])
if remEn != nil {
t.Fatalf("unexpected entry removed: %+v", remEn)
}
}
// 4 3 | - | 2 1 0
s.assertLen(2, 0, 3)
s.assertLRUEntry(4, admissionWindow)
s.assertLRUEntry(3, admissionWindow)
s.assertLRUEntry(2, probationSegment)
s.assertLRUEntry(1, probationSegment)
s.assertLRUEntry(0, probationSegment)
s.lfu.access(en[1])
s.lfu.access(en[2])
// 4 3 | 2 1 | 0
s.assertLen(2, 2, 1)
s.assertLRUEntry(2, protectedSegment)
s.assertLRUEntry(1, protectedSegment)
s.assertLRUEntry(0, probationSegment)
remEn := s.lfu.write(en[5])
// 5 4 | 2 1 | 0
if remEn == nil {
t.Fatalf("expect an entry removed when adding %+v", en[5])
}
s.assertEntry(remEn, 3, "3", admissionWindow)
s.lfu.access(en[4])
s.lfu.access(en[5])
remEn = s.lfu.write(en[6])
// 6 5 | 2 1 | 4
if remEn == nil {
t.Fatalf("expect an entry removed when adding %+v", en[6])
}
s.assertLen(2, 2, 1)
s.assertEntry(remEn, 0, "0", probationSegment)
n := s.lfu.estimate(en[1].hash)
if n != 2 {
t.Fatalf("unexpected estimate: %d %+v", n, en[1])
}
s.lfu.access(en[2])
s.lfu.access(en[2])
n = s.lfu.estimate(en[2].hash)
if n != 4 {
t.Fatalf("unexpected estimate: %d %+v", n, en[2])
}
}