Codebase list golang-github-renekroon-ttlcache / aa8a254
New upstream version 1.7.0+ds Sascha Steinbiss 3 years ago
6 changed file(s) with 119 addition(s) and 33 deletion(s). Raw diff Collapse all Expand all
00 language: go
11
22 go:
3 - 1.13
4 - 1.12
3 - "1.14"
4 - "1.13"
55 git:
66 depth: 1
77
88 install:
99 - go install -race std
10 - go get golang.org/x/tools/cmd/cover
11 - go get golang.org/x/lint/golint
10 - go install golang.org/x/tools/cmd/cover
11 - go install golang.org/x/lint/golint
1212 - export PATH=$HOME/gopath/bin:$PATH
1313
1414 script:
77 4. Fast and memory efficient
88 5. Can trigger callback on key expiration
99 6. Cleanup resources by calling `Close()` at end of lifecycle.
10
11 Note (issue #25): by default, due to historic reasons, the TTL will be reset on each cache hit and you need to explicitly configure the cache to use a TTL that will not get extended.
1012
1113 [![Build Status](https://travis-ci.org/ReneKroon/ttlcache.svg?branch=master)](https://travis-ci.org/ReneKroon/ttlcache)
1214
3739 }
3840
3941 cache := ttlcache.NewCache()
40 defer ttlcache.Close()
42 defer cache.Close()
4143 cache.SetTTL(time.Duration(10 * time.Second))
4244 cache.SetExpirationCallback(expirationCallback)
4345
6264 The main differences are:
6365
6466 1. A item can store any kind of object, previously, only strings could be saved
65 2. Optionally, you can add callbacks to: check if a value should expire, be notified if a value expires, and be notified when new values are added to the cache
67 2. Optionally, you can add callbacks too: check if a value should expire, be notified if a value expires, and be notified when new values are added to the cache
6668 3. The expiration can be either global or per item
6769 4. Can exist items without expiration time
6870 5. Expirations and callbacks are realtime. Don't have a pooling time to check anymore, now it's done with a heap.
7979 select {
8080 case shutdownFeedback := <-cache.shutdownSignal:
8181 timer.Stop()
82 cache.mutex.Lock()
83 if cache.priorityQueue.Len() > 0 {
84 cache.evictjob()
85 }
86 cache.mutex.Unlock()
8287 shutdownFeedback <- struct{}{}
8388 return
8489 case <-timer.C:
8994 continue
9095 }
9196
92 // index will only be advanced if the current entry will not be evicted
93 i := 0
94 for item := cache.priorityQueue.items[i]; item.expired(); item = cache.priorityQueue.items[i] {
95
96 if cache.checkExpireCallback != nil {
97 if !cache.checkExpireCallback(item.key, item.data) {
98 item.touch()
99 cache.priorityQueue.update(item)
100 i++
101 if i == cache.priorityQueue.Len() {
102 break
103 }
104 continue
105 }
106 }
107
108 cache.priorityQueue.remove(item)
109 delete(cache.items, item.key)
110 if cache.expireCallback != nil {
111 go cache.expireCallback(item.key, item.data)
112 }
113 if cache.priorityQueue.Len() == 0 {
114 goto done
115 }
116 }
117 done:
97 cache.cleanjob()
11898 cache.mutex.Unlock()
11999
120100 case <-cache.expirationNotification:
121101 timer.Stop()
122102 continue
103 }
104 }
105 }
106
107 func (cache *Cache) evictjob() {
108 // index will only be advanced if the current entry will not be evicted
109 i := 0
110 for item := cache.priorityQueue.items[i]; ; item = cache.priorityQueue.items[i] {
111
112 cache.priorityQueue.remove(item)
113 delete(cache.items, item.key)
114 if cache.expireCallback != nil {
115 go cache.expireCallback(item.key, item.data)
116 }
117 if cache.priorityQueue.Len() == 0 {
118 return
119 }
120 }
121 }
122
123 func (cache *Cache) cleanjob() {
124 // index will only be advanced if the current entry will not be evicted
125 i := 0
126 for item := cache.priorityQueue.items[i]; item.expired(); item = cache.priorityQueue.items[i] {
127
128 if cache.checkExpireCallback != nil {
129 if !cache.checkExpireCallback(item.key, item.data) {
130 item.touch()
131 cache.priorityQueue.update(item)
132 i++
133 if i == cache.priorityQueue.Len() {
134 break
135 }
136 continue
137 }
138 }
139
140 cache.priorityQueue.remove(item)
141 delete(cache.items, item.key)
142 if cache.expireCallback != nil {
143 go cache.expireCallback(item.key, item.data)
144 }
145 if cache.priorityQueue.Len() == 0 {
146 return
123147 }
124148 }
125149 }
1515 func TestMain(m *testing.M) {
1616 goleak.VerifyTestMain(m)
1717 }
18
19 // Issue #28: call expirationCallback automatically on cache.Close()
20 func TestCache_ExpirationOnClose(t *testing.T) {
21
22 cache := NewCache()
23
24 success := make(chan struct{})
25 defer close(success)
26
27 cache.SetTTL(time.Hour * 100)
28 cache.SetExpirationCallback(func(key string, value interface{}) {
29 t.Logf("%s\t%v", key, value)
30 success <- struct{}{}
31 })
32 cache.Set("1", 1)
33 cache.Set("2", 1)
34 cache.Set("3", 1)
35
36 found := 0
37 cache.Close()
38 wait := time.NewTimer(time.Millisecond * 100)
39 for found != 3 {
40 select {
41 case <-success:
42 found++
43 case <-wait.C:
44 t.Fail()
45 }
46 }
47
48 }
49
50 // # Issue 29: After Close() the behaviour of Get, Set, Remove is not defined.
51 /*
52 func TestCache_ModifyAfterClose(t *testing.T) {
53 cache := NewCache()
54
55 cache.SetTTL(time.Hour * 100)
56 cache.SetExpirationCallback(func(key string, value interface{}) {
57 t.Logf("%s\t%v", key, value)
58 })
59 cache.Set("1", 1)
60 cache.Set("2", 1)
61 cache.Set("3", 1)
62
63 cache.Close()
64
65 cache.Get("broken3")
66 cache.Set("broken", 1)
67 cache.Remove("broken2")
68
69 wait := time.NewTimer(time.Millisecond * 100)
70
71 select {
72 case <-wait.C:
73 t.Fail()
74 }
75
76 }*/
1877
1978 // Issue #23: Goroutine leak on closing. When adding a close method i would like to see
2079 // that it can be called in a repeated way without problems.
00 module github.com/ReneKroon/ttlcache
11
2 go 1.12
2 go 1.14
33
44 require (
55 github.com/davecgh/go-spew v1.1.1 // indirect
22 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
33 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
44 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5 github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
56 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
67 github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
78 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=