智慧食堂
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

240 lines
4.9 KiB

  1. package cache
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "sync"
  6. "time"
  7. )
  8. var (
  9. // DefaultEvery means the clock time of recycling the expired cache items in memory.
  10. DefaultEvery = 60 // 1 minute
  11. )
  12. // MemoryItem store memory cache item.
  13. type MemoryItem struct {
  14. val interface{}
  15. createdTime time.Time
  16. lifespan time.Duration
  17. }
  18. func (mi *MemoryItem) isExpire() bool {
  19. // 0 means forever
  20. if mi.lifespan == 0 {
  21. return false
  22. }
  23. return time.Now().Sub(mi.createdTime) > mi.lifespan
  24. }
  25. // MemoryCache is Memory cache adapter.
  26. // it contains a RW locker for safe map storage.
  27. type MemoryCache struct {
  28. sync.RWMutex
  29. dur time.Duration
  30. items map[string]*MemoryItem
  31. Every int // run an expiration check Every clock time
  32. }
  33. // NewMemoryCache returns a new MemoryCache.
  34. func NewMemoryCache() Cache {
  35. cache := MemoryCache{items: make(map[string]*MemoryItem)}
  36. return &cache
  37. }
  38. // Get cache from memory.
  39. // if non-existed or expired, return nil.
  40. func (bc *MemoryCache) Get(name string) interface{} {
  41. bc.RLock()
  42. defer bc.RUnlock()
  43. if itm, ok := bc.items[name]; ok {
  44. if itm.isExpire() {
  45. return nil
  46. }
  47. return itm.val
  48. }
  49. return nil
  50. }
  51. // GetMulti gets caches from memory.
  52. // if non-existed or expired, return nil.
  53. func (bc *MemoryCache) GetMulti(names []string) []interface{} {
  54. var rc []interface{}
  55. for _, name := range names {
  56. rc = append(rc, bc.Get(name))
  57. }
  58. return rc
  59. }
  60. // Put cache to memory.
  61. // if lifespan is 0, it will be forever till restart.
  62. func (bc *MemoryCache) Put(name string, value interface{}, lifespan time.Duration) error {
  63. bc.Lock()
  64. defer bc.Unlock()
  65. bc.items[name] = &MemoryItem{
  66. val: value,
  67. createdTime: time.Now(),
  68. lifespan: lifespan,
  69. }
  70. return nil
  71. }
  72. // Delete cache in memory.
  73. func (bc *MemoryCache) Delete(name string) error {
  74. bc.Lock()
  75. defer bc.Unlock()
  76. if _, ok := bc.items[name]; !ok {
  77. return errors.New("key not exist")
  78. }
  79. delete(bc.items, name)
  80. if _, ok := bc.items[name]; ok {
  81. return errors.New("delete key error")
  82. }
  83. return nil
  84. }
  85. // Incr increase cache counter in memory.
  86. // it supports int,int32,int64,uint,uint32,uint64.
  87. func (bc *MemoryCache) Incr(key string) error {
  88. bc.RLock()
  89. defer bc.RUnlock()
  90. itm, ok := bc.items[key]
  91. if !ok {
  92. return errors.New("key not exist")
  93. }
  94. switch itm.val.(type) {
  95. case int:
  96. itm.val = itm.val.(int) + 1
  97. case int32:
  98. itm.val = itm.val.(int32) + 1
  99. case int64:
  100. itm.val = itm.val.(int64) + 1
  101. case uint:
  102. itm.val = itm.val.(uint) + 1
  103. case uint32:
  104. itm.val = itm.val.(uint32) + 1
  105. case uint64:
  106. itm.val = itm.val.(uint64) + 1
  107. default:
  108. return errors.New("item val is not (u)int (u)int32 (u)int64")
  109. }
  110. return nil
  111. }
  112. // Decr decrease counter in memory.
  113. func (bc *MemoryCache) Decr(key string) error {
  114. bc.RLock()
  115. defer bc.RUnlock()
  116. itm, ok := bc.items[key]
  117. if !ok {
  118. return errors.New("key not exist")
  119. }
  120. switch itm.val.(type) {
  121. case int:
  122. itm.val = itm.val.(int) - 1
  123. case int64:
  124. itm.val = itm.val.(int64) - 1
  125. case int32:
  126. itm.val = itm.val.(int32) - 1
  127. case uint:
  128. if itm.val.(uint) > 0 {
  129. itm.val = itm.val.(uint) - 1
  130. } else {
  131. return errors.New("item val is less than 0")
  132. }
  133. case uint32:
  134. if itm.val.(uint32) > 0 {
  135. itm.val = itm.val.(uint32) - 1
  136. } else {
  137. return errors.New("item val is less than 0")
  138. }
  139. case uint64:
  140. if itm.val.(uint64) > 0 {
  141. itm.val = itm.val.(uint64) - 1
  142. } else {
  143. return errors.New("item val is less than 0")
  144. }
  145. default:
  146. return errors.New("item val is not int int64 int32")
  147. }
  148. return nil
  149. }
  150. // IsExist check cache exist in memory.
  151. func (bc *MemoryCache) IsExist(name string) bool {
  152. bc.RLock()
  153. defer bc.RUnlock()
  154. if v, ok := bc.items[name]; ok {
  155. return !v.isExpire()
  156. }
  157. return false
  158. }
  159. // ClearAll will delete all cache in memory.
  160. func (bc *MemoryCache) ClearAll() error {
  161. bc.Lock()
  162. defer bc.Unlock()
  163. bc.items = make(map[string]*MemoryItem)
  164. return nil
  165. }
  166. // StartAndGC start memory cache. it will check expiration in every clock time.
  167. func (bc *MemoryCache) StartAndGC(config string) error {
  168. var cf map[string]int
  169. json.Unmarshal([]byte(config), &cf)
  170. if _, ok := cf["interval"]; !ok {
  171. cf = make(map[string]int)
  172. cf["interval"] = DefaultEvery
  173. }
  174. dur := time.Duration(cf["interval"]) * time.Second
  175. bc.Every = cf["interval"]
  176. bc.dur = dur
  177. go bc.vacuum()
  178. return nil
  179. }
  180. // check expiration.
  181. func (bc *MemoryCache) vacuum() {
  182. bc.RLock()
  183. every := bc.Every
  184. bc.RUnlock()
  185. if every < 1 {
  186. return
  187. }
  188. for {
  189. <-time.After(bc.dur)
  190. if bc.items == nil {
  191. return
  192. }
  193. if keys := bc.expiredKeys(); len(keys) != 0 {
  194. bc.clearItems(keys)
  195. }
  196. }
  197. }
  198. // expiredKeys returns key list which are expired.
  199. func (bc *MemoryCache) expiredKeys() (keys []string) {
  200. bc.RLock()
  201. defer bc.RUnlock()
  202. for key, itm := range bc.items {
  203. if itm.isExpire() {
  204. keys = append(keys, key)
  205. }
  206. }
  207. return
  208. }
  209. // clearItems removes all the items which key in keys.
  210. func (bc *MemoryCache) clearItems(keys []string) {
  211. bc.Lock()
  212. defer bc.Unlock()
  213. for _, key := range keys {
  214. delete(bc.items, key)
  215. }
  216. }
  217. func init() {
  218. Register("memory", NewMemoryCache)
  219. }