4
4
"fmt"
5
5
"sync"
6
6
7
- "github.com/hashicorp/golang-lru/simplelru"
7
+ "github.com/hashicorp/golang-lru/v2/ simplelru"
8
8
)
9
9
10
10
const (
@@ -26,25 +26,25 @@ const (
26
26
// computationally about 2x the cost, and adds some metadata over
27
27
// head. The ARCCache is similar, but does not require setting any
28
28
// parameters.
29
- type TwoQueueCache struct {
29
+ type TwoQueueCache [ K comparable , V any ] struct {
30
30
size int
31
31
recentSize int
32
32
33
- recent simplelru.LRUCache
34
- frequent simplelru.LRUCache
35
- recentEvict simplelru.LRUCache
33
+ recent simplelru.LRUCache [ K , V ]
34
+ frequent simplelru.LRUCache [ K , V ]
35
+ recentEvict simplelru.LRUCache [ K , V ]
36
36
lock sync.RWMutex
37
37
}
38
38
39
39
// New2Q creates a new TwoQueueCache using the default
40
40
// values for the parameters.
41
- func New2Q (size int ) (* TwoQueueCache , error ) {
42
- return New2QParams (size , Default2QRecentRatio , Default2QGhostEntries )
41
+ func New2Q [ K comparable , V any ] (size int ) (* TwoQueueCache [ K , V ] , error ) {
42
+ return New2QParams [ K , V ] (size , Default2QRecentRatio , Default2QGhostEntries )
43
43
}
44
44
45
45
// New2QParams creates a new TwoQueueCache using the provided
46
46
// parameter values.
47
- func New2QParams (size int , recentRatio , ghostRatio float64 ) (* TwoQueueCache , error ) {
47
+ func New2QParams [ K comparable , V any ] (size int , recentRatio , ghostRatio float64 ) (* TwoQueueCache [ K , V ] , error ) {
48
48
if size <= 0 {
49
49
return nil , fmt .Errorf ("invalid size" )
50
50
}
@@ -60,21 +60,21 @@ func New2QParams(size int, recentRatio, ghostRatio float64) (*TwoQueueCache, err
60
60
evictSize := int (float64 (size ) * ghostRatio )
61
61
62
62
// Allocate the LRUs
63
- recent , err := simplelru .NewLRU (size , nil )
63
+ recent , err := simplelru .NewLRU [ K , V ] (size , nil )
64
64
if err != nil {
65
65
return nil , err
66
66
}
67
- frequent , err := simplelru .NewLRU (size , nil )
67
+ frequent , err := simplelru .NewLRU [ K , V ] (size , nil )
68
68
if err != nil {
69
69
return nil , err
70
70
}
71
- recentEvict , err := simplelru .NewLRU (evictSize , nil )
71
+ recentEvict , err := simplelru .NewLRU [ K , V ] (evictSize , nil )
72
72
if err != nil {
73
73
return nil , err
74
74
}
75
75
76
76
// Initialize the cache
77
- c := & TwoQueueCache {
77
+ c := & TwoQueueCache [ K , V ] {
78
78
size : size ,
79
79
recentSize : recentSize ,
80
80
recent : recent ,
@@ -85,7 +85,7 @@ func New2QParams(size int, recentRatio, ghostRatio float64) (*TwoQueueCache, err
85
85
}
86
86
87
87
// Get looks up a key's value from the cache.
88
- func (c * TwoQueueCache ) Get (key interface {} ) (value interface {} , ok bool ) {
88
+ func (c * TwoQueueCache [ K , V ] ) Get (key K ) (value V , ok bool ) {
89
89
c .lock .Lock ()
90
90
defer c .lock .Unlock ()
91
91
@@ -103,11 +103,11 @@ func (c *TwoQueueCache) Get(key interface{}) (value interface{}, ok bool) {
103
103
}
104
104
105
105
// No hit
106
- return nil , false
106
+ return
107
107
}
108
108
109
109
// Add adds a value to the cache.
110
- func (c * TwoQueueCache ) Add (key , value interface {} ) {
110
+ func (c * TwoQueueCache [ K , V ] ) Add (key K , value V ) {
111
111
c .lock .Lock ()
112
112
defer c .lock .Unlock ()
113
113
@@ -141,7 +141,7 @@ func (c *TwoQueueCache) Add(key, value interface{}) {
141
141
}
142
142
143
143
// ensureSpace is used to ensure we have space in the cache
144
- func (c * TwoQueueCache ) ensureSpace (recentEvict bool ) {
144
+ func (c * TwoQueueCache [ K , V ] ) ensureSpace (recentEvict bool ) {
145
145
// If we have space, nothing to do
146
146
recentLen := c .recent .Len ()
147
147
freqLen := c .frequent .Len ()
@@ -153,7 +153,8 @@ func (c *TwoQueueCache) ensureSpace(recentEvict bool) {
153
153
// the target, evict from there
154
154
if recentLen > 0 && (recentLen > c .recentSize || (recentLen == c .recentSize && ! recentEvict )) {
155
155
k , _ , _ := c .recent .RemoveOldest ()
156
- c .recentEvict .Add (k , nil )
156
+ var empty V
157
+ c .recentEvict .Add (k , empty )
157
158
return
158
159
}
159
160
@@ -162,15 +163,15 @@ func (c *TwoQueueCache) ensureSpace(recentEvict bool) {
162
163
}
163
164
164
165
// Len returns the number of items in the cache.
165
- func (c * TwoQueueCache ) Len () int {
166
+ func (c * TwoQueueCache [ K , V ] ) Len () int {
166
167
c .lock .RLock ()
167
168
defer c .lock .RUnlock ()
168
169
return c .recent .Len () + c .frequent .Len ()
169
170
}
170
171
171
172
// Keys returns a slice of the keys in the cache.
172
173
// The frequently used keys are first in the returned slice.
173
- func (c * TwoQueueCache ) Keys () []interface {} {
174
+ func (c * TwoQueueCache [ K , V ] ) Keys () []K {
174
175
c .lock .RLock ()
175
176
defer c .lock .RUnlock ()
176
177
k1 := c .frequent .Keys ()
@@ -179,7 +180,7 @@ func (c *TwoQueueCache) Keys() []interface{} {
179
180
}
180
181
181
182
// Remove removes the provided key from the cache.
182
- func (c * TwoQueueCache ) Remove (key interface {} ) {
183
+ func (c * TwoQueueCache [ K , V ] ) Remove (key K ) {
183
184
c .lock .Lock ()
184
185
defer c .lock .Unlock ()
185
186
if c .frequent .Remove (key ) {
@@ -194,7 +195,7 @@ func (c *TwoQueueCache) Remove(key interface{}) {
194
195
}
195
196
196
197
// Purge is used to completely clear the cache.
197
- func (c * TwoQueueCache ) Purge () {
198
+ func (c * TwoQueueCache [ K , V ] ) Purge () {
198
199
c .lock .Lock ()
199
200
defer c .lock .Unlock ()
200
201
c .recent .Purge ()
@@ -204,15 +205,15 @@ func (c *TwoQueueCache) Purge() {
204
205
205
206
// Contains is used to check if the cache contains a key
206
207
// without updating recency or frequency.
207
- func (c * TwoQueueCache ) Contains (key interface {} ) bool {
208
+ func (c * TwoQueueCache [ K , V ] ) Contains (key K ) bool {
208
209
c .lock .RLock ()
209
210
defer c .lock .RUnlock ()
210
211
return c .frequent .Contains (key ) || c .recent .Contains (key )
211
212
}
212
213
213
214
// Peek is used to inspect the cache value of a key
214
215
// without updating recency or frequency.
215
- func (c * TwoQueueCache ) Peek (key interface {} ) (value interface {} , ok bool ) {
216
+ func (c * TwoQueueCache [ K , V ] ) Peek (key K ) (value V , ok bool ) {
216
217
c .lock .RLock ()
217
218
defer c .lock .RUnlock ()
218
219
if val , ok := c .frequent .Peek (key ); ok {
0 commit comments