Skip to content

Commit 08190fb

Browse files
authored
Merge pull request #27 from Code-Hex/fix/call-janitor-run
fixed to call janitor run method
2 parents 52983e9 + 6cbf7f8 commit 08190fb

File tree

3 files changed

+39
-18
lines changed

3 files changed

+39
-18
lines changed

cache.go

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package cache
22

33
import (
44
"context"
5-
"runtime"
65
"sync"
76
"time"
87

@@ -16,9 +15,13 @@ import (
1615

1716
// Interface is a common-cache interface.
1817
type Interface[K comparable, V any] interface {
18+
// Get looks up a key's value from the cache.
1919
Get(key K) (value V, ok bool)
20+
// Set sets a value to the cache with key. replacing any existing value.
2021
Set(key K, val V)
22+
// Keys returns the keys of the cache. The order is relied on algorithms.
2123
Keys() []K
24+
// Delete deletes the item with provided key from the cache.
2225
Delete(key K)
2326
}
2427

@@ -147,38 +150,30 @@ func WithJanitorInterval[K comparable, V any](d time.Duration) Option[K, V] {
147150
}
148151

149152
// New creates a new thread safe Cache.
150-
// This function will be stopped an internal janitor when the cache is
151-
// no longer referenced anywhere.
153+
// The janitor will not be stopped which is created by this function. If you
154+
// want to stop the janitor gracefully, You should use the `NewContext` function
155+
// instead of this.
152156
//
153157
// There are several Cache replacement policies available with you specified any options.
154158
func New[K comparable, V any](opts ...Option[K, V]) *Cache[K, V] {
155-
o := newOptions[K, V]()
156-
for _, optFunc := range opts {
157-
optFunc(o)
158-
}
159-
ctx, cancel := context.WithCancel(context.Background())
160-
cache := &Cache[K, V]{
161-
cache: o.cache,
162-
janitor: newJanitor(ctx, o.janitorInterval),
163-
}
164-
runtime.SetFinalizer(cache, func(self *Cache[K, V]) {
165-
cancel()
166-
})
167-
return cache
159+
return NewContext(context.Background(), opts...)
168160
}
169161

170162
// NewContext creates a new thread safe Cache with context.
163+
// This function will be stopped an internal janitor when the context is cancelled.
171164
//
172165
// There are several Cache replacement policies available with you specified any options.
173166
func NewContext[K comparable, V any](ctx context.Context, opts ...Option[K, V]) *Cache[K, V] {
174167
o := newOptions[K, V]()
175168
for _, optFunc := range opts {
176169
optFunc(o)
177170
}
178-
return &Cache[K, V]{
171+
cache := &Cache[K, V]{
179172
cache: o.cache,
180173
janitor: newJanitor(ctx, o.janitorInterval),
181174
}
175+
cache.janitor.run(cache.DeleteExpired)
176+
return cache
182177
}
183178

184179
// Get looks up a key's value from the cache.
@@ -202,12 +197,18 @@ func (c *Cache[K, V]) Get(key K) (value V, ok bool) {
202197

203198
// DeleteExpired all expired items from the cache.
204199
func (c *Cache[K, V]) DeleteExpired() {
205-
for _, key := range c.cache.Keys() {
200+
c.mu.Lock()
201+
keys := c.cache.Keys()
202+
c.mu.Unlock()
203+
204+
for _, key := range keys {
205+
c.mu.Lock()
206206
// if is expired, delete it and return nil instead
207207
item, ok := c.cache.Get(key)
208208
if ok && item.Expired() {
209209
c.cache.Delete(key)
210210
}
211+
c.mu.Unlock()
211212
}
212213
}
213214

cache_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"math/rand"
55
"sync"
66
"testing"
7+
"time"
78

89
cache "github.com/Code-Hex/go-generics-cache"
910
"github.com/Code-Hex/go-generics-cache/policy/clock"
@@ -103,3 +104,20 @@ func TestMultiThread(t *testing.T) {
103104
})
104105
}
105106
}
107+
108+
func TestCallJanitor(t *testing.T) {
109+
c := cache.New(
110+
cache.WithJanitorInterval[string, int](100 * time.Millisecond),
111+
)
112+
113+
c.Set("1", 10, cache.WithExpiration(10*time.Millisecond))
114+
c.Set("2", 20, cache.WithExpiration(20*time.Millisecond))
115+
c.Set("3", 30, cache.WithExpiration(30*time.Millisecond))
116+
117+
<-time.After(300 * time.Millisecond)
118+
119+
keys := c.Keys()
120+
if len(keys) != 0 {
121+
t.Errorf("want items is empty but got %d", len(keys))
122+
}
123+
}

janitor.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@ func newJanitor(ctx context.Context, interval time.Duration) *janitor {
2323
return j
2424
}
2525

26+
// stop to stop the janitor.
2627
func (j *janitor) stop() {
2728
j.once.Do(func() { close(j.done) })
2829
}
2930

31+
// run with the given cleanup callback function.
3032
func (j *janitor) run(cleanup func()) {
3133
go func() {
3234
ticker := time.NewTicker(j.interval)

0 commit comments

Comments
 (0)