arc.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. // Copyright (c) 2015 Hans Alexander Gugel <alexander.gugel@gmail.com>
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy
  4. // of this software and associated documentation files (the "Software"), to deal
  5. // in the Software without restriction, including without limitation the rights
  6. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. // copies of the Software, and to permit persons to whom the Software is
  8. // furnished to do so, subject to the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be included in all
  11. // copies or substantial portions of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  19. // SOFTWARE.
  20. // This file contains a modified version of package arc from
  21. // https://github.com/alexanderGugel/arc
  22. //
  23. // It implements the ARC (Adaptive Replacement Cache) algorithm as detailed in
  24. // https://www.usenix.org/legacy/event/fast03/tech/full_papers/megiddo/megiddo.pdf
  25. package trie
  26. import (
  27. "container/list"
  28. "sync"
  29. )
  30. type arc struct {
  31. p int
  32. c int
  33. t1 *list.List
  34. b1 *list.List
  35. t2 *list.List
  36. b2 *list.List
  37. cache map[string]*entry
  38. mutex sync.Mutex
  39. }
  40. type entry struct {
  41. key hashNode
  42. value node
  43. ll *list.List
  44. el *list.Element
  45. }
  46. // newARC returns a new Adaptive Replacement Cache with the
  47. // given capacity.
  48. func newARC(c int) *arc {
  49. return &arc{
  50. c: c,
  51. t1: list.New(),
  52. b1: list.New(),
  53. t2: list.New(),
  54. b2: list.New(),
  55. cache: make(map[string]*entry, c),
  56. }
  57. }
  58. // Clear clears the cache
  59. func (a *arc) Clear() {
  60. a.mutex.Lock()
  61. defer a.mutex.Unlock()
  62. a.p = 0
  63. a.t1 = list.New()
  64. a.b1 = list.New()
  65. a.t2 = list.New()
  66. a.b2 = list.New()
  67. a.cache = make(map[string]*entry, a.c)
  68. }
  69. // Put inserts a new key-value pair into the cache.
  70. // This optimizes future access to this entry (side effect).
  71. func (a *arc) Put(key hashNode, value node) bool {
  72. a.mutex.Lock()
  73. defer a.mutex.Unlock()
  74. ent, ok := a.cache[string(key)]
  75. if ok != true {
  76. ent = &entry{key: key, value: value}
  77. a.req(ent)
  78. a.cache[string(key)] = ent
  79. } else {
  80. ent.value = value
  81. a.req(ent)
  82. }
  83. return ok
  84. }
  85. // Get retrieves a previously via Set inserted entry.
  86. // This optimizes future access to this entry (side effect).
  87. func (a *arc) Get(key hashNode) (value node, ok bool) {
  88. a.mutex.Lock()
  89. defer a.mutex.Unlock()
  90. ent, ok := a.cache[string(key)]
  91. if ok {
  92. a.req(ent)
  93. return ent.value, ent.value != nil
  94. }
  95. return nil, false
  96. }
  97. func (a *arc) req(ent *entry) {
  98. if ent.ll == a.t1 || ent.ll == a.t2 {
  99. // Case I
  100. ent.setMRU(a.t2)
  101. } else if ent.ll == a.b1 {
  102. // Case II
  103. // Cache Miss in t1 and t2
  104. // Adaptation
  105. var d int
  106. if a.b1.Len() >= a.b2.Len() {
  107. d = 1
  108. } else {
  109. d = a.b2.Len() / a.b1.Len()
  110. }
  111. a.p = a.p + d
  112. if a.p > a.c {
  113. a.p = a.c
  114. }
  115. a.replace(ent)
  116. ent.setMRU(a.t2)
  117. } else if ent.ll == a.b2 {
  118. // Case III
  119. // Cache Miss in t1 and t2
  120. // Adaptation
  121. var d int
  122. if a.b2.Len() >= a.b1.Len() {
  123. d = 1
  124. } else {
  125. d = a.b1.Len() / a.b2.Len()
  126. }
  127. a.p = a.p - d
  128. if a.p < 0 {
  129. a.p = 0
  130. }
  131. a.replace(ent)
  132. ent.setMRU(a.t2)
  133. } else if ent.ll == nil {
  134. // Case IV
  135. if a.t1.Len()+a.b1.Len() == a.c {
  136. // Case A
  137. if a.t1.Len() < a.c {
  138. a.delLRU(a.b1)
  139. a.replace(ent)
  140. } else {
  141. a.delLRU(a.t1)
  142. }
  143. } else if a.t1.Len()+a.b1.Len() < a.c {
  144. // Case B
  145. if a.t1.Len()+a.t2.Len()+a.b1.Len()+a.b2.Len() >= a.c {
  146. if a.t1.Len()+a.t2.Len()+a.b1.Len()+a.b2.Len() == 2*a.c {
  147. a.delLRU(a.b2)
  148. }
  149. a.replace(ent)
  150. }
  151. }
  152. ent.setMRU(a.t1)
  153. }
  154. }
  155. func (a *arc) delLRU(list *list.List) {
  156. lru := list.Back()
  157. list.Remove(lru)
  158. delete(a.cache, string(lru.Value.(*entry).key))
  159. }
  160. func (a *arc) replace(ent *entry) {
  161. if a.t1.Len() > 0 && ((a.t1.Len() > a.p) || (ent.ll == a.b2 && a.t1.Len() == a.p)) {
  162. lru := a.t1.Back().Value.(*entry)
  163. lru.value = nil
  164. lru.setMRU(a.b1)
  165. } else {
  166. lru := a.t2.Back().Value.(*entry)
  167. lru.value = nil
  168. lru.setMRU(a.b2)
  169. }
  170. }
  171. func (e *entry) setLRU(list *list.List) {
  172. e.detach()
  173. e.ll = list
  174. e.el = e.ll.PushBack(e)
  175. }
  176. func (e *entry) setMRU(list *list.List) {
  177. e.detach()
  178. e.ll = list
  179. e.el = e.ll.PushFront(e)
  180. }
  181. func (e *entry) detach() {
  182. if e.ll != nil {
  183. e.ll.Remove(e.el)
  184. }
  185. }