Add API Framework Revel Source Files
[iec.git] / src / foundation / api / revel / cache / inmemory.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         "fmt"
9         "reflect"
10         "time"
11
12         "github.com/patrickmn/go-cache"
13         "sync"
14 )
15
16 type InMemoryCache struct {
17         cache cache.Cache  // Only expose the methods we want to make available
18         mu    sync.RWMutex // For increment / decrement prevent reads and writes
19 }
20
21 func NewInMemoryCache(defaultExpiration time.Duration) InMemoryCache {
22         return InMemoryCache{cache: *cache.New(defaultExpiration, time.Minute), mu: sync.RWMutex{}}
23 }
24
25 func (c InMemoryCache) Get(key string, ptrValue interface{}) error {
26         c.mu.RLock()
27         defer c.mu.RUnlock()
28
29         value, found := c.cache.Get(key)
30         if !found {
31                 return ErrCacheMiss
32         }
33
34         v := reflect.ValueOf(ptrValue)
35         if v.Type().Kind() == reflect.Ptr && v.Elem().CanSet() {
36                 v.Elem().Set(reflect.ValueOf(value))
37                 return nil
38         }
39
40         err := fmt.Errorf("revel/cache: attempt to get %s, but can not set value %v", key, v)
41         cacheLog.Error(err.Error())
42         return err
43 }
44
45 func (c InMemoryCache) GetMulti(keys ...string) (Getter, error) {
46         return c, nil
47 }
48
49 func (c InMemoryCache) Set(key string, value interface{}, expires time.Duration) error {
50         c.mu.Lock()
51         defer c.mu.Unlock()
52         // NOTE: go-cache understands the values of DefaultExpiryTime and ForEverNeverExpiry
53         c.cache.Set(key, value, expires)
54         return nil
55 }
56
57 func (c InMemoryCache) Add(key string, value interface{}, expires time.Duration) error {
58         c.mu.Lock()
59         defer c.mu.Unlock()
60         err := c.cache.Add(key, value, expires)
61         if err != nil {
62                 return ErrNotStored
63         }
64         return err
65 }
66
67 func (c InMemoryCache) Replace(key string, value interface{}, expires time.Duration) error {
68         c.mu.Lock()
69         defer c.mu.Unlock()
70         if err := c.cache.Replace(key, value, expires); err != nil {
71                 return ErrNotStored
72         }
73         return nil
74 }
75
76 func (c InMemoryCache) Delete(key string) error {
77         c.mu.RLock()
78         defer c.mu.RUnlock()
79         if _, found := c.cache.Get(key); !found {
80                 return ErrCacheMiss
81         }
82         c.cache.Delete(key)
83         return nil
84 }
85
86 func (c InMemoryCache) Increment(key string, n uint64) (newValue uint64, err error) {
87         c.mu.Lock()
88         defer c.mu.Unlock()
89         if _, found := c.cache.Get(key); !found {
90                 return 0, ErrCacheMiss
91         }
92         if err = c.cache.Increment(key, int64(n)); err != nil {
93                 return
94         }
95
96         return c.convertTypeToUint64(key)
97 }
98
99 func (c InMemoryCache) Decrement(key string, n uint64) (newValue uint64, err error) {
100         c.mu.Lock()
101         defer c.mu.Unlock()
102         if nv, err := c.convertTypeToUint64(key); err != nil {
103                 return 0, err
104         } else {
105                 // Stop from going below zero
106                 if n > nv {
107                         n = nv
108                 }
109         }
110         if err = c.cache.Decrement(key, int64(n)); err != nil {
111                 return
112         }
113
114         return c.convertTypeToUint64(key)
115 }
116
117 func (c InMemoryCache) Flush() error {
118         c.mu.Lock()
119         defer c.mu.Unlock()
120
121         c.cache.Flush()
122         return nil
123 }
124
125 // Fetches and returns the converted type to a uint64
126 func (c InMemoryCache) convertTypeToUint64(key string) (newValue uint64, err error) {
127         v, found := c.cache.Get(key)
128         if !found {
129                 return newValue, ErrCacheMiss
130         }
131
132         switch v.(type) {
133         case int:
134                 newValue = uint64(v.(int))
135         case int8:
136                 newValue = uint64(v.(int8))
137         case int16:
138                 newValue = uint64(v.(int16))
139         case int32:
140                 newValue = uint64(v.(int32))
141         case int64:
142                 newValue = uint64(v.(int64))
143         case uint:
144                 newValue = uint64(v.(uint))
145         case uintptr:
146                 newValue = uint64(v.(uintptr))
147         case uint8:
148                 newValue = uint64(v.(uint8))
149         case uint16:
150                 newValue = uint64(v.(uint16))
151         case uint32:
152                 newValue = uint64(v.(uint32))
153         case uint64:
154                 newValue = uint64(v.(uint64))
155         case float32:
156                 newValue = uint64(v.(float32))
157         case float64:
158                 newValue = uint64(v.(float64))
159         default:
160                 err = ErrInvalidValue
161         }
162         return
163 }