arc.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  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. // Put inserts a new key-value pair into the cache.
  59. // This optimizes future access to this entry (side effect).
  60. func (a *arc) Put(key hashNode, value node) bool {
  61. a.mutex.Lock()
  62. defer a.mutex.Unlock()
  63. ent, ok := a.cache[string(key)]
  64. if ok != true {
  65. ent = &entry{key: key, value: value}
  66. a.req(ent)
  67. a.cache[string(key)] = ent
  68. } else {
  69. ent.value = value
  70. a.req(ent)
  71. }
  72. return ok
  73. }
  74. // Get retrieves a previously via Set inserted entry.
  75. // This optimizes future access to this entry (side effect).
  76. func (a *arc) Get(key hashNode) (value node, ok bool) {
  77. a.mutex.Lock()
  78. defer a.mutex.Unlock()
  79. ent, ok := a.cache[string(key)]
  80. if ok {
  81. a.req(ent)
  82. return ent.value, ent.value != nil
  83. }
  84. return nil, false
  85. }
  86. func (a *arc) req(ent *entry) {
  87. if ent.ll == a.t1 || ent.ll == a.t2 {
  88. // Case I
  89. ent.setMRU(a.t2)
  90. } else if ent.ll == a.b1 {
  91. // Case II
  92. // Cache Miss in t1 and t2
  93. // Adaptation
  94. var d int
  95. if a.b1.Len() >= a.b2.Len() {
  96. d = 1
  97. } else {
  98. d = a.b2.Len() / a.b1.Len()
  99. }
  100. a.p = a.p + d
  101. if a.p > a.c {
  102. a.p = a.c
  103. }
  104. a.replace(ent)
  105. ent.setMRU(a.t2)
  106. } else if ent.ll == a.b2 {
  107. // Case III
  108. // Cache Miss in t1 and t2
  109. // Adaptation
  110. var d int
  111. if a.b2.Len() >= a.b1.Len() {
  112. d = 1
  113. } else {
  114. d = a.b1.Len() / a.b2.Len()
  115. }
  116. a.p = a.p - d
  117. if a.p < 0 {
  118. a.p = 0
  119. }
  120. a.replace(ent)
  121. ent.setMRU(a.t2)
  122. } else if ent.ll == nil {
  123. // Case IV
  124. if a.t1.Len()+a.b1.Len() == a.c {
  125. // Case A
  126. if a.t1.Len() < a.c {
  127. a.delLRU(a.b1)
  128. a.replace(ent)
  129. } else {
  130. a.delLRU(a.t1)
  131. }
  132. } else if a.t1.Len()+a.b1.Len() < a.c {
  133. // Case B
  134. if a.t1.Len()+a.t2.Len()+a.b1.Len()+a.b2.Len() >= a.c {
  135. if a.t1.Len()+a.t2.Len()+a.b1.Len()+a.b2.Len() == 2*a.c {
  136. a.delLRU(a.b2)
  137. }
  138. a.replace(ent)
  139. }
  140. }
  141. ent.setMRU(a.t1)
  142. }
  143. }
  144. func (a *arc) delLRU(list *list.List) {
  145. lru := list.Back()
  146. list.Remove(lru)
  147. delete(a.cache, string(lru.Value.(*entry).key))
  148. }
  149. func (a *arc) replace(ent *entry) {
  150. if a.t1.Len() > 0 && ((a.t1.Len() > a.p) || (ent.ll == a.b2 && a.t1.Len() == a.p)) {
  151. lru := a.t1.Back().Value.(*entry)
  152. lru.value = nil
  153. lru.setMRU(a.b1)
  154. } else {
  155. lru := a.t2.Back().Value.(*entry)
  156. lru.value = nil
  157. lru.setMRU(a.b2)
  158. }
  159. }
  160. func (e *entry) setLRU(list *list.List) {
  161. e.detach()
  162. e.ll = list
  163. e.el = e.ll.PushBack(e)
  164. }
  165. func (e *entry) setMRU(list *list.List) {
  166. e.detach()
  167. e.ll = list
  168. e.el = e.ll.PushFront(e)
  169. }
  170. func (e *entry) detach() {
  171. if e.ll != nil {
  172. e.ll.Remove(e.el)
  173. }
  174. }