Skip to content

Instantly share code, notes, and snippets.

@bmishra
Last active May 11, 2018 06:58
Show Gist options
  • Select an option

  • Save bmishra/a0cb24c0f8f2b86ab17c2040b87de973 to your computer and use it in GitHub Desktop.

Select an option

Save bmishra/a0cb24c0f8f2b86ab17c2040b87de973 to your computer and use it in GitHub Desktop.

Revisions

  1. Binayak Mishra revised this gist May 11, 2018. 1 changed file with 19 additions and 9 deletions.
    28 changes: 19 additions & 9 deletions cache.go
    Original file line number Diff line number Diff line change
    @@ -25,10 +25,17 @@ type cacheItem struct {

    // Error variables
    var (
    ErrNoSuchKey = errors.New("No such key")
    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 }

    @@ -42,28 +49,30 @@ func New() *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{"GET", key, nil, 0, response}
    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) {
    func (c *Cache) Set(key string, val interface{}, ttl int64) (interface{}, error) {
    response := make(chan result)
    c.requests <- request{"SET", key, val, ttl, response}
    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{"EXPIRE", key, nil, 0, response}
    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 "SET":
    case cmdSet:
    item := cacheItem{
    value: req.val,
    }
    @@ -73,17 +82,18 @@ func (c *Cache) server() {
    }

    cache[req.key] = item
    case "GET":
    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}
    delete(cache, req.key)
    c.Expire(req.key)
    } else {
    req.response <- result{e.(cacheItem).value, nil}
    }
    case "EXPIRE":
    case cmdExpire:
    e := cache[req.key]
    if e != nil {
    delete(cache, req.key)
  2. Binayak Mishra created this gist May 9, 2018.
    93 changes: 93 additions & 0 deletions cache.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,93 @@
    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 key")
    ErrItemExpired = errors.New("Expired cache item")
    )

    // 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{"GET", 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) {
    response := make(chan result)
    c.requests <- request{"SET", key, val, ttl, response}
    }

    // Expire remove an item from cache
    func (c *Cache) Expire(key string) {
    response := make(chan result)
    c.requests <- request{"EXPIRE", key, nil, 0, response}
    }

    func (c *Cache) server() {
    cache := make(map[string]interface{})
    for req := range c.requests {
    switch req.cmd {
    case "SET":
    item := cacheItem{
    value: req.val,
    }

    if req.ttl > 0 {
    item.expiry = time.Now().Unix() + req.ttl
    }

    cache[req.key] = item
    case "GET":
    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}
    delete(cache, req.key)
    } else {
    req.response <- result{e.(cacheItem).value, nil}
    }
    case "EXPIRE":
    e := cache[req.key]
    if e != nil {
    delete(cache, req.key)
    }
    }
    }
    }