|
|
@ -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 {
|
|
|
|