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.

179 lines
3.7 KiB

  1. // Copyright 2013 Beego Authors
  2. // Copyright 2014 The Macaron Authors
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License"): you may
  5. // not use this file except in compliance with the License. You may obtain
  6. // a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. // License for the specific language governing permissions and limitations
  14. // under the License.
  15. package cache
  16. import (
  17. "errors"
  18. "sync"
  19. "time"
  20. )
  21. // MemoryItem represents a memory cache item.
  22. type MemoryItem struct {
  23. val interface{}
  24. created int64
  25. expire int64
  26. }
  27. func (item *MemoryItem) hasExpired() bool {
  28. return item.expire > 0 &&
  29. (time.Now().Unix()-item.created) >= item.expire
  30. }
  31. // MemoryCacher represents a memory cache adapter implementation.
  32. type MemoryCacher struct {
  33. lock sync.RWMutex
  34. items map[string]*MemoryItem
  35. interval int // GC interval.
  36. }
  37. // NewMemoryCacher creates and returns a new memory cacher.
  38. func NewMemoryCacher() *MemoryCacher {
  39. return &MemoryCacher{items: make(map[string]*MemoryItem)}
  40. }
  41. // Put puts value into cache with key and expire time.
  42. // If expired is 0, it will be deleted by next GC operation.
  43. func (c *MemoryCacher) Put(key string, val interface{}, expire int64) error {
  44. c.lock.Lock()
  45. defer c.lock.Unlock()
  46. c.items[key] = &MemoryItem{
  47. val: val,
  48. created: time.Now().Unix(),
  49. expire: expire,
  50. }
  51. return nil
  52. }
  53. // Get gets cached value by given key.
  54. func (c *MemoryCacher) Get(key string) interface{} {
  55. c.lock.RLock()
  56. defer c.lock.RUnlock()
  57. item, ok := c.items[key]
  58. if !ok {
  59. return nil
  60. }
  61. if item.hasExpired() {
  62. go c.Delete(key)
  63. return nil
  64. }
  65. return item.val
  66. }
  67. // Delete deletes cached value by given key.
  68. func (c *MemoryCacher) Delete(key string) error {
  69. c.lock.Lock()
  70. defer c.lock.Unlock()
  71. delete(c.items, key)
  72. return nil
  73. }
  74. // Incr increases cached int-type value by given key as a counter.
  75. func (c *MemoryCacher) Incr(key string) (err error) {
  76. c.lock.RLock()
  77. defer c.lock.RUnlock()
  78. item, ok := c.items[key]
  79. if !ok {
  80. return errors.New("key not exist")
  81. }
  82. item.val, err = Incr(item.val)
  83. return err
  84. }
  85. // Decr decreases cached int-type value by given key as a counter.
  86. func (c *MemoryCacher) Decr(key string) (err error) {
  87. c.lock.RLock()
  88. defer c.lock.RUnlock()
  89. item, ok := c.items[key]
  90. if !ok {
  91. return errors.New("key not exist")
  92. }
  93. item.val, err = Decr(item.val)
  94. return err
  95. }
  96. // IsExist returns true if cached value exists.
  97. func (c *MemoryCacher) IsExist(key string) bool {
  98. c.lock.RLock()
  99. defer c.lock.RUnlock()
  100. _, ok := c.items[key]
  101. return ok
  102. }
  103. // Flush deletes all cached data.
  104. func (c *MemoryCacher) Flush() error {
  105. c.lock.Lock()
  106. defer c.lock.Unlock()
  107. c.items = make(map[string]*MemoryItem)
  108. return nil
  109. }
  110. func (c *MemoryCacher) checkRawExpiration(key string) {
  111. item, ok := c.items[key]
  112. if !ok {
  113. return
  114. }
  115. if item.hasExpired() {
  116. delete(c.items, key)
  117. }
  118. }
  119. func (c *MemoryCacher) checkExpiration(key string) {
  120. c.lock.Lock()
  121. defer c.lock.Unlock()
  122. c.checkRawExpiration(key)
  123. }
  124. func (c *MemoryCacher) startGC() {
  125. c.lock.Lock()
  126. defer c.lock.Unlock()
  127. if c.interval < 1 {
  128. return
  129. }
  130. if c.items != nil {
  131. for key, _ := range c.items {
  132. c.checkRawExpiration(key)
  133. }
  134. }
  135. time.AfterFunc(time.Duration(c.interval)*time.Second, func() { c.startGC() })
  136. }
  137. // StartAndGC starts GC routine based on config string settings.
  138. func (c *MemoryCacher) StartAndGC(opt Options) error {
  139. c.lock.Lock()
  140. c.interval = opt.Interval
  141. c.lock.Unlock()
  142. go c.startGC()
  143. return nil
  144. }
  145. func init() {
  146. Register("memory", NewMemoryCacher())
  147. }