cachemap.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. package cache
  2. import (
  3. "context"
  4. "sync"
  5. "time"
  6. )
  7. const (
  8. LiveInfinite = time.Duration(-1)
  9. )
  10. type CallCreate func(key any) (value any, created bool)
  11. type CallCreateNew func(key any) (rKey, value any, created bool)
  12. type CallCheck func(key, value any, exists bool) (rKey, rValue any, created bool)
  13. type item struct {
  14. value any
  15. expire int64
  16. }
  17. func NewCacheMap(ctx context.Context, maxSize int, live time.Duration) *CacheMap {
  18. cctx, cancel := context.WithCancel(ctx)
  19. res := &CacheMap{
  20. ctx: cctx,
  21. cancel: cancel,
  22. items: make(map[any]*item),
  23. mi: new(sync.RWMutex),
  24. live: live,
  25. maxSize: maxSize,
  26. mc: new(sync.RWMutex),
  27. }
  28. // todo - clean worker
  29. return res
  30. }
  31. type CacheMap struct {
  32. finished bool
  33. ctx context.Context
  34. cancel context.CancelFunc
  35. items map[any]*item
  36. mi *sync.RWMutex
  37. live time.Duration
  38. maxSize int
  39. cleanChans []chan map[any]any
  40. mc *sync.RWMutex
  41. }
  42. func (s *CacheMap) IsFinished() bool {
  43. return s.finished
  44. }
  45. func (s *CacheMap) close() {
  46. s.finished = true
  47. s.mc.Lock()
  48. for _, ch := range s.cleanChans {
  49. close(ch)
  50. }
  51. s.cleanChans = nil
  52. s.mc.Unlock()
  53. }
  54. func (s *CacheMap) eventClean(m map[any]any) {
  55. s.mc.RLock()
  56. for _, ch := range s.cleanChans {
  57. select {
  58. case ch <- m:
  59. default:
  60. }
  61. }
  62. s.mc.RUnlock()
  63. }
  64. func (s *CacheMap) EventCleaner() <-chan map[any]any {
  65. s.mc.Lock()
  66. ech := make(chan map[any]any, 1)
  67. s.cleanChans = append(s.cleanChans, ech)
  68. s.mc.Unlock()
  69. return ech
  70. }
  71. func (s *CacheMap) cleanWorker() {
  72. defer func() {
  73. for _, v := range s.cleanChans {
  74. close(v)
  75. }
  76. }()
  77. t := time.NewTicker(s.live)
  78. loop:
  79. for {
  80. select {
  81. case <-t.C:
  82. // clean items
  83. nowTS := time.Now().Unix()
  84. m := make(map[any]any)
  85. s.mi.Lock()
  86. for key, item := range s.items {
  87. if item.expire < nowTS {
  88. delete(s.items, key)
  89. m[key] = item.value
  90. }
  91. }
  92. s.mi.Unlock()
  93. if len(m) > 0 {
  94. s.eventClean(m)
  95. }
  96. case <-s.ctx.Done():
  97. break loop
  98. }
  99. }
  100. }
  101. func (s *CacheMap) delete(key any) {
  102. delete(s.items, key)
  103. }
  104. // Delete removes cached object
  105. func (s *CacheMap) Delete(key any) {
  106. s.mi.Lock()
  107. s.delete(key)
  108. s.mi.Unlock()
  109. }
  110. func (s *CacheMap) set(key, value any) {
  111. s.items[key] = &item{
  112. value: value,
  113. expire: time.Now().Add(s.live).UnixNano(),
  114. }
  115. }
  116. func (s *CacheMap) keysOlder(count int) []any {
  117. if count > len(s.items) {
  118. count = len(s.items)
  119. }
  120. last, llast := time.Now().Unix(), int64(-1)
  121. res := make([]any, 0, count)
  122. for len(res) < count {
  123. var rKey any
  124. ltmp := last
  125. for key, val := range s.items {
  126. if val.expire < ltmp && val.expire > llast {
  127. rKey = key
  128. ltmp = val.expire
  129. }
  130. }
  131. res = append(res, rKey)
  132. llast = ltmp
  133. }
  134. return res
  135. }
  136. func (s *CacheMap) Set(key, value any) {
  137. s.mi.Lock()
  138. if s.maxSize > 0 && len(s.items) == s.maxSize {
  139. // remove first
  140. for key, val := range s.items {
  141. delete(s.items, key)
  142. s.eventClean(map[any]any{
  143. key: val.value,
  144. })
  145. break
  146. }
  147. }
  148. s.set(key, value)
  149. s.mi.Unlock()
  150. }
  151. func (s *CacheMap) SetMulti(m map[any]any) {
  152. s.mi.Lock()
  153. /*
  154. if s.maxSize > 0 && len(s.items)+len(m) > s.maxSize {
  155. // remove first
  156. for key, val := range s.items {
  157. delete(s.items, key)
  158. s.eventClean(map[any]any{
  159. key: val.value,
  160. })
  161. break
  162. }
  163. }
  164. */
  165. for key, val := range m {
  166. s.set(key, val)
  167. }
  168. s.mi.Unlock()
  169. }
  170. func (s *CacheMap) DeleteMulti(keys []any) {
  171. s.mi.Lock()
  172. for _, key := range keys {
  173. delete(s.items, key)
  174. }
  175. s.mi.Unlock()
  176. }
  177. func (s *CacheMap) get(key any) (res any, check bool) {
  178. var it *item
  179. if it, check = s.items[key]; check {
  180. res = it.value
  181. }
  182. return
  183. }
  184. func (s *CacheMap) Get(key any) (res any, check bool) {
  185. s.mi.RLock()
  186. res, check = s.get(key)
  187. s.mi.RUnlock()
  188. return
  189. }
  190. func (s *CacheMap) GetCreate(key any, mCreate CallCreate) (val any, check bool) {
  191. if val, check = s.Get(key); !check {
  192. s.mi.Lock()
  193. defer s.mi.Unlock()
  194. if val, check = s.get(key); check {
  195. return
  196. }
  197. if val, check = mCreate(key); check {
  198. s.set(key, val)
  199. }
  200. }
  201. return
  202. }
  203. func (s *CacheMap) GetCreateNew(key any, mCreateNew CallCreateNew) (rKey, val any, check bool) {
  204. rKey = key
  205. if val, check = s.Get(key); !check {
  206. s.mi.Lock()
  207. defer s.mi.Unlock()
  208. if val, check = s.get(key); check {
  209. return
  210. }
  211. if rKey, val, check = mCreateNew(key); check {
  212. s.set(rKey, val)
  213. }
  214. }
  215. return
  216. }
  217. func (s *CacheMap) GetCheck(key any, mCheck CallCheck) (res any, check bool) {
  218. s.mi.Lock()
  219. res, check = s.get(key)
  220. if rKey, rVal, rCheck := mCheck(key, res, check); rCheck {
  221. s.set(rKey, rVal)
  222. key, res, check = rKey, rVal, true
  223. }
  224. s.mi.Unlock()
  225. return
  226. }
  227. // Each implements a map bypass for each key using the callback function. If the callback function returns false, then the cycle stops
  228. func (s *CacheMap) Each(callback func(any, any) bool) {
  229. s.mi.RLock()
  230. defer s.mi.RUnlock()
  231. for key, val := range s.items {
  232. if !callback(key, val.value) {
  233. return
  234. }
  235. }
  236. }
  237. func (s CacheMap) Len() (res int) {
  238. s.mi.RLock()
  239. res = len(s.items)
  240. s.mi.RUnlock()
  241. return
  242. }
  243. func (s *CacheMap) Keys() (res []any) {
  244. s.mi.RLock()
  245. res = make([]any, 0, len(s.items))
  246. for key := range s.items {
  247. res = append(res, key)
  248. }
  249. s.mi.RUnlock()
  250. return
  251. }
  252. func (s *CacheMap) Clear() {
  253. s.mi.Lock()
  254. s.items = make(map[any]*item)
  255. s.mi.Unlock()
  256. }