Skip to content

Commit

Permalink
delete expirable LRU Close method
Browse files Browse the repository at this point in the history
  • Loading branch information
paskal committed Aug 7, 2023
1 parent f2e3b29 commit 575866d
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 32 deletions.
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@ import (
func main() {
// make cache with 10ms TTL and 5 max keys
cache := expirable.NewLRU[string, string](5, nil, time.Millisecond*10)
// expirable cache need to be closed after used
defer cache.Close()


// set value under key1.
cache.Add("key1", "val1")
Expand Down
28 changes: 15 additions & 13 deletions expirable/expirable_lru.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const numBuckets = 100
//
// Providing 0 TTL turns expiring off.
//
// Delete expired entries every 1/100th of ttl value.
// Delete expired entries every 1/100th of ttl value. Goroutine which deletes expired entries runs indefinitely.
func NewLRU[K comparable, V any](size int, onEvict EvictCallback[K, V], ttl time.Duration) *LRU[K, V] {
if size < 0 {
size = 0
Expand All @@ -71,8 +71,10 @@ func NewLRU[K comparable, V any](size int, onEvict EvictCallback[K, V], ttl time
res.buckets[i] = bucket[K, V]{entries: make(map[K]*internal.Entry[K, V])}
}

// enable deleteExpired() running in separate goroutine for cache
// with non-zero TTL
// enable deleteExpired() running in separate goroutine for cache with non-zero TTL
//
// Important: done channel is never closed, so deleteExpired() goroutine will never exit,
// it's decided to add functionality to close it in the version later than v2.
if res.ttl != noEvictionTTL {
go func(done <-chan struct{}) {
ticker := time.NewTicker(res.ttl / numBuckets)
Expand Down Expand Up @@ -270,16 +272,16 @@ func (c *LRU[K, V]) Resize(size int) (evicted int) {
}

// Close destroys cleanup goroutine. To clean up the cache, run Purge() before Close().
func (c *LRU[K, V]) Close() {
c.mu.Lock()
defer c.mu.Unlock()
select {
case <-c.done:
return
default:
}
close(c.done)
}
// func (c *LRU[K, V]) Close() {
// c.mu.Lock()
// defer c.mu.Unlock()
// select {
// case <-c.done:
// return
// default:
// }
// close(c.done)
// }

// removeOldest removes the oldest item from the cache. Has to be called with lock!
func (c *LRU[K, V]) removeOldest() {
Expand Down
20 changes: 6 additions & 14 deletions expirable/expirable_lru_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ func BenchmarkLRU_Freq_NoExpire(b *testing.B) {

func BenchmarkLRU_Rand_WithExpire(b *testing.B) {
l := NewLRU[int64, int64](8192, nil, time.Millisecond*10)
defer l.Close()

trace := make([]int64, b.N*2)
for i := 0; i < b.N*2; i++ {
Expand All @@ -94,7 +93,6 @@ func BenchmarkLRU_Rand_WithExpire(b *testing.B) {

func BenchmarkLRU_Freq_WithExpire(b *testing.B) {
l := NewLRU[int64, int64](8192, nil, time.Millisecond*10)
defer l.Close()

trace := make([]int64, b.N*2)
for i := 0; i < b.N*2; i++ {
Expand Down Expand Up @@ -195,7 +193,6 @@ func TestLRUEdgeCases(t *testing.T) {

func TestLRU_Values(t *testing.T) {
lc := NewLRU[string, string](3, nil, 0)
defer lc.Close()

lc.Add("key1", "val1")
lc.Add("key2", "val2")
Expand All @@ -207,17 +204,16 @@ func TestLRU_Values(t *testing.T) {
}
}

func TestExpirableMultipleClose(_ *testing.T) {
lc := NewLRU[string, string](10, nil, 0)
lc.Close()
// should not panic
lc.Close()
}
// func TestExpirableMultipleClose(_ *testing.T) {
// lc := NewLRU[string, string](10, nil, 0)
// lc.Close()
// // should not panic
// lc.Close()
// }

func TestLRUWithPurge(t *testing.T) {
var evicted []string
lc := NewLRU(10, func(key string, value string) { evicted = append(evicted, key, value) }, 150*time.Millisecond)
defer lc.Close()

k, v, ok := lc.GetOldest()
if k != "" {
Expand Down Expand Up @@ -299,7 +295,6 @@ func TestLRUWithPurge(t *testing.T) {

func TestLRUWithPurgeEnforcedBySize(t *testing.T) {
lc := NewLRU[string, string](10, nil, time.Hour)
defer lc.Close()

for i := 0; i < 100; i++ {
i := i
Expand Down Expand Up @@ -370,7 +365,6 @@ func TestLRUInvalidateAndEvict(t *testing.T) {

func TestLoadingExpired(t *testing.T) {
lc := NewLRU[string, string](0, nil, time.Millisecond*5)
defer lc.Close()

lc.Add("key1", "val1")
if lc.Len() != 1 {
Expand Down Expand Up @@ -484,8 +478,6 @@ func TestLRURemoveOldest(t *testing.T) {
func ExampleLRU() {
// make cache with 10ms TTL and 5 max keys
cache := NewLRU[string, string](5, nil, time.Millisecond*10)
// expirable cache need to be closed after used
defer cache.Close()

// set value under key1.
cache.Add("key1", "val1")
Expand Down
3 changes: 0 additions & 3 deletions simplelru/lru.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,6 @@ func (c *LRU[K, V]) Resize(size int) (evicted int) {
return diff
}

// Close does nothing for this type of cache.
func (c *LRU[K, V]) Close() {}

// removeOldest removes the oldest item from the cache.
func (c *LRU[K, V]) removeOldest() {
if ent := c.evictList.Back(); ent != nil {
Expand Down

0 comments on commit 575866d

Please sign in to comment.