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 {
|
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…
Reference in New Issue