Support cache expiry based on create/last access time

This commit is contained in:
Soam Vasani
2016-11-05 21:41:57 -07:00
parent 68f860dcb3
commit 9dcadd5f4a
+36 -21
View File
@@ -19,6 +19,7 @@ package cache
import ( import (
"time" "time"
"errors"
"fmt" "fmt"
"github.com/platform9/fission" "github.com/platform9/fission"
) )
@@ -40,8 +41,9 @@ type (
value interface{} value interface{}
} }
Cache struct { Cache struct {
cache map[interface{}]Value cache map[interface{}]*Value
expiryTime time.Duration ctimeExpiry time.Duration
atimeExpiry time.Duration
requestChannel chan *request requestChannel chan *request
} }
@@ -53,29 +55,33 @@ type (
} }
response struct { response struct {
error error
mapCopy map[interface{}]interface{} existingValue interface{}
value interface{} mapCopy map[interface{}]interface{}
value interface{}
} }
) )
func (c *Cache) IsOld(v *Value) bool { func (c *Cache) IsOld(v *Value) bool {
if c.expiryTime == time.Duration(0) { if (c.ctimeExpiry != time.Duration(0)) && (time.Now().Sub(v.ctime) > c.ctimeExpiry) {
return false
}
if time.Now().Sub(v.ctime) > c.expiryTime {
return true return true
} }
if (c.atimeExpiry != time.Duration(0)) && (time.Now().Sub(v.atime) > c.atimeExpiry) {
return true
}
return false return false
} }
func MakeCache(expiryTime time.Duration) *Cache { func MakeCache(ctimeExpiry, atimeExpiry time.Duration) *Cache {
c := &Cache{ c := &Cache{
cache: make(map[interface{}]Value), cache: make(map[interface{}]*Value),
expiryTime: expiryTime, ctimeExpiry: ctimeExpiry,
atimeExpiry: atimeExpiry,
requestChannel: make(chan *request), requestChannel: make(chan *request),
} }
go c.service() go c.service()
if expiryTime != time.Duration(0) { if ctimeExpiry != time.Duration(0) || atimeExpiry != time.Duration(0) {
go c.expiryService() go c.expiryService()
} }
return c return c
@@ -91,7 +97,7 @@ func (c *Cache) service() {
if !ok { if !ok {
resp.error = fission.MakeError(fission.ErrorNotFound, resp.error = fission.MakeError(fission.ErrorNotFound,
fmt.Sprintf("key '%v' not found", req.key)) fmt.Sprintf("key '%v' not found", req.key))
} else if c.IsOld(&val) { } else if c.IsOld(val) {
resp.error = fission.MakeError(fission.ErrorNotFound, resp.error = fission.MakeError(fission.ErrorNotFound,
fmt.Sprintf("key '%v' expired (atime %v)", req.key, val.atime)) fmt.Sprintf("key '%v' expired (atime %v)", req.key, val.atime))
delete(c.cache, req.key) delete(c.cache, req.key)
@@ -104,10 +110,17 @@ func (c *Cache) service() {
req.responseChannel <- resp req.responseChannel <- resp
case SET: case SET:
now := time.Now() now := time.Now()
c.cache[req.key] = Value{ if _, ok := c.cache[req.key]; ok {
value: req.value, val := c.cache[req.key]
ctime: now, val.atime = time.Now()
atime: now, resp.existingValue = val.value
resp.error = errors.New("value already exists")
} else {
c.cache[req.key] = &Value{
value: req.value,
ctime: now,
atime: now,
}
} }
req.responseChannel <- resp req.responseChannel <- resp
case DELETE: case DELETE:
@@ -115,7 +128,7 @@ func (c *Cache) service() {
req.responseChannel <- resp req.responseChannel <- resp
case EXPIRE: case EXPIRE:
for k, v := range c.cache { for k, v := range c.cache {
if c.IsOld(&v) { if c.IsOld(v) {
delete(c.cache, k) delete(c.cache, k)
} }
} }
@@ -123,7 +136,7 @@ func (c *Cache) service() {
case COPY: case COPY:
resp.mapCopy = make(map[interface{}]interface{}) resp.mapCopy = make(map[interface{}]interface{})
for k, v := range c.cache { for k, v := range c.cache {
resp.mapCopy[k] = v resp.mapCopy[k] = v.value
} }
req.responseChannel <- resp req.responseChannel <- resp
default: default:
@@ -145,7 +158,9 @@ func (c *Cache) Get(key interface{}) (interface{}, error) {
return resp.value, resp.error return resp.value, resp.error
} }
func (c *Cache) Set(key interface{}, value interface{}) error { // if key exists in the cache, the new value is NOT set; instead an
// error and the old value are returned
func (c *Cache) Set(key interface{}, value interface{}) (error, interface{}) {
respChannel := make(chan *response) respChannel := make(chan *response)
c.requestChannel <- &request{ c.requestChannel <- &request{
requestType: SET, requestType: SET,
@@ -154,7 +169,7 @@ func (c *Cache) Set(key interface{}, value interface{}) error {
responseChannel: respChannel, responseChannel: respChannel,
} }
resp := <-respChannel resp := <-respChannel
return resp.error return resp.error, resp.existingValue
} }
func (c *Cache) Delete(key interface{}) error { func (c *Cache) Delete(key interface{}) error {