Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add reason to OnEvictCallback
Browse files Browse the repository at this point in the history
costela committed Aug 5, 2024
1 parent 27252e0 commit 482fbab
Showing 5 changed files with 34 additions and 18 deletions.
15 changes: 8 additions & 7 deletions s3fifo/s3fifo.go
Original file line number Diff line number Diff line change
@@ -3,9 +3,10 @@ package s3fifo
import (
"container/list"
"context"
"github.com/scalalang2/golang-fifo/types"
"sync"
"time"

"github.com/scalalang2/golang-fifo/types"
)

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

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

func (s *S3FIFO[K, V]) removeEntry(e *entry[K, V]) {
func (s *S3FIFO[K, V]) removeEntry(e *entry[K, V], reason types.EvictReason) {
if s.callback != nil {
s.callback(e.key, e.value)
s.callback(e.key, e.value, reason)
}

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

for _, e := range bucket.entries {
s.removeEntry(e)
s.removeEntry(e, types.EvictReasonExpired)
}

s.mu.Unlock()
@@ -292,7 +293,7 @@ func (s *S3FIFO[K, V]) evictFromSmall() {
s.evictFromMain()
}
} else {
s.removeEntry(el)
s.removeEntry(el, types.EvictReasonEvicted)
s.ghost.add(key)
evicted = true
delete(s.items, key)
@@ -314,7 +315,7 @@ func (s *S3FIFO[K, V]) evictFromMain() {
s.items[key].freq -= 1
s.items[key].element = s.main.PushFront(el.key)
} else {
s.removeEntry(el)
s.removeEntry(el, types.EvictReasonEvicted)
evicted = true
delete(s.items, key)
}
5 changes: 3 additions & 2 deletions s3fifo/s3fifo_test.go
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ import (
"time"

"fortio.org/assert"
"github.com/scalalang2/golang-fifo/types"
)

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

cache.SetOnEvicted(func(key int, value int) {
cache.SetOnEvicted(func(key int, value int, _ types.EvictReason) {
evicted[key] = value
})

@@ -216,7 +217,7 @@ func TestEvictionCallbackWithTTL(t *testing.T) {
var mu sync.Mutex
cache := New[int, int](10, time.Second)
evicted := make(map[int]int)
cache.SetOnEvicted(func(key int, value int) {
cache.SetOnEvicted(func(key int, value int, _ types.EvictReason) {
mu.Lock()
evicted[key] = value
mu.Unlock()
12 changes: 6 additions & 6 deletions sieve/sieve.go
Original file line number Diff line number Diff line change
@@ -149,7 +149,7 @@ func (s *Sieve[K, V]) Remove(key K) (ok bool) {
s.hand = s.hand.Prev()
}

s.removeEntry(e)
s.removeEntry(e, types.EvictReasonRemoved)
return true
}

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

for _, e := range s.items {
s.removeEntry(e)
s.removeEntry(e, types.EvictReasonRemoved)
}

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

func (s *Sieve[K, V]) removeEntry(e *entry[K, V]) {
func (s *Sieve[K, V]) removeEntry(e *entry[K, V], reason types.EvictReason) {
if s.callback != nil {
s.callback(e.key, e.value)
s.callback(e.key, e.value, reason)
}

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

s.hand = o.Prev()
s.removeEntry(el)
s.removeEntry(el, types.EvictReasonEvicted)
}

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

for _, e := range bucket.entries {
s.removeEntry(e)
s.removeEntry(e, types.EvictReasonExpired)
}

s.mu.Unlock()
5 changes: 3 additions & 2 deletions sieve/sieve_test.go
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ import (
"time"

"fortio.org/assert"
"github.com/scalalang2/golang-fifo/types"
)

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

cache.SetOnEvicted(func(key int, value int) {
cache.SetOnEvicted(func(key int, value int, _ types.EvictReason) {
evicted[key] = value
})

@@ -170,7 +171,7 @@ func TestEvictionCallbackWithTTL(t *testing.T) {
var mu sync.Mutex
cache := New[int, int](10, time.Second)
evicted := make(map[int]int)
cache.SetOnEvicted(func(key int, value int) {
cache.SetOnEvicted(func(key int, value int, _ types.EvictReason) {
mu.Lock()
evicted[key] = value
mu.Unlock()
15 changes: 14 additions & 1 deletion types/types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
package types

type OnEvictCallback[K comparable, V any] func(key K, value V)
// EvictReason is the reason for an entry to be evicted from the cache.
// It is used in the [OnEvictCallback] function.
type EvictReason int

const (
// EvictReasonExpired is used when an item is removed because its TTL has expired.
EvictReasonExpired = iota
// EvictReasonEvicted is used when an item is removed because the cache size limit was exceeded.
EvictReasonEvicted
// EvictReasonRemoved is used when an item is explicitly deleted.
EvictReasonRemoved
)

type OnEvictCallback[K comparable, V any] func(key K, value V, reason EvictReason)

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

0 comments on commit 482fbab

Please sign in to comment.