Skip to content

Commit 1a257a8

Browse files
committed
add GetDropped function
1 parent 78289f8 commit 1a257a8

File tree

4 files changed

+60
-21
lines changed

4 files changed

+60
-21
lines changed

cache.go

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ import (
1010

1111
type Cache struct {
1212
*Configuration
13-
list *list.List
14-
size int64
15-
buckets []*bucket
16-
bucketMask uint32
17-
deletables chan *Item
18-
promotables chan *Item
19-
donec chan struct{}
13+
list *list.List
14+
size int64
15+
buckets []*bucket
16+
bucketMask uint32
17+
deletables chan *Item
18+
promotables chan *Item
19+
donec chan struct{}
20+
getDroppedReq chan struct{}
21+
getDroppedRes chan int
2022
}
2123

2224
// Create a new cache with the specified configuration
@@ -27,6 +29,8 @@ func New(config *Configuration) *Cache {
2729
Configuration: config,
2830
bucketMask: uint32(config.buckets) - 1,
2931
buckets: make([]*bucket, config.buckets),
32+
getDroppedReq: make(chan struct{}),
33+
getDroppedRes: make(chan int),
3034
}
3135
for i := 0; i < int(config.buckets); i++ {
3236
c.buckets[i] = &bucket{
@@ -137,6 +141,13 @@ func (c *Cache) Stop() {
137141
<-c.donec
138142
}
139143

144+
// Gets the number of items removed from the cache due to memory pressure since
145+
// the last time GetDropped was called
146+
func (c *Cache) GetDropped() int {
147+
c.getDroppedReq <- struct{}{}
148+
return <-c.getDroppedRes
149+
}
150+
140151
func (c *Cache) restart() {
141152
c.deletables = make(chan *Item, c.deleteBuffer)
142153
c.promotables = make(chan *Item, c.promoteBuffer)
@@ -170,18 +181,21 @@ func (c *Cache) promote(item *Item) {
170181

171182
func (c *Cache) worker() {
172183
defer close(c.donec)
173-
184+
dropped := 0
174185
for {
175186
select {
176187
case item, ok := <-c.promotables:
177188
if ok == false {
178189
goto drain
179190
}
180191
if c.doPromote(item) && c.size > c.maxSize {
181-
c.gc()
192+
dropped += c.gc()
182193
}
183194
case item := <-c.deletables:
184195
c.doDelete(item)
196+
case _ = <-c.getDroppedReq:
197+
c.getDroppedRes <- dropped
198+
dropped = 0
185199
}
186200
}
187201

@@ -227,11 +241,12 @@ func (c *Cache) doPromote(item *Item) bool {
227241
return true
228242
}
229243

230-
func (c *Cache) gc() {
244+
func (c *Cache) gc() int {
245+
dropped := 0
231246
element := c.list.Back()
232247
for i := 0; i < c.itemsToPrune; i++ {
233248
if element == nil {
234-
return
249+
return dropped
235250
}
236251
prev := element.Prev()
237252
item := element.Value.(*Item)
@@ -242,8 +257,10 @@ func (c *Cache) gc() {
242257
if c.onDelete != nil {
243258
c.onDelete(item)
244259
}
260+
dropped += 1
245261
item.promotions = -2
246262
}
247263
element = prev
248264
}
265+
return dropped
249266
}

cache_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ func (_ CacheTests) RemovesOldestItemWhenFullBySizer() {
156156
Expect(cache.Get("2")).To.Equal(nil)
157157
Expect(cache.Get("3")).To.Equal(nil)
158158
Expect(cache.Get("4").Value().(*SizedItem).id).To.Equal(4)
159+
Expect(cache.GetDropped()).To.Equal(4)
160+
Expect(cache.GetDropped()).To.Equal(0)
159161
}
160162

161163
func (_ CacheTests) SetUpdatesSizeOnDelta() {

layeredcache.go

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ import (
1010

1111
type LayeredCache struct {
1212
*Configuration
13-
list *list.List
14-
buckets []*layeredBucket
15-
bucketMask uint32
16-
size int64
17-
deletables chan *Item
18-
promotables chan *Item
19-
donec chan struct{}
13+
list *list.List
14+
buckets []*layeredBucket
15+
bucketMask uint32
16+
size int64
17+
deletables chan *Item
18+
promotables chan *Item
19+
donec chan struct{}
20+
getDroppedReq chan struct{}
21+
getDroppedRes chan int
2022
}
2123

2224
// Create a new layered cache with the specified configuration.
@@ -39,6 +41,8 @@ func Layered(config *Configuration) *LayeredCache {
3941
bucketMask: uint32(config.buckets) - 1,
4042
buckets: make([]*layeredBucket, config.buckets),
4143
deletables: make(chan *Item, config.deleteBuffer),
44+
getDroppedReq: make(chan struct{}),
45+
getDroppedRes: make(chan int),
4246
}
4347
for i := 0; i < int(config.buckets); i++ {
4448
c.buckets[i] = &layeredBucket{
@@ -162,6 +166,13 @@ func (c *LayeredCache) Stop() {
162166
<-c.donec
163167
}
164168

169+
// Gets the number of items removed from the cache due to memory pressure since
170+
// the last time GetDropped was called
171+
func (c *LayeredCache) GetDropped() int {
172+
c.getDroppedReq <- struct{}{}
173+
return <-c.getDroppedRes
174+
}
175+
165176
func (c *LayeredCache) restart() {
166177
c.promotables = make(chan *Item, c.promoteBuffer)
167178
c.donec = make(chan struct{})
@@ -189,14 +200,15 @@ func (c *LayeredCache) promote(item *Item) {
189200

190201
func (c *LayeredCache) worker() {
191202
defer close(c.donec)
203+
dropped := 0
192204
for {
193205
select {
194206
case item, ok := <-c.promotables:
195207
if ok == false {
196208
return
197209
}
198210
if c.doPromote(item) && c.size > c.maxSize {
199-
c.gc()
211+
dropped += c.gc()
200212
}
201213
case item := <-c.deletables:
202214
if item.element == nil {
@@ -208,6 +220,9 @@ func (c *LayeredCache) worker() {
208220
}
209221
c.list.Remove(item.element)
210222
}
223+
case _ = <-c.getDroppedReq:
224+
c.getDroppedRes <- dropped
225+
dropped = 0
211226
}
212227
}
213228
}
@@ -229,11 +244,12 @@ func (c *LayeredCache) doPromote(item *Item) bool {
229244
return true
230245
}
231246

232-
func (c *LayeredCache) gc() {
247+
func (c *LayeredCache) gc() int {
233248
element := c.list.Back()
249+
dropped := 0
234250
for i := 0; i < c.itemsToPrune; i++ {
235251
if element == nil {
236-
return
252+
return dropped
237253
}
238254
prev := element.Prev()
239255
item := element.Value.(*Item)
@@ -242,7 +258,9 @@ func (c *LayeredCache) gc() {
242258
c.size -= item.size
243259
c.list.Remove(element)
244260
item.promotions = -2
261+
dropped += 1
245262
}
246263
element = prev
247264
}
265+
return dropped
248266
}

layeredcache_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ func (_ LayeredCacheTests) RemovesOldestItemWhenFull() {
170170
Expect(cache.Get("2", "a")).To.Equal(nil)
171171
Expect(cache.Get("3", "a").Value()).To.Equal(3)
172172
Expect(cache.Get("xx", "b").Value()).To.Equal(9001)
173+
Expect(cache.GetDropped()).To.Equal(4)
174+
Expect(cache.GetDropped()).To.Equal(0)
173175
}
174176

175177
func newLayered() *LayeredCache {

0 commit comments

Comments
 (0)