123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- package cache
- import (
- "log"
- "runtime"
- "sync"
- "time"
- )
- type CallCreate func(key interface{}) (value interface{}, created bool)
- type CallCreateNew func(key interface{}) (rKey, value interface{}, created bool)
- type CallCheck func(key, value interface{}, exists bool) (rKey, rValue interface{}, created bool)
- func NewMap(liveDuration time.Duration, maxSize int) *CacheMap {
- res := &CacheMap{&cacheMap{
- locker: new(sync.RWMutex),
- items: make(map[interface{}]*cacheMapItem),
- liveDuration: liveDuration,
- maxSize: maxSize,
- stopCleanerChan: make(chan byte),
- }}
- runtime.SetFinalizer(res, destroyCacheMap)
- return res
- }
- type CacheMap struct {
- *cacheMap
- }
- type cacheMapItem struct {
- value interface{}
- expire int64
- }
- type cacheMap struct {
- locker *sync.RWMutex
- items map[interface{}]*cacheMapItem
- liveDuration time.Duration
- maxSize int
- cleanerWork bool
- stopCleanerChan chan byte
- cleanedEventChan chan map[interface{}]interface{}
- }
- func (s *cacheMap) CleanEvent() (eventChan <-chan map[interface{}]interface{}) {
- s.locker.Lock()
- if s.cleanedEventChan == nil {
- s.cleanedEventChan = make(chan map[interface{}]interface{})
- }
- eventChan = s.cleanedEventChan
- s.locker.Unlock()
- return
- }
- func (s *cacheMap) runCleaner() {
- ticker := time.NewTicker(s.liveDuration / 2)
- for {
- log.Println("CLEANER")
- select {
- case <-ticker.C:
- {
- now := time.Now().UnixNano()
- s.locker.Lock()
- cleaned := make(map[interface{}]interface{})
- for key, val := range s.items {
- if now > val.expire {
- cleaned[key] = val.value
- delete(s.items, key)
- }
- }
- if len(cleaned) > 0 {
- select {
- case s.cleanedEventChan <- cleaned:
- default:
- }
- }
- if len(s.items) == 0 {
- s.cleanerWork = false
- ticker.Stop()
- s.locker.Unlock()
- return
- }
- s.locker.Unlock()
- }
- case <-s.stopCleanerChan:
- {
- s.cleanerWork = false
- ticker.Stop()
- return
- }
- }
- }
- }
- func (s *cacheMap) delete(key interface{}) {
- delete(s.items, key)
- if len(s.items) == 0 && s.cleanerWork {
- s.stopCleanerChan <- 0
- }
- }
- // Delete removes cached object
- func (s *cacheMap) Delete(key interface{}) {
- s.locker.Lock()
- s.delete(key)
- s.locker.Unlock()
- }
- func (s *cacheMap) set(key, value interface{}) {
- s.items[key] = &cacheMapItem{
- value: value,
- expire: time.Now().Add(s.liveDuration).UnixNano(),
- }
- if !s.cleanerWork {
- s.cleanerWork = true
- go s.runCleaner()
- }
- }
- func (s *cacheMap) Set(key, value interface{}) {
- s.locker.Lock()
- s.set(key, value)
- s.locker.Unlock()
- }
- func (s *cacheMap) SetMulti(m map[interface{}]interface{}) {
- s.locker.Lock()
- for key, val := range m {
- s.set(key, val)
- }
- s.locker.Unlock()
- }
- func (s *CacheMap) DeleteMulti(keys []interface{}) {
- s.locker.Lock()
- for _, key := range keys {
- delete(s.items, key)
- }
- s.locker.Unlock()
- }
- func (s *cacheMap) get(key interface{}) (res interface{}, check bool) {
- var item *cacheMapItem
- if item, check = s.items[key]; check {
- res = item.value
- }
- return
- }
- func (s *cacheMap) Get(key interface{}) (res interface{}, check bool) {
- s.locker.RLock()
- res, check = s.get(key)
- s.locker.RUnlock()
- return
- }
- func (s *cacheMap) GetCreate(key interface{}, mCreate CallCreate) (val interface{}, check bool) {
- if val, check = s.Get(key); !check {
- s.locker.Lock()
- if val, check = s.get(key); check {
- s.locker.Unlock()
- return
- }
- if val, check = mCreate(key); check {
- s.set(key, val)
- }
- s.locker.Unlock()
- }
- return
- }
- func (s *cacheMap) GetCreateNew(key interface{}, mCreateNew CallCreateNew) (rKey, val interface{}, check bool) {
- rKey = key
- if val, check = s.Get(key); !check {
- s.locker.Lock()
- if val, check = s.get(key); check {
- s.locker.Unlock()
- return
- }
- if rKey, val, check = mCreateNew(key); check {
- s.set(rKey, val)
- }
- s.locker.Unlock()
- }
- return
- }
- func (s *cacheMap) GetCheck(key interface{}, mCheck CallCheck) (res interface{}, check bool) {
- s.locker.Lock()
- res, check = s.get(key)
- if rKey, rVal, rCheck := mCheck(key, res, check); rCheck {
- s.set(rKey, rVal)
- key, res, check = rKey, rVal, true
- }
- s.locker.Unlock()
- return
- }
- // Each implements a map bypass for each key using the callback function. If the callback function returns false, then the cycle stops
- func (s *cacheMap) Each(callback func(interface{}, interface{}) bool) {
- s.locker.RLock()
- for key, val := range s.items {
- if !callback(key, val.value) {
- s.locker.RUnlock()
- return
- }
- }
- s.locker.RUnlock()
- }
- func (s *cacheMap) Len() (res int) {
- s.locker.RLock()
- res = len(s.items)
- s.locker.RUnlock()
- return
- }
- func (s *cacheMap) Keys() (res []interface{}) {
- s.locker.RLock()
- res = make([]interface{}, 0, len(s.items))
- for key := range s.items {
- res = append(res, key)
- }
- s.locker.RUnlock()
- return
- }
- func (s *cacheMap) Clear() {
- s.locker.Lock()
- s.items = make(map[interface{}]*cacheMapItem)
- s.locker.Unlock()
- }
- // for garbage collector
- func destroyCacheMap(m *CacheMap) {
- close(m.stopCleanerChan)
- if m.cleanedEventChan != nil {
- close(m.cleanedEventChan)
- }
- }
|