Skip to content

Commit b4c0f97

Browse files
committed
Add another test, clean up add logic a bit
1 parent a7814ff commit b4c0f97

File tree

2 files changed

+104
-12
lines changed

2 files changed

+104
-12
lines changed

clock/clock.go

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -75,19 +75,18 @@ func (c *Cache[K, V]) Add(key K, val V) {
7575
value: val,
7676
})
7777
c.indices[key] = len(c.buf) - 1
78-
c.clockhand = (c.clockhand + 1) % len(c.buf)
79-
return
80-
}
81-
// Full, evict by reference bit then replace
82-
hand := c.clockhand
83-
for c.touches[hand].Load() > 0 {
84-
c.touches[hand].Add(-1)
85-
hand = (hand + 1) % len(c.buf)
78+
} else {
79+
// Full, evict by reference bit then replace
80+
for c.touches[c.clockhand].Load() > 0 {
81+
c.touches[c.clockhand].Add(-1)
82+
c.clockhand += 1 % len(c.buf)
83+
}
84+
c.Evict(c.buf[c.clockhand].key)
85+
c.buf.insertAt(c.clockhand, key, val)
86+
c.indices[key] = c.clockhand
87+
c.touches[c.clockhand].Add(1)
8688
}
87-
c.Evict(c.buf[hand].key)
88-
c.buf.insertAt(hand, key, val)
89-
c.indices[key] = hand
90-
c.clockhand = hand
89+
c.clockhand = (c.clockhand + 1) % len(c.buf)
9190
}
9291

9392
// Get returns the value for a given key, if present.

clock/clock_test.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,96 @@ func TestCacheGet(t *testing.T) {
4444
})
4545
}
4646
}
47+
48+
func TestCacheAdd(t *testing.T) {
49+
tests := []struct {
50+
name string
51+
size int
52+
keysToAdd []string
53+
valueToAdd []string
54+
expectedCache buffer[string, string]
55+
}{
56+
{
57+
"beyond_capacity_evicts_first_untouched",
58+
3,
59+
[]string{"key-a", "key-b", "key-c", "key-d", "key-e"},
60+
[]string{"val-a", "val-b", "val-c", "val-d", "val-e"},
61+
buffer[string, string]{
62+
&bufferItem[string, string]{key: "key-e", value: "val-e"},
63+
&bufferItem[string, string]{key: "key-b", value: "val-b"},
64+
&bufferItem[string, string]{key: "key-d", value: "val-d"},
65+
},
66+
},
67+
{
68+
"multiple_touches_decreases_eviction_chances",
69+
3,
70+
[]string{"key-a", "key-b", "key-c", "key-a", "key-a", "key-d", "key-e"},
71+
[]string{"val-a", "val-b", "val-c", "val-a", "val-a", "val-d", "val-e"},
72+
buffer[string, string]{
73+
&bufferItem[string, string]{key: "key-a", value: "val-a"},
74+
&bufferItem[string, string]{key: "key-e", value: "val-e"},
75+
&bufferItem[string, string]{key: "key-d", value: "val-d"},
76+
},
77+
},
78+
}
79+
for _, test := range tests {
80+
t.Run(test.name, func(t *testing.T) {
81+
cache := New[string, string](test.size)
82+
for i := 0; i < len(test.keysToAdd); i++ {
83+
key := test.keysToAdd[i]
84+
val := test.valueToAdd[i]
85+
cache.Add(key, val)
86+
}
87+
for i := 0; i < len(cache.buf); i++ {
88+
cachedKey := cache.buf[i].key
89+
cachedValue := cache.buf[i].value
90+
expectedKey := test.expectedCache[i].key
91+
expectedValue := test.expectedCache[i].value
92+
if cachedKey != expectedKey {
93+
t.Fatalf("bad cache key; got %s, wanted %s at index %d", cachedKey, expectedKey, i)
94+
}
95+
if cachedValue != expectedValue {
96+
t.Fatalf("bad cache value; got %s, wanted %s at index %d", cachedValue, expectedValue, i)
97+
}
98+
}
99+
})
100+
}
101+
}
102+
103+
func BenchmarkGetAllHits(b *testing.B) {
104+
b.ReportAllocs()
105+
type complexStruct struct {
106+
a, b, c, d, e, f int64
107+
k, l, m, n, o, p float64
108+
}
109+
// Populate the cache
110+
l := New[int, complexStruct](32)
111+
for z := 0; z < 32; z++ {
112+
l.Add(z, complexStruct{a: int64(z)})
113+
}
114+
115+
b.ResetTimer()
116+
for z := 0; z < b.N; z++ {
117+
// take the lower 5 bits as mod 32 so we always hit
118+
l.Get(z & 31)
119+
}
120+
}
121+
122+
func BenchmarkGetHalfHits(b *testing.B) {
123+
b.ReportAllocs()
124+
type complexStruct struct {
125+
a, b, c, d, e, f int64
126+
k, l, m, n, o, p float64
127+
}
128+
// Populate the cache
129+
l := New[int, complexStruct](32)
130+
for z := 0; z < 32; z++ {
131+
l.Add(z, complexStruct{a: int64(z)})
132+
}
133+
134+
b.ResetTimer()
135+
for z := 0; z < b.N; z++ {
136+
// take the lower 4 bits as mod 16 shifted left by 1 to
137+
l.Get((z&15)<<1 | z&16>>4 | z&1<<4)
138+
}
139+
}

0 commit comments

Comments
 (0)