Checking if an item should be promoted because it's new is the uncommon

case which we can optimize out by being more explicit when we create
a new item
This commit is contained in:
Karl Seguin 2013-11-13 13:46:41 +08:00
parent 3fa767d9ff
commit 6720535fab
5 changed files with 25 additions and 17 deletions

View file

@ -16,7 +16,7 @@ func (b *Bucket) get(key string) *Item {
return b.lookup[key]
}
func (b *Bucket) set(key string, value interface{}, duration time.Duration) *Item {
func (b *Bucket) set(key string, value interface{}, duration time.Duration) (*Item, bool) {
expires := time.Now().Add(duration)
b.Lock()
defer b.Unlock()
@ -25,11 +25,11 @@ func (b *Bucket) set(key string, value interface{}, duration time.Duration) *Ite
existing.value = value
existing.expires = expires
existing.Unlock()
return existing
return existing, false
}
item := newItem(key, value, expires)
b.lookup[key] = item
return item
return item, true
}
func (b *Bucket) delete(key string) {

View file

@ -3,7 +3,7 @@ package ccache
import (
"time"
"testing"
"github.com/karlseguin/gspec"
"github.com/viki-org/gspec"
)
func TestGetMissFromBucket(t *testing.T) {
@ -24,19 +24,23 @@ func TestDeleteItemFromBucket(t *testing.T) {
}
func TestSetsANewBucketItem(t *testing.T) {
spec := gspec.New(t)
bucket := testBucket()
item := bucket.set("spice", TestValue("flow"), time.Minute)
item, new := bucket.set("spice", TestValue("flow"), time.Minute)
assertValue(t, item, "flow")
item = bucket.get("spice")
assertValue(t, item, "flow")
spec.Expect(new).ToEqual(true)
}
func TestSetsAnExistingItem(t *testing.T) {
spec := gspec.New(t)
bucket := testBucket()
item := bucket.set("power", TestValue("9002"), time.Minute)
item, new := bucket.set("power", TestValue("9002"), time.Minute)
assertValue(t, item, "9002")
item = bucket.get("power")
assertValue(t, item, "9002")
spec.Expect(new).ToEqual(false)
}
func testBucket() *Bucket {

View file

@ -42,13 +42,17 @@ func (c *Cache) Get(key string) interface{} {
c.deleteItem(bucket, item)
return nil
}
c.promote(item)
c.conditionalPromote(item)
return item.value
}
func (c *Cache) Set(key string, value interface{}, duration time.Duration) {
item := c.bucket(key).set(key, value, duration)
c.promote(item)
item, new := c.bucket(key).set(key, value, duration)
if new {
c.promote(item)
} else {
c.conditionalPromote(item)
}
}
func (c *Cache) Fetch(key string, duration time.Duration, fetch func() (interface{}, error)) (interface{}, error) {
@ -88,8 +92,12 @@ func (c *Cache) bucket(key string) *Bucket {
return c.buckets[index]
}
func (c *Cache) promote(item *Item) {
func (c *Cache) conditionalPromote(item *Item) {
if item.shouldPromote(c.getsPerPromote) == false { return }
c.promote(item)
}
func (c *Cache) promote(item *Item) {
c.promotables <- item
}

View file

@ -27,7 +27,7 @@ func newItem(key string, value interface{}, expires time.Time) *Item {
func (i *Item) shouldPromote(getsPerPromote int32) bool {
promotions := atomic.AddInt32(&i.promotions, 1)
if promotions == getsPerPromote || promotions == 0 {
if promotions == getsPerPromote {
return true
}
return false

View file

@ -2,16 +2,12 @@ package ccache
import (
"testing"
"github.com/karlseguin/gspec"
"github.com/viki-org/gspec"
)
func TestItemPromotability(t *testing.T) {
spec := gspec.New(t)
item := &Item{promotions: -1}
spec.Expect(item.shouldPromote(5)).ToEqual(true)
spec.Expect(item.shouldPromote(5)).ToEqual(false)
item.promotions = 4
item := &Item{promotions: 4}
spec.Expect(item.shouldPromote(5)).ToEqual(true)
spec.Expect(item.shouldPromote(5)).ToEqual(false)
}