Skip to content

Commit 08edb9d

Browse files
costelascalalang2
authored andcommitted
feat: add reason to OnEvictCallback
1 parent 59489b8 commit 08edb9d

File tree

5 files changed

+48
-30
lines changed

5 files changed

+48
-30
lines changed

s3fifo/s3fifo.go

+8-7
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ package s3fifo
33
import (
44
"container/list"
55
"context"
6-
"github.com/scalalang2/golang-fifo/types"
76
"sync"
87
"time"
8+
9+
"github.com/scalalang2/golang-fifo/types"
910
)
1011

1112
const numberOfBuckets = 100
@@ -150,7 +151,7 @@ func (s *S3FIFO[K, V]) Remove(key K) (ok bool) {
150151
s.mu.Lock()
151152
defer s.mu.Unlock()
152153
if e, ok := s.items[key]; ok {
153-
s.removeEntry(e)
154+
s.removeEntry(e, types.EvictReasonRemoved)
154155
return true
155156
}
156157

@@ -209,9 +210,9 @@ func (s *S3FIFO[K, V]) Close() {
209210
s.mu.Unlock()
210211
}
211212

212-
func (s *S3FIFO[K, V]) removeEntry(e *entry[K, V]) {
213+
func (s *S3FIFO[K, V]) removeEntry(e *entry[K, V], reason types.EvictReason) {
213214
if s.callback != nil {
214-
s.callback(e.key, e.value)
215+
s.callback(e.key, e.value, reason)
215216
}
216217

217218
if s.ghost.contains(e.key) {
@@ -256,7 +257,7 @@ func (s *S3FIFO[K, V]) deleteExpired() {
256257
}
257258

258259
for _, e := range bucket.entries {
259-
s.removeEntry(e)
260+
s.removeEntry(e, types.EvictReasonExpired)
260261
}
261262

262263
s.mu.Unlock()
@@ -292,7 +293,7 @@ func (s *S3FIFO[K, V]) evictFromSmall() {
292293
s.evictFromMain()
293294
}
294295
} else {
295-
s.removeEntry(el)
296+
s.removeEntry(el, types.EvictReasonEvicted)
296297
s.ghost.add(key)
297298
evicted = true
298299
delete(s.items, key)
@@ -314,7 +315,7 @@ func (s *S3FIFO[K, V]) evictFromMain() {
314315
s.items[key].freq -= 1
315316
s.items[key].element = s.main.PushFront(el.key)
316317
} else {
317-
s.removeEntry(el)
318+
s.removeEntry(el, types.EvictReasonEvicted)
318319
evicted = true
319320
delete(s.items, key)
320321
}

s3fifo/s3fifo_test.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"time"
77

88
"fortio.org/assert"
9+
"github.com/scalalang2/golang-fifo/types"
910
)
1011

1112
const noEvictionTTL = 0
@@ -192,7 +193,7 @@ func TestEvictionCallback(t *testing.T) {
192193
cache := New[int, int](10, noEvictionTTL)
193194
evicted := make(map[int]int)
194195

195-
cache.SetOnEvicted(func(key int, value int) {
196+
cache.SetOnEvicted(func(key int, value int, _ types.EvictReason) {
196197
evicted[key] = value
197198
})
198199

@@ -216,7 +217,7 @@ func TestEvictionCallbackWithTTL(t *testing.T) {
216217
var mu sync.Mutex
217218
cache := New[int, int](10, time.Second)
218219
evicted := make(map[int]int)
219-
cache.SetOnEvicted(func(key int, value int) {
220+
cache.SetOnEvicted(func(key int, value int, _ types.EvictReason) {
220221
mu.Lock()
221222
evicted[key] = value
222223
mu.Unlock()

sieve/sieve.go

+20-18
Original file line numberDiff line numberDiff line change
@@ -81,23 +81,25 @@ func New[K comparable, V any](size int, ttl time.Duration) *Sieve[K, V] {
8181
}
8282

8383
if ttl != 0 {
84-
go func(ctx context.Context) {
85-
ticker := time.NewTicker(ttl / numberOfBuckets)
86-
defer ticker.Stop()
87-
for {
88-
select {
89-
case <-ctx.Done():
90-
return
91-
case <-ticker.C:
92-
cache.deleteExpired()
93-
}
94-
}
95-
}(cache.ctx)
84+
go cache.cleanup(cache.ctx)
9685
}
9786

9887
return cache
9988
}
10089

90+
func (s *Sieve[K, V]) cleanup(ctx context.Context) {
91+
ticker := time.NewTicker(s.ttl / numberOfBuckets)
92+
defer ticker.Stop()
93+
for {
94+
select {
95+
case <-ctx.Done():
96+
return
97+
case <-ticker.C:
98+
s.deleteExpired()
99+
}
100+
}
101+
}
102+
101103
func (s *Sieve[K, V]) Set(key K, value V) {
102104
s.mu.Lock()
103105
defer s.mu.Unlock()
@@ -147,7 +149,7 @@ func (s *Sieve[K, V]) Remove(key K) (ok bool) {
147149
s.hand = s.hand.Prev()
148150
}
149151

150-
s.removeEntry(e)
152+
s.removeEntry(e, types.EvictReasonRemoved)
151153
return true
152154
}
153155

@@ -191,7 +193,7 @@ func (s *Sieve[K, V]) Purge() {
191193
defer s.mu.Unlock()
192194

193195
for _, e := range s.items {
194-
s.removeEntry(e)
196+
s.removeEntry(e, types.EvictReasonRemoved)
195197
}
196198

197199
for i := range s.buckets {
@@ -213,9 +215,9 @@ func (s *Sieve[K, V]) Close() {
213215
s.mu.Unlock()
214216
}
215217

216-
func (s *Sieve[K, V]) removeEntry(e *entry[K, V]) {
218+
func (s *Sieve[K, V]) removeEntry(e *entry[K, V], reason types.EvictReason) {
217219
if s.callback != nil {
218-
s.callback(e.key, e.value)
220+
s.callback(e.key, e.value, reason)
219221
}
220222

221223
s.ll.Remove(e.element)
@@ -249,7 +251,7 @@ func (s *Sieve[K, V]) evict() {
249251
}
250252

251253
s.hand = o.Prev()
252-
s.removeEntry(el)
254+
s.removeEntry(el, types.EvictReasonEvicted)
253255
}
254256

255257
func (s *Sieve[K, V]) addToBucket(e *entry[K, V]) {
@@ -285,7 +287,7 @@ func (s *Sieve[K, V]) deleteExpired() {
285287
}
286288

287289
for _, e := range bucket.entries {
288-
s.removeEntry(e)
290+
s.removeEntry(e, types.EvictReasonExpired)
289291
}
290292

291293
s.mu.Unlock()

sieve/sieve_test.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"time"
77

88
"fortio.org/assert"
9+
"github.com/scalalang2/golang-fifo/types"
910
)
1011

1112
const noEvictionTTL = 0
@@ -146,7 +147,7 @@ func TestEvictionCallback(t *testing.T) {
146147
cache := New[int, int](10, noEvictionTTL)
147148
evicted := make(map[int]int)
148149

149-
cache.SetOnEvicted(func(key int, value int) {
150+
cache.SetOnEvicted(func(key int, value int, _ types.EvictReason) {
150151
evicted[key] = value
151152
})
152153

@@ -170,7 +171,7 @@ func TestEvictionCallbackWithTTL(t *testing.T) {
170171
var mu sync.Mutex
171172
cache := New[int, int](10, time.Second)
172173
evicted := make(map[int]int)
173-
cache.SetOnEvicted(func(key int, value int) {
174+
cache.SetOnEvicted(func(key int, value int, _ types.EvictReason) {
174175
mu.Lock()
175176
evicted[key] = value
176177
mu.Unlock()

types/types.go

+14-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
11
package types
22

3-
type OnEvictCallback[K comparable, V any] func(key K, value V)
3+
// EvictReason is the reason for an entry to be evicted from the cache.
4+
// It is used in the [OnEvictCallback] function.
5+
type EvictReason int
6+
7+
const (
8+
// EvictReasonExpired is used when an item is removed because its TTL has expired.
9+
EvictReasonExpired = iota
10+
// EvictReasonEvicted is used when an item is removed because the cache size limit was exceeded.
11+
EvictReasonEvicted
12+
// EvictReasonRemoved is used when an item is explicitly deleted.
13+
EvictReasonRemoved
14+
)
15+
16+
type OnEvictCallback[K comparable, V any] func(key K, value V, reason EvictReason)
417

518
// Cache is the interface for a cache.
619
type Cache[K comparable, V any] interface {

0 commit comments

Comments
 (0)