Add API Framework Revel Source Files
[iec.git] / src / foundation / api / revel / cache / memcached.go
1 // Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved.
2 // Revel Framework source code and usage is governed by a MIT style
3 // license that can be found in the LICENSE file.
4
5 package cache
6
7 import (
8         "errors"
9         "time"
10
11         "github.com/bradfitz/gomemcache/memcache"
12         "github.com/revel/revel/logger"
13 )
14
15 // MemcachedCache wraps the Memcached client to meet the Cache interface.
16 type MemcachedCache struct {
17         *memcache.Client
18         defaultExpiration time.Duration
19 }
20
21 func NewMemcachedCache(hostList []string, defaultExpiration time.Duration) MemcachedCache {
22         return MemcachedCache{memcache.New(hostList...), defaultExpiration}
23 }
24
25 func (c MemcachedCache) Set(key string, value interface{}, expires time.Duration) error {
26         return c.invoke((*memcache.Client).Set, key, value, expires)
27 }
28
29 func (c MemcachedCache) Add(key string, value interface{}, expires time.Duration) error {
30         return c.invoke((*memcache.Client).Add, key, value, expires)
31 }
32
33 func (c MemcachedCache) Replace(key string, value interface{}, expires time.Duration) error {
34         return c.invoke((*memcache.Client).Replace, key, value, expires)
35 }
36
37 func (c MemcachedCache) Get(key string, ptrValue interface{}) error {
38         item, err := c.Client.Get(key)
39         if err != nil {
40                 return convertMemcacheError(err)
41         }
42         return Deserialize(item.Value, ptrValue)
43 }
44
45 func (c MemcachedCache) GetMulti(keys ...string) (Getter, error) {
46         items, err := c.Client.GetMulti(keys)
47         if err != nil {
48                 return nil, convertMemcacheError(err)
49         }
50         return ItemMapGetter(items), nil
51 }
52
53 func (c MemcachedCache) Delete(key string) error {
54         return convertMemcacheError(c.Client.Delete(key))
55 }
56
57 func (c MemcachedCache) Increment(key string, delta uint64) (newValue uint64, err error) {
58         newValue, err = c.Client.Increment(key, delta)
59         return newValue, convertMemcacheError(err)
60 }
61
62 func (c MemcachedCache) Decrement(key string, delta uint64) (newValue uint64, err error) {
63         newValue, err = c.Client.Decrement(key, delta)
64         return newValue, convertMemcacheError(err)
65 }
66
67 func (c MemcachedCache) Flush() error {
68         err := errors.New("Flush: can not flush memcached")
69         cacheLog.Error(err.Error())
70         return err
71 }
72
73 func (c MemcachedCache) invoke(f func(*memcache.Client, *memcache.Item) error,
74         key string, value interface{}, expires time.Duration) error {
75
76         switch expires {
77         case DefaultExpiryTime:
78                 expires = c.defaultExpiration
79         case ForEverNeverExpiry:
80                 expires = time.Duration(0)
81         }
82
83         b, err := Serialize(value)
84         if err != nil {
85                 return err
86         }
87         return convertMemcacheError(f(c.Client, &memcache.Item{
88                 Key:        key,
89                 Value:      b,
90                 Expiration: int32(expires / time.Second),
91         }))
92 }
93
94 // ItemMapGetter implements a Getter on top of the returned item map.
95 type ItemMapGetter map[string]*memcache.Item
96
97 func (g ItemMapGetter) Get(key string, ptrValue interface{}) error {
98         item, ok := g[key]
99         if !ok {
100                 return ErrCacheMiss
101         }
102
103         return Deserialize(item.Value, ptrValue)
104 }
105
106 func convertMemcacheError(err error) error {
107         switch err {
108         case nil:
109                 return nil
110         case memcache.ErrCacheMiss:
111                 return ErrCacheMiss
112         case memcache.ErrNotStored:
113                 return ErrNotStored
114         }
115
116         cacheLog.Error("convertMemcacheError:", "error", err, "trace", logger.NewCallStack())
117         return err
118 }