Buckets must be a power of 2. Move from % to & for determining the bucket.
This commit is contained in:
parent
624c03cd3e
commit
5e131cc17c
7 changed files with 36 additions and 12 deletions
6
cache.go
6
cache.go
|
@ -12,7 +12,7 @@ type Cache struct {
|
|||
*Configuration
|
||||
list *list.List
|
||||
buckets []*Bucket
|
||||
bucketCount uint32
|
||||
bucketMask uint32
|
||||
deletables chan *Item
|
||||
promotables chan *Item
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ func New(config *Configuration) *Cache {
|
|||
c := &Cache{
|
||||
list: list.New(),
|
||||
Configuration: config,
|
||||
bucketCount: uint32(config.buckets),
|
||||
bucketMask: uint32(config.buckets) - 1,
|
||||
buckets: make([]*Bucket, config.buckets),
|
||||
deletables: make(chan *Item, config.deleteBuffer),
|
||||
promotables: make(chan *Item, config.promoteBuffer),
|
||||
|
@ -102,7 +102,7 @@ func (c *Cache) deleteItem(bucket *Bucket, item *Item) {
|
|||
func (c *Cache) bucket(key string) *Bucket {
|
||||
h := fnv.New32a()
|
||||
h.Write([]byte(key))
|
||||
return c.buckets[h.Sum32()%c.bucketCount]
|
||||
return c.buckets[h.Sum32()&c.bucketMask]
|
||||
}
|
||||
|
||||
func (c *Cache) conditionalPromote(item *Item) {
|
||||
|
|
|
@ -30,9 +30,12 @@ func (c *Configuration) MaxItems(max uint64) *Configuration {
|
|||
}
|
||||
|
||||
// Keys are hashed into % bucket count to provide greater concurrency (every set
|
||||
// requires a write lock on the bucket)
|
||||
// [64]
|
||||
// requires a write lock on the bucket). Must be a power of 2 (1, 2, 4, 8, 16, ...)
|
||||
// [16]
|
||||
func (c *Configuration) Buckets(count uint32) *Configuration {
|
||||
if count == 0 || ((count&(^count+1)) == count) == false {
|
||||
count = 16
|
||||
}
|
||||
c.buckets = int(count)
|
||||
return c
|
||||
}
|
||||
|
|
23
configuration_test.go
Normal file
23
configuration_test.go
Normal file
|
@ -0,0 +1,23 @@
|
|||
package ccache
|
||||
|
||||
import (
|
||||
. "github.com/karlseguin/expect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type ConfigurationTests struct{}
|
||||
|
||||
func Test_Configuration(t *testing.T) {
|
||||
Expectify(new(ConfigurationTests), t)
|
||||
}
|
||||
|
||||
func (_ *ConfigurationTests) BucketsPowerOf2() {
|
||||
for i := uint32(0); i < 31; i++ {
|
||||
c := Configure().Buckets(i)
|
||||
if i == 1 || i == 2 || i == 4 || i == 8 || i == 16 {
|
||||
Expect(c.buckets).ToEqual(int(i))
|
||||
} else {
|
||||
Expect(c.buckets).ToEqual(16)
|
||||
}
|
||||
}
|
||||
}
|
3
item.go
3
item.go
|
@ -6,7 +6,6 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
|
||||
type TrackedItem interface {
|
||||
Value() interface{}
|
||||
Release()
|
||||
|
@ -80,7 +79,7 @@ func (i *Item) Expired() bool {
|
|||
|
||||
func (i *Item) TTL() time.Duration {
|
||||
expires := atomic.LoadInt64(&i.expires)
|
||||
return time.Second * time.Duration(expires - time.Now().Unix())
|
||||
return time.Second * time.Duration(expires-time.Now().Unix())
|
||||
}
|
||||
|
||||
func (i *Item) Expires() time.Time {
|
||||
|
|
|
@ -40,7 +40,6 @@ func (i *ItemTests) Expires() {
|
|||
Expect(item.Expires().Unix()).To.Equal(now + 10)
|
||||
}
|
||||
|
||||
|
||||
func (i *ItemTests) Extend() {
|
||||
item := &Item{expires: time.Now().Unix() + 10}
|
||||
item.Extend(time.Minute * 2)
|
||||
|
|
|
@ -12,7 +12,7 @@ type LayeredCache struct {
|
|||
*Configuration
|
||||
list *list.List
|
||||
buckets []*LayeredBucket
|
||||
bucketCount uint32
|
||||
bucketMask uint32
|
||||
deletables chan *Item
|
||||
promotables chan *Item
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ func Layered(config *Configuration) *LayeredCache {
|
|||
c := &LayeredCache{
|
||||
list: list.New(),
|
||||
Configuration: config,
|
||||
bucketCount: uint32(config.buckets),
|
||||
bucketMask: uint32(config.buckets) - 1,
|
||||
buckets: make([]*LayeredBucket, config.buckets),
|
||||
deletables: make(chan *Item, config.deleteBuffer),
|
||||
promotables: make(chan *Item, config.promoteBuffer),
|
||||
|
@ -101,7 +101,7 @@ func (c *LayeredCache) Clear() {
|
|||
func (c *LayeredCache) bucket(key string) *LayeredBucket {
|
||||
h := fnv.New32a()
|
||||
h.Write([]byte(key))
|
||||
return c.buckets[h.Sum32()%c.bucketCount]
|
||||
return c.buckets[h.Sum32()&c.bucketMask]
|
||||
}
|
||||
|
||||
func (c *LayeredCache) conditionalPromote(item *Item) {
|
||||
|
|
|
@ -39,7 +39,7 @@ The most likely configuration options to tweak are:
|
|||
|
||||
Configurations that change the internals of the cache, which aren't as likely to need tweaking:
|
||||
|
||||
* `Buckets` - ccache shards its internal map to provide a greater amount of concurrency. The number of buckets is configurable (default: 16)
|
||||
* `Buckets` - ccache shards its internal map to provide a greater amount of concurrency. Must be a power of 2 (default: 16).
|
||||
* `PromoteBuffer(int)` - the size of the buffer to use to queue promotions (default: 1024)
|
||||
* `DeleteBuffer(int)` the size of the buffer to use to queue deletions (default: 1024)
|
||||
|
||||
|
|
Loading…
Reference in a new issue