policy.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. package cache
  2. import (
  3. "container/list"
  4. "sync"
  5. "sync/atomic"
  6. )
  7. const (
  8. // Number of cache data store will be 2 ^ concurrencyLevel.
  9. concurrencyLevel = 2
  10. segmentCount = 1 << concurrencyLevel
  11. segmentMask = segmentCount - 1
  12. )
  13. // entry stores cached entry key and value.
  14. type entry struct {
  15. // Structs with first field align to 64 bits will also be aligned to 64.
  16. // https://golang.org/pkg/sync/atomic/#pkg-note-BUG
  17. // hash is the hash value of this entry key
  18. hash uint64
  19. // accessTime is the last time this entry was accessed.
  20. accessTime int64 // Access atomically - must be aligned on 32-bit
  21. // writeTime is the last time this entry was updated.
  22. writeTime int64 // Access atomically - must be aligned on 32-bit
  23. // FIXME: More efficient way to store boolean flags
  24. invalidated int32
  25. loading int32
  26. key Key
  27. value atomic.Value // Store value
  28. // These properties are managed by only cache policy so do not need atomic access.
  29. // accessList is the list (ordered by access time) this entry is currently in.
  30. accessList *list.Element
  31. // writeList is the list (ordered by write time) this entry is currently in.
  32. writeList *list.Element
  33. // listID is ID of the list which this entry is currently in.
  34. listID uint8
  35. }
  36. func newEntry(k Key, v Value, h uint64) *entry {
  37. en := &entry{
  38. key: k,
  39. hash: h,
  40. }
  41. en.setValue(v)
  42. return en
  43. }
  44. func (e *entry) getValue() Value {
  45. return e.value.Load().(Value)
  46. }
  47. func (e *entry) setValue(v Value) {
  48. e.value.Store(v)
  49. }
  50. func (e *entry) getAccessTime() int64 {
  51. return atomic.LoadInt64(&e.accessTime)
  52. }
  53. func (e *entry) setAccessTime(v int64) {
  54. atomic.StoreInt64(&e.accessTime, v)
  55. }
  56. func (e *entry) getWriteTime() int64 {
  57. return atomic.LoadInt64(&e.writeTime)
  58. }
  59. func (e *entry) setWriteTime(v int64) {
  60. atomic.StoreInt64(&e.writeTime, v)
  61. }
  62. func (e *entry) getLoading() bool {
  63. return atomic.LoadInt32(&e.loading) != 0
  64. }
  65. func (e *entry) setLoading(v bool) bool {
  66. if v {
  67. return atomic.CompareAndSwapInt32(&e.loading, 0, 1)
  68. }
  69. return atomic.CompareAndSwapInt32(&e.loading, 1, 0)
  70. }
  71. func (e *entry) getInvalidated() bool {
  72. return atomic.LoadInt32(&e.invalidated) != 0
  73. }
  74. func (e *entry) setInvalidated(v bool) {
  75. if v {
  76. atomic.StoreInt32(&e.invalidated, 1)
  77. } else {
  78. atomic.StoreInt32(&e.invalidated, 0)
  79. }
  80. }
  81. // getEntry returns the entry attached to the given list element.
  82. func getEntry(el *list.Element) *entry {
  83. return el.Value.(*entry)
  84. }
  85. // event is the cache event (add, hit or delete).
  86. type event uint8
  87. const (
  88. eventWrite event = iota
  89. eventAccess
  90. eventDelete
  91. eventClose
  92. )
  93. type entryEvent struct {
  94. entry *entry
  95. event event
  96. }
  97. // cache is a data structure for cache entries.
  98. type cache struct {
  99. size int64 // Access atomically - must be aligned on 32-bit
  100. segs [segmentCount]sync.Map // map[Key]*entry
  101. }
  102. func (c *cache) get(k Key, h uint64) *entry {
  103. seg := c.segment(h)
  104. v, ok := seg.Load(k)
  105. if ok {
  106. return v.(*entry)
  107. }
  108. return nil
  109. }
  110. func (c *cache) getOrSet(v *entry) *entry {
  111. seg := c.segment(v.hash)
  112. en, ok := seg.LoadOrStore(v.key, v)
  113. if ok {
  114. return en.(*entry)
  115. }
  116. atomic.AddInt64(&c.size, 1)
  117. return nil
  118. }
  119. func (c *cache) delete(v *entry) {
  120. seg := c.segment(v.hash)
  121. seg.Delete(v.key)
  122. atomic.AddInt64(&c.size, -1)
  123. }
  124. func (c *cache) len() int {
  125. return int(atomic.LoadInt64(&c.size))
  126. }
  127. func (c *cache) walk(fn func(*entry)) {
  128. for i := range c.segs {
  129. c.segs[i].Range(func(k, v interface{}) bool {
  130. fn(v.(*entry))
  131. return true
  132. })
  133. }
  134. }
  135. func (c *cache) segment(h uint64) *sync.Map {
  136. return &c.segs[h&segmentMask]
  137. }
  138. // policy is a cache policy.
  139. type policy interface {
  140. // init initializes the policy.
  141. init(cache *cache, maximumSize int)
  142. // write handles Write event for the entry.
  143. // It adds new entry and returns evicted entry if needed.
  144. write(entry *entry) *entry
  145. // access handles Access event for the entry.
  146. // It marks then entry recently accessed.
  147. access(entry *entry)
  148. // remove removes the entry.
  149. remove(entry *entry) *entry
  150. // iterate iterates all entries by their access time.
  151. iterate(func(entry *entry) bool)
  152. }
  153. func newPolicy(name string) policy {
  154. switch name {
  155. case "", "slru":
  156. return &slruCache{}
  157. case "lru":
  158. return &lruCache{}
  159. case "tinylfu":
  160. return &tinyLFU{}
  161. default:
  162. panic("cache: unsupported policy " + name)
  163. }
  164. }
  165. // recencyQueue manages cache entries by write time.
  166. type recencyQueue struct {
  167. ls list.List
  168. }
  169. func (w *recencyQueue) init(cache *cache, maximumSize int) {
  170. w.ls.Init()
  171. }
  172. func (w *recencyQueue) write(en *entry) *entry {
  173. if en.writeList == nil {
  174. en.writeList = w.ls.PushFront(en)
  175. } else {
  176. w.ls.MoveToFront(en.writeList)
  177. }
  178. return nil
  179. }
  180. func (w *recencyQueue) access(en *entry) {
  181. }
  182. func (w *recencyQueue) remove(en *entry) *entry {
  183. if en.writeList == nil {
  184. return en
  185. }
  186. w.ls.Remove(en.writeList)
  187. en.writeList = nil
  188. return en
  189. }
  190. func (w *recencyQueue) iterate(fn func(en *entry) bool) {
  191. iterateListFromBack(&w.ls, fn)
  192. }
  193. type discardingQueue struct{}
  194. func (discardingQueue) init(cache *cache, maximumSize int) {
  195. }
  196. func (discardingQueue) write(en *entry) *entry {
  197. return nil
  198. }
  199. func (discardingQueue) access(en *entry) {
  200. }
  201. func (discardingQueue) remove(en *entry) *entry {
  202. return en
  203. }
  204. func (discardingQueue) iterate(fn func(en *entry) bool) {
  205. }
  206. func iterateListFromBack(ls *list.List, fn func(en *entry) bool) {
  207. for el := ls.Back(); el != nil; {
  208. en := getEntry(el)
  209. prev := el.Prev() // Get Prev as fn can delete the entry.
  210. if !fn(en) {
  211. return
  212. }
  213. el = prev
  214. }
  215. }