Don't use defer for mutex unlocking (it currently adds ~200ns)

master
Patrick Mylund Nielsen 13 years ago
parent 13b338b204
commit 91bd4334f1

@ -34,6 +34,8 @@ type Cache struct {
type cache struct { type cache struct {
DefaultExpiration time.Duration DefaultExpiration time.Duration
Items map[string]*Item 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 mu sync.Mutex
janitor *janitor janitor *janitor
} }
@ -42,9 +44,8 @@ type cache struct {
// cache's default expiration time is used. If it is -1, the item never expires. // 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) { func (c *cache) Set(k string, x interface{}, d time.Duration) {
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock()
c.set(k, x, d) c.set(k, x, d)
c.mu.Unlock()
} }
func (c *cache) set(k string, x interface{}, d time.Duration) { 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. // or if the existing item has expired. Returns an error if not.
func (c *cache) Add(k string, x interface{}, d time.Duration) error { func (c *cache) Add(k string, x interface{}, d time.Duration) error {
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock()
_, found := c.get(k) _, found := c.get(k)
if found { if found {
c.mu.Unlock()
return fmt.Errorf("Item %s already exists", k) return fmt.Errorf("Item %s already exists", k)
} }
c.set(k, x, d) c.set(k, x, d)
c.mu.Unlock()
return nil return nil
} }
@ -80,13 +81,13 @@ func (c *cache) Add(k string, x interface{}, d time.Duration) error {
// it does not. // it does not.
func (c *cache) Replace(k string, x interface{}, d time.Duration) error { func (c *cache) Replace(k string, x interface{}, d time.Duration) error {
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock()
_, found := c.get(k) _, found := c.get(k)
if !found { if !found {
c.mu.Unlock()
return fmt.Errorf("Item %s doesn't exist", k) return fmt.Errorf("Item %s doesn't exist", k)
} }
c.set(k, x, d) c.set(k, x, d)
c.mu.Unlock()
return nil 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. // the given key was found in the cache.
func (c *cache) Get(k string) (interface{}, bool) { func (c *cache) Get(k string) (interface{}, bool) {
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() x, found := c.get(k)
c.mu.Unlock()
return c.get(k) return x, found
} }
func (c *cache) get(k string) (interface{}, bool) { 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. // n. Passing a negative number will cause the item to be decremented.
func (c *cache) IncrementFloat(k string, n float64) error { func (c *cache) IncrementFloat(k string, n float64) error {
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock()
v, found := c.Items[k] v, found := c.Items[k]
if !found || v.Expired() { if !found || v.Expired() {
c.mu.Unlock()
return fmt.Errorf("Item not found") return fmt.Errorf("Item not found")
} }
t := reflect.TypeOf(v.Object) t := reflect.TypeOf(v.Object)
switch t.Kind() { switch t.Kind() {
default: default:
c.mu.Unlock()
return fmt.Errorf("The value of %s is not an integer", k) return fmt.Errorf("The value of %s is not an integer", k)
case reflect.Uint: case reflect.Uint:
v.Object = v.Object.(uint) + uint(n) v.Object = v.Object.(uint) + uint(n)
@ -155,6 +156,7 @@ func (c *cache) IncrementFloat(k string, n float64) error {
case reflect.Float64: case reflect.Float64:
v.Object = v.Object.(float64) + n v.Object = v.Object.(float64) + n
} }
c.mu.Unlock()
return nil 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. // Deletes an item from the cache. Does nothing if the item does not exist in the cache.
func (c *cache) Delete(k string) { func (c *cache) Delete(k string) {
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock()
c.delete(k) c.delete(k)
c.mu.Unlock()
} }
func (c *cache) delete(k string) { func (c *cache) delete(k string) {
@ -189,13 +190,12 @@ func (c *cache) delete(k string) {
// Deletes all expired items from the cache. // Deletes all expired items from the cache.
func (c *cache) DeleteExpired() { func (c *cache) DeleteExpired() {
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock()
for k, v := range c.Items { for k, v := range c.Items {
if v.Expired() { if v.Expired() {
c.delete(k) c.delete(k)
} }
} }
c.mu.Unlock()
} }
// Writes the cache's items (using Gob) to an io.Writer. // 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. // Deletes all items from the cache.
func (c *cache) Flush() { func (c *cache) Flush() {
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock()
c.Items = map[string]*Item{} c.Items = map[string]*Item{}
c.mu.Unlock()
} }
type janitor struct { type janitor struct {

@ -675,11 +675,11 @@ func BenchmarkCacheSetDelete(b *testing.B) {
func BenchmarkCacheSetDeleteSingleLock(b *testing.B) { func BenchmarkCacheSetDeleteSingleLock(b *testing.B) {
tc := New(0, 0) tc := New(0, 0)
tc.mu.Lock() tc.mu.Lock()
defer tc.mu.Unlock()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
tc.set("foo", "bar", 0) tc.set("foo", "bar", 0)
tc.delete("foo") tc.delete("foo")
} }
tc.mu.Unlock()
} }
func BenchmarkMapSetDelete(b *testing.B) { func BenchmarkMapSetDelete(b *testing.B) {

Loading…
Cancel
Save