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.

289 lines
7.1 KiB

  1. // Copyright 2015 The Xorm Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package xorm
  5. import (
  6. "container/list"
  7. "fmt"
  8. "sync"
  9. "time"
  10. "github.com/go-xorm/core"
  11. )
  12. type LRUCacher struct {
  13. idList *list.List
  14. sqlList *list.List
  15. idIndex map[string]map[string]*list.Element
  16. sqlIndex map[string]map[string]*list.Element
  17. store core.CacheStore
  18. mutex sync.Mutex
  19. // maxSize int
  20. MaxElementSize int
  21. Expired time.Duration
  22. GcInterval time.Duration
  23. }
  24. func NewLRUCacher(store core.CacheStore, maxElementSize int) *LRUCacher {
  25. return NewLRUCacher2(store, 3600*time.Second, maxElementSize)
  26. }
  27. func NewLRUCacher2(store core.CacheStore, expired time.Duration, maxElementSize int) *LRUCacher {
  28. cacher := &LRUCacher{store: store, idList: list.New(),
  29. sqlList: list.New(), Expired: expired,
  30. GcInterval: core.CacheGcInterval, MaxElementSize: maxElementSize,
  31. sqlIndex: make(map[string]map[string]*list.Element),
  32. idIndex: make(map[string]map[string]*list.Element),
  33. }
  34. cacher.RunGC()
  35. return cacher
  36. }
  37. //func NewLRUCacher3(store CacheStore, expired time.Duration, maxSize int) *LRUCacher {
  38. // return newLRUCacher(store, expired, maxSize, 0)
  39. //}
  40. // RunGC run once every m.GcInterval
  41. func (m *LRUCacher) RunGC() {
  42. time.AfterFunc(m.GcInterval, func() {
  43. m.RunGC()
  44. m.GC()
  45. })
  46. }
  47. // GC check ids lit and sql list to remove all element expired
  48. func (m *LRUCacher) GC() {
  49. //fmt.Println("begin gc ...")
  50. //defer fmt.Println("end gc ...")
  51. m.mutex.Lock()
  52. defer m.mutex.Unlock()
  53. var removedNum int
  54. for e := m.idList.Front(); e != nil; {
  55. if removedNum <= core.CacheGcMaxRemoved &&
  56. time.Now().Sub(e.Value.(*idNode).lastVisit) > m.Expired {
  57. removedNum++
  58. next := e.Next()
  59. //fmt.Println("removing ...", e.Value)
  60. node := e.Value.(*idNode)
  61. m.delBean(node.tbName, node.id)
  62. e = next
  63. } else {
  64. //fmt.Printf("removing %d cache nodes ..., left %d\n", removedNum, m.idList.Len())
  65. break
  66. }
  67. }
  68. removedNum = 0
  69. for e := m.sqlList.Front(); e != nil; {
  70. if removedNum <= core.CacheGcMaxRemoved &&
  71. time.Now().Sub(e.Value.(*sqlNode).lastVisit) > m.Expired {
  72. removedNum++
  73. next := e.Next()
  74. //fmt.Println("removing ...", e.Value)
  75. node := e.Value.(*sqlNode)
  76. m.delIds(node.tbName, node.sql)
  77. e = next
  78. } else {
  79. //fmt.Printf("removing %d cache nodes ..., left %d\n", removedNum, m.sqlList.Len())
  80. break
  81. }
  82. }
  83. }
  84. // GetIds returns all bean's ids according to sql and parameter from cache
  85. func (m *LRUCacher) GetIds(tableName, sql string) interface{} {
  86. m.mutex.Lock()
  87. defer m.mutex.Unlock()
  88. if _, ok := m.sqlIndex[tableName]; !ok {
  89. m.sqlIndex[tableName] = make(map[string]*list.Element)
  90. }
  91. if v, err := m.store.Get(sql); err == nil {
  92. if el, ok := m.sqlIndex[tableName][sql]; !ok {
  93. el = m.sqlList.PushBack(newSqlNode(tableName, sql))
  94. m.sqlIndex[tableName][sql] = el
  95. } else {
  96. lastTime := el.Value.(*sqlNode).lastVisit
  97. // if expired, remove the node and return nil
  98. if time.Now().Sub(lastTime) > m.Expired {
  99. m.delIds(tableName, sql)
  100. return nil
  101. }
  102. m.sqlList.MoveToBack(el)
  103. el.Value.(*sqlNode).lastVisit = time.Now()
  104. }
  105. return v
  106. } else {
  107. m.delIds(tableName, sql)
  108. }
  109. return nil
  110. }
  111. // GetBean returns bean according tableName and id from cache
  112. func (m *LRUCacher) GetBean(tableName string, id string) interface{} {
  113. m.mutex.Lock()
  114. defer m.mutex.Unlock()
  115. if _, ok := m.idIndex[tableName]; !ok {
  116. m.idIndex[tableName] = make(map[string]*list.Element)
  117. }
  118. tid := genId(tableName, id)
  119. if v, err := m.store.Get(tid); err == nil {
  120. if el, ok := m.idIndex[tableName][id]; ok {
  121. lastTime := el.Value.(*idNode).lastVisit
  122. // if expired, remove the node and return nil
  123. if time.Now().Sub(lastTime) > m.Expired {
  124. m.delBean(tableName, id)
  125. //m.clearIds(tableName)
  126. return nil
  127. }
  128. m.idList.MoveToBack(el)
  129. el.Value.(*idNode).lastVisit = time.Now()
  130. } else {
  131. el = m.idList.PushBack(newIdNode(tableName, id))
  132. m.idIndex[tableName][id] = el
  133. }
  134. return v
  135. } else {
  136. // store bean is not exist, then remove memory's index
  137. m.delBean(tableName, id)
  138. //m.clearIds(tableName)
  139. return nil
  140. }
  141. }
  142. // Clear all sql-ids mapping on table tableName from cache
  143. func (m *LRUCacher) clearIds(tableName string) {
  144. if tis, ok := m.sqlIndex[tableName]; ok {
  145. for sql, v := range tis {
  146. m.sqlList.Remove(v)
  147. m.store.Del(sql)
  148. }
  149. }
  150. m.sqlIndex[tableName] = make(map[string]*list.Element)
  151. }
  152. func (m *LRUCacher) ClearIds(tableName string) {
  153. m.mutex.Lock()
  154. defer m.mutex.Unlock()
  155. m.clearIds(tableName)
  156. }
  157. func (m *LRUCacher) clearBeans(tableName string) {
  158. if tis, ok := m.idIndex[tableName]; ok {
  159. for id, v := range tis {
  160. m.idList.Remove(v)
  161. tid := genId(tableName, id)
  162. m.store.Del(tid)
  163. }
  164. }
  165. m.idIndex[tableName] = make(map[string]*list.Element)
  166. }
  167. func (m *LRUCacher) ClearBeans(tableName string) {
  168. m.mutex.Lock()
  169. defer m.mutex.Unlock()
  170. m.clearBeans(tableName)
  171. }
  172. func (m *LRUCacher) PutIds(tableName, sql string, ids interface{}) {
  173. m.mutex.Lock()
  174. defer m.mutex.Unlock()
  175. if _, ok := m.sqlIndex[tableName]; !ok {
  176. m.sqlIndex[tableName] = make(map[string]*list.Element)
  177. }
  178. if el, ok := m.sqlIndex[tableName][sql]; !ok {
  179. el = m.sqlList.PushBack(newSqlNode(tableName, sql))
  180. m.sqlIndex[tableName][sql] = el
  181. } else {
  182. el.Value.(*sqlNode).lastVisit = time.Now()
  183. }
  184. m.store.Put(sql, ids)
  185. if m.sqlList.Len() > m.MaxElementSize {
  186. e := m.sqlList.Front()
  187. node := e.Value.(*sqlNode)
  188. m.delIds(node.tbName, node.sql)
  189. }
  190. }
  191. func (m *LRUCacher) PutBean(tableName string, id string, obj interface{}) {
  192. m.mutex.Lock()
  193. defer m.mutex.Unlock()
  194. var el *list.Element
  195. var ok bool
  196. if el, ok = m.idIndex[tableName][id]; !ok {
  197. el = m.idList.PushBack(newIdNode(tableName, id))
  198. m.idIndex[tableName][id] = el
  199. } else {
  200. el.Value.(*idNode).lastVisit = time.Now()
  201. }
  202. m.store.Put(genId(tableName, id), obj)
  203. if m.idList.Len() > m.MaxElementSize {
  204. e := m.idList.Front()
  205. node := e.Value.(*idNode)
  206. m.delBean(node.tbName, node.id)
  207. }
  208. }
  209. func (m *LRUCacher) delIds(tableName, sql string) {
  210. if _, ok := m.sqlIndex[tableName]; ok {
  211. if el, ok := m.sqlIndex[tableName][sql]; ok {
  212. delete(m.sqlIndex[tableName], sql)
  213. m.sqlList.Remove(el)
  214. }
  215. }
  216. m.store.Del(sql)
  217. }
  218. func (m *LRUCacher) DelIds(tableName, sql string) {
  219. m.mutex.Lock()
  220. defer m.mutex.Unlock()
  221. m.delIds(tableName, sql)
  222. }
  223. func (m *LRUCacher) delBean(tableName string, id string) {
  224. tid := genId(tableName, id)
  225. if el, ok := m.idIndex[tableName][id]; ok {
  226. delete(m.idIndex[tableName], id)
  227. m.idList.Remove(el)
  228. m.clearIds(tableName)
  229. }
  230. m.store.Del(tid)
  231. }
  232. func (m *LRUCacher) DelBean(tableName string, id string) {
  233. m.mutex.Lock()
  234. defer m.mutex.Unlock()
  235. m.delBean(tableName, id)
  236. }
  237. type idNode struct {
  238. tbName string
  239. id string
  240. lastVisit time.Time
  241. }
  242. type sqlNode struct {
  243. tbName string
  244. sql string
  245. lastVisit time.Time
  246. }
  247. func genSqlKey(sql string, args interface{}) string {
  248. return fmt.Sprintf("%v-%v", sql, args)
  249. }
  250. func genId(prefix string, id string) string {
  251. return fmt.Sprintf("%v-%v", prefix, id)
  252. }
  253. func newIdNode(tbName string, id string) *idNode {
  254. return &idNode{tbName, id, time.Now()}
  255. }
  256. func newSqlNode(tbName, sql string) *sqlNode {
  257. return &sqlNode{tbName, sql, time.Now()}
  258. }