cache.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. package gcache
  2. import (
  3. "errors"
  4. "fmt"
  5. "sync"
  6. "time"
  7. )
  8. const (
  9. TYPE_SIMPLE = "simple"
  10. TYPE_LRU = "lru"
  11. TYPE_LFU = "lfu"
  12. TYPE_ARC = "arc"
  13. )
  14. var KeyNotFoundError = errors.New("Key not found.")
  15. type Cache interface {
  16. Set(interface{}, interface{}) error
  17. SetWithExpire(interface{}, interface{}, time.Duration) error
  18. Get(interface{}) (interface{}, error)
  19. GetIFPresent(interface{}) (interface{}, error)
  20. GetALL() map[interface{}]interface{}
  21. get(interface{}, bool) (interface{}, error)
  22. Remove(interface{}) bool
  23. Purge()
  24. Keys() []interface{}
  25. Len() int
  26. statsAccessor
  27. }
  28. type baseCache struct {
  29. clock Clock
  30. size int
  31. loaderExpireFunc LoaderExpireFunc
  32. evictedFunc EvictedFunc
  33. purgeVisitorFunc PurgeVisitorFunc
  34. addedFunc AddedFunc
  35. deserializeFunc DeserializeFunc
  36. serializeFunc SerializeFunc
  37. expiration *time.Duration
  38. mu sync.RWMutex
  39. loadGroup Group
  40. *stats
  41. }
  42. type (
  43. LoaderFunc func(interface{}) (interface{}, error)
  44. LoaderExpireFunc func(interface{}) (interface{}, *time.Duration, error)
  45. EvictedFunc func(interface{}, interface{})
  46. PurgeVisitorFunc func(interface{}, interface{})
  47. AddedFunc func(interface{}, interface{})
  48. DeserializeFunc func(interface{}, interface{}) (interface{}, error)
  49. SerializeFunc func(interface{}, interface{}) (interface{}, error)
  50. )
  51. type CacheBuilder struct {
  52. clock Clock
  53. tp string
  54. size int
  55. loaderExpireFunc LoaderExpireFunc
  56. evictedFunc EvictedFunc
  57. purgeVisitorFunc PurgeVisitorFunc
  58. addedFunc AddedFunc
  59. expiration *time.Duration
  60. deserializeFunc DeserializeFunc
  61. serializeFunc SerializeFunc
  62. }
  63. func New(size int) *CacheBuilder {
  64. return &CacheBuilder{
  65. clock: NewRealClock(),
  66. tp: TYPE_SIMPLE,
  67. size: size,
  68. }
  69. }
  70. func (cb *CacheBuilder) Clock(clock Clock) *CacheBuilder {
  71. cb.clock = clock
  72. return cb
  73. }
  74. // Set a loader function.
  75. // loaderFunc: create a new value with this function if cached value is expired.
  76. func (cb *CacheBuilder) LoaderFunc(loaderFunc LoaderFunc) *CacheBuilder {
  77. cb.loaderExpireFunc = func(k interface{}) (interface{}, *time.Duration, error) {
  78. v, err := loaderFunc(k)
  79. return v, nil, err
  80. }
  81. return cb
  82. }
  83. // Set a loader function with expiration.
  84. // loaderExpireFunc: create a new value with this function if cached value is expired.
  85. // If nil returned instead of time.Duration from loaderExpireFunc than value will never expire.
  86. func (cb *CacheBuilder) LoaderExpireFunc(loaderExpireFunc LoaderExpireFunc) *CacheBuilder {
  87. cb.loaderExpireFunc = loaderExpireFunc
  88. return cb
  89. }
  90. func (cb *CacheBuilder) EvictType(tp string) *CacheBuilder {
  91. cb.tp = tp
  92. return cb
  93. }
  94. func (cb *CacheBuilder) Simple() *CacheBuilder {
  95. return cb.EvictType(TYPE_SIMPLE)
  96. }
  97. func (cb *CacheBuilder) LRU() *CacheBuilder {
  98. return cb.EvictType(TYPE_LRU)
  99. }
  100. func (cb *CacheBuilder) LFU() *CacheBuilder {
  101. return cb.EvictType(TYPE_LFU)
  102. }
  103. func (cb *CacheBuilder) ARC() *CacheBuilder {
  104. return cb.EvictType(TYPE_ARC)
  105. }
  106. func (cb *CacheBuilder) EvictedFunc(evictedFunc EvictedFunc) *CacheBuilder {
  107. cb.evictedFunc = evictedFunc
  108. return cb
  109. }
  110. func (cb *CacheBuilder) PurgeVisitorFunc(purgeVisitorFunc PurgeVisitorFunc) *CacheBuilder {
  111. cb.purgeVisitorFunc = purgeVisitorFunc
  112. return cb
  113. }
  114. func (cb *CacheBuilder) AddedFunc(addedFunc AddedFunc) *CacheBuilder {
  115. cb.addedFunc = addedFunc
  116. return cb
  117. }
  118. func (cb *CacheBuilder) DeserializeFunc(deserializeFunc DeserializeFunc) *CacheBuilder {
  119. cb.deserializeFunc = deserializeFunc
  120. return cb
  121. }
  122. func (cb *CacheBuilder) SerializeFunc(serializeFunc SerializeFunc) *CacheBuilder {
  123. cb.serializeFunc = serializeFunc
  124. return cb
  125. }
  126. func (cb *CacheBuilder) Expiration(expiration time.Duration) *CacheBuilder {
  127. cb.expiration = &expiration
  128. return cb
  129. }
  130. func (cb *CacheBuilder) Build() Cache {
  131. if cb.size <= 0 && cb.tp != TYPE_SIMPLE {
  132. panic("gcache: Cache size <= 0")
  133. }
  134. return cb.build()
  135. }
  136. func (cb *CacheBuilder) build() Cache {
  137. switch cb.tp {
  138. case TYPE_SIMPLE:
  139. return newSimpleCache(cb)
  140. case TYPE_LRU:
  141. return newLRUCache(cb)
  142. case TYPE_LFU:
  143. return newLFUCache(cb)
  144. case TYPE_ARC:
  145. return newARC(cb)
  146. default:
  147. panic("gcache: Unknown type " + cb.tp)
  148. }
  149. }
  150. func buildCache(c *baseCache, cb *CacheBuilder) {
  151. c.clock = cb.clock
  152. c.size = cb.size
  153. c.loaderExpireFunc = cb.loaderExpireFunc
  154. c.expiration = cb.expiration
  155. c.addedFunc = cb.addedFunc
  156. c.deserializeFunc = cb.deserializeFunc
  157. c.serializeFunc = cb.serializeFunc
  158. c.evictedFunc = cb.evictedFunc
  159. c.purgeVisitorFunc = cb.purgeVisitorFunc
  160. c.stats = &stats{}
  161. }
  162. // load a new value using by specified key.
  163. func (c *baseCache) load(key interface{}, cb func(interface{}, *time.Duration, error) (interface{}, error), isWait bool) (interface{}, bool, error) {
  164. v, called, err := c.loadGroup.Do(key, func() (v interface{}, e error) {
  165. defer func() {
  166. if r := recover(); r != nil {
  167. e = fmt.Errorf("Loader panics: %v", r)
  168. }
  169. }()
  170. return cb(c.loaderExpireFunc(key))
  171. }, isWait)
  172. if err != nil {
  173. return nil, called, err
  174. }
  175. return v, called, nil
  176. }