cache: make Stop() synchronous and races in tests

worker goroutine running concurrently with tests would cause data race errors
when running tests with -race enabled.
This commit is contained in:
Anthony Romano 2017-02-10 10:51:01 -08:00
parent c69270ce08
commit b3c864ded7
2 changed files with 37 additions and 16 deletions

View file

@ -16,6 +16,7 @@ type Cache struct {
bucketMask uint32
deletables chan *Item
promotables chan *Item
donec chan struct{}
}
// Create a new cache with the specified configuration
@ -26,15 +27,13 @@ func New(config *Configuration) *Cache {
Configuration: config,
bucketMask: uint32(config.buckets) - 1,
buckets: make([]*bucket, config.buckets),
deletables: make(chan *Item, config.deleteBuffer),
promotables: make(chan *Item, config.promoteBuffer),
}
for i := 0; i < int(config.buckets); i++ {
c.buckets[i] = &bucket{
lookup: make(map[string]*Item),
}
}
go c.worker()
c.restart()
return c
}
@ -119,6 +118,14 @@ func (c *Cache) Clear() {
// is called are likely to panic
func (c *Cache) Stop() {
close(c.promotables)
<-c.donec
}
func (c *Cache) restart() {
c.deletables = make(chan *Item, c.deleteBuffer)
c.promotables = make(chan *Item, c.promoteBuffer)
c.donec = make(chan struct{})
go c.worker()
}
func (c *Cache) deleteItem(bucket *bucket, item *Item) {
@ -146,6 +153,8 @@ func (c *Cache) promote(item *Item) {
}
func (c *Cache) worker() {
defer close(c.donec)
for {
select {
case item, ok := <-c.promotables:

View file

@ -41,7 +41,7 @@ func (_ CacheTests) GCsTheOldestItems() {
}
//let the items get promoted (and added to our list)
time.Sleep(time.Millisecond * 10)
cache.gc()
gcCache(cache)
Expect(cache.Get("9")).To.Equal(nil)
Expect(cache.Get("10").Value()).To.Equal(10)
}
@ -54,7 +54,7 @@ func (_ CacheTests) PromotedItemsDontGetPruned() {
time.Sleep(time.Millisecond * 10) //run the worker once to init the list
cache.Get("9")
time.Sleep(time.Millisecond * 10)
cache.gc()
gcCache(cache)
Expect(cache.Get("9").Value()).To.Equal(9)
Expect(cache.Get("10")).To.Equal(nil)
Expect(cache.Get("11").Value()).To.Equal(11)
@ -67,11 +67,11 @@ func (_ CacheTests) TrackerDoesNotCleanupHeldInstance() {
}
item := cache.TrackingGet("0")
time.Sleep(time.Millisecond * 10)
cache.gc()
gcCache(cache)
Expect(cache.Get("0").Value()).To.Equal(0)
Expect(cache.Get("1")).To.Equal(nil)
item.Release()
cache.gc()
gcCache(cache)
Expect(cache.Get("0")).To.Equal(nil)
}
@ -104,19 +104,19 @@ func (_ CacheTests) SetUpdatesSizeOnDelta() {
cache.Set("a", &SizedItem{0, 2}, time.Minute)
cache.Set("b", &SizedItem{0, 3}, time.Minute)
time.Sleep(time.Millisecond * 5)
Expect(cache.size).To.Equal(int64(5))
checkSize(cache, 5)
cache.Set("b", &SizedItem{0, 3}, time.Minute)
time.Sleep(time.Millisecond * 5)
Expect(cache.size).To.Equal(int64(5))
checkSize(cache, 5)
cache.Set("b", &SizedItem{0, 4}, time.Minute)
time.Sleep(time.Millisecond * 5)
Expect(cache.size).To.Equal(int64(6))
checkSize(cache, 6)
cache.Set("b", &SizedItem{0, 2}, time.Minute)
time.Sleep(time.Millisecond * 5)
Expect(cache.size).To.Equal(int64(4))
checkSize(cache, 4)
cache.Delete("b")
time.Sleep(time.Millisecond * 100)
Expect(cache.size).To.Equal(int64(2))
checkSize(cache, 2)
}
func (_ CacheTests) ReplaceDoesNotchangeSizeIfNotSet() {
@ -126,7 +126,7 @@ func (_ CacheTests) ReplaceDoesNotchangeSizeIfNotSet() {
cache.Set("3", &SizedItem{1, 2}, time.Minute)
cache.Replace("4", &SizedItem{1, 2})
time.Sleep(time.Millisecond * 5)
Expect(cache.size).To.Equal(int64(6))
checkSize(cache, 6)
}
func (_ CacheTests) ReplaceChangesSize() {
@ -136,15 +136,15 @@ func (_ CacheTests) ReplaceChangesSize() {
cache.Replace("2", &SizedItem{1, 2})
time.Sleep(time.Millisecond * 5)
Expect(cache.size).To.Equal(int64(4))
checkSize(cache, 4)
cache.Replace("2", &SizedItem{1, 1})
time.Sleep(time.Millisecond * 5)
Expect(cache.size).To.Equal(int64(3))
checkSize(cache, 3)
cache.Replace("2", &SizedItem{1, 3})
time.Sleep(time.Millisecond * 5)
Expect(cache.size).To.Equal(int64(5))
checkSize(cache, 5)
}
type SizedItem struct {
@ -155,3 +155,15 @@ type SizedItem struct {
func (s *SizedItem) Size() int64 {
return s.s
}
func checkSize(cache *Cache, sz int64) {
cache.Stop()
Expect(cache.size).To.Equal(sz)
cache.restart()
}
func gcCache(cache *Cache) {
cache.Stop()
cache.gc()
cache.restart()
}