Don't use defer for mutex unlocking (it currently adds ~200ns)
This commit is contained in:
parent
13b338b204
commit
91bd4334f1
33
cache.go
33
cache.go
@ -34,6 +34,8 @@ type Cache struct {
|
||||
type cache struct {
|
||||
DefaultExpiration time.Duration
|
||||
Items map[string]*Item
|
||||
// TODO: Calls to mu.Unlock are currently not deferred because defer
|
||||
// adds ~200 ns (as of 792c7561af4b+ tip.)
|
||||
mu sync.Mutex
|
||||
janitor *janitor
|
||||
}
|
||||
@ -42,9 +44,8 @@ type cache struct {
|
||||
// cache's default expiration time is used. If it is -1, the item never expires.
|
||||
func (c *cache) Set(k string, x interface{}, d time.Duration) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
c.set(k, x, d)
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
func (c *cache) set(k string, x interface{}, d time.Duration) {
|
||||
@ -66,13 +67,13 @@ func (c *cache) set(k string, x interface{}, d time.Duration) {
|
||||
// or if the existing item has expired. Returns an error if not.
|
||||
func (c *cache) Add(k string, x interface{}, d time.Duration) error {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
_, found := c.get(k)
|
||||
if found {
|
||||
c.mu.Unlock()
|
||||
return fmt.Errorf("Item %s already exists", k)
|
||||
}
|
||||
c.set(k, x, d)
|
||||
c.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -80,13 +81,13 @@ func (c *cache) Add(k string, x interface{}, d time.Duration) error {
|
||||
// it does not.
|
||||
func (c *cache) Replace(k string, x interface{}, d time.Duration) error {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
_, found := c.get(k)
|
||||
if !found {
|
||||
c.mu.Unlock()
|
||||
return fmt.Errorf("Item %s doesn't exist", k)
|
||||
}
|
||||
c.set(k, x, d)
|
||||
c.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -94,9 +95,9 @@ func (c *cache) Replace(k string, x interface{}, d time.Duration) error {
|
||||
// the given key was found in the cache.
|
||||
func (c *cache) Get(k string) (interface{}, bool) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
return c.get(k)
|
||||
x, found := c.get(k)
|
||||
c.mu.Unlock()
|
||||
return x, found
|
||||
}
|
||||
|
||||
func (c *cache) get(k string) (interface{}, bool) {
|
||||
@ -117,16 +118,16 @@ func (c *cache) get(k string) (interface{}, bool) {
|
||||
// n. Passing a negative number will cause the item to be decremented.
|
||||
func (c *cache) IncrementFloat(k string, n float64) error {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
v, found := c.Items[k]
|
||||
if !found || v.Expired() {
|
||||
c.mu.Unlock()
|
||||
return fmt.Errorf("Item not found")
|
||||
}
|
||||
|
||||
t := reflect.TypeOf(v.Object)
|
||||
switch t.Kind() {
|
||||
default:
|
||||
c.mu.Unlock()
|
||||
return fmt.Errorf("The value of %s is not an integer", k)
|
||||
case reflect.Uint:
|
||||
v.Object = v.Object.(uint) + uint(n)
|
||||
@ -155,6 +156,7 @@ func (c *cache) IncrementFloat(k string, n float64) error {
|
||||
case reflect.Float64:
|
||||
v.Object = v.Object.(float64) + n
|
||||
}
|
||||
c.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -177,9 +179,8 @@ func (c *cache) Decrement(k string, n int64) error {
|
||||
// Deletes an item from the cache. Does nothing if the item does not exist in the cache.
|
||||
func (c *cache) Delete(k string) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
c.delete(k)
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
func (c *cache) delete(k string) {
|
||||
@ -189,13 +190,12 @@ func (c *cache) delete(k string) {
|
||||
// Deletes all expired items from the cache.
|
||||
func (c *cache) DeleteExpired() {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
for k, v := range c.Items {
|
||||
if v.Expired() {
|
||||
c.delete(k)
|
||||
}
|
||||
}
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
// Writes the cache's items (using Gob) to an io.Writer.
|
||||
@ -262,9 +262,8 @@ func (c *cache) LoadFile(fname string) error {
|
||||
// Deletes all items from the cache.
|
||||
func (c *cache) Flush() {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
c.Items = map[string]*Item{}
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
type janitor struct {
|
||||
|
@ -675,11 +675,11 @@ func BenchmarkCacheSetDelete(b *testing.B) {
|
||||
func BenchmarkCacheSetDeleteSingleLock(b *testing.B) {
|
||||
tc := New(0, 0)
|
||||
tc.mu.Lock()
|
||||
defer tc.mu.Unlock()
|
||||
for i := 0; i < b.N; i++ {
|
||||
tc.set("foo", "bar", 0)
|
||||
tc.delete("foo")
|
||||
}
|
||||
tc.mu.Unlock()
|
||||
}
|
||||
|
||||
func BenchmarkMapSetDelete(b *testing.B) {
|
||||
|
Loading…
Reference in New Issue
Block a user