Last active
May 11, 2018 06:58
-
-
Save bmishra/a0cb24c0f8f2b86ab17c2040b87de973 to your computer and use it in GitHub Desktop.
Simple in-memory cache
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package cache | |
| import ( | |
| "errors" | |
| "time" | |
| ) | |
| type request struct { | |
| cmd string | |
| key string | |
| val interface{} | |
| ttl int64 // seconds | |
| response chan<- result | |
| } | |
| type result struct { | |
| value interface{} | |
| err error | |
| } | |
| type cacheItem struct { | |
| value interface{} | |
| expiry int64 | |
| } | |
| // Error variables | |
| var ( | |
| ErrNoSuchKey = errors.New("No such cache item") | |
| ErrItemExpired = errors.New("Expired cache item") | |
| ) | |
| // commands | |
| const ( | |
| cmdGet = "GET" | |
| cmdSet = "SET" | |
| cmdExpire = "EXPIRE" | |
| ) | |
| // Cache simple in-memory cache | |
| type Cache struct{ requests chan request } | |
| // New init new Cache | |
| func New() *Cache { | |
| cache := &Cache{requests: make(chan request)} | |
| go cache.server() | |
| return cache | |
| } | |
| // Get fetch a value from cache, returns error if key is missing | |
| func (c *Cache) Get(key string) (interface{}, error) { | |
| response := make(chan result) | |
| c.requests <- request{cmdGet, key, nil, 0, response} | |
| res := <-response | |
| return res.value, res.err | |
| } | |
| // Set sets a key value pair into the cache | |
| func (c *Cache) Set(key string, val interface{}, ttl int64) (interface{}, error) { | |
| response := make(chan result) | |
| c.requests <- request{cmdSet, key, val, ttl, response} | |
| res := <-response | |
| return res.value, res.err | |
| } | |
| // Expire remove an item from cache | |
| func (c *Cache) Expire(key string) { | |
| response := make(chan result) | |
| c.requests <- request{cmdExpire, key, nil, 0, response} | |
| } | |
| func (c *Cache) server() { | |
| cache := make(map[string]interface{}) | |
| for req := range c.requests { | |
| switch req.cmd { | |
| case cmdSet: | |
| item := cacheItem{ | |
| value: req.val, | |
| } | |
| if req.ttl > 0 { | |
| item.expiry = time.Now().Unix() + req.ttl | |
| } | |
| cache[req.key] = item | |
| req.response <- result{1, nil} | |
| case cmdGet: | |
| e := cache[req.key] | |
| if e == nil { | |
| req.response <- result{nil, ErrNoSuchKey} | |
| } else if e.(cacheItem).expiry > 0 && time.Now().Unix() > e.(cacheItem).expiry { | |
| req.response <- result{nil, ErrItemExpired} | |
| c.Expire(req.key) | |
| } else { | |
| req.response <- result{e.(cacheItem).value, nil} | |
| } | |
| case cmdExpire: | |
| e := cache[req.key] | |
| if e != nil { | |
| delete(cache, req.key) | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment