github.com/keysonzzz/kmg@v0.0.0-20151121023212-05317bfd7d39/kmgCache/MemoryTtlCacheV2.go (about) 1 package kmgCache 2 3 import ( 4 "sync" 5 "time" 6 7 "github.com/golang/groupcache/singleflight" 8 ) 9 10 //请调用 NewTtlCache() 初始化 11 type MemoryTtlCacheV2 struct { 12 cache map[string]ttlCacheEntry 13 lock sync.RWMutex 14 singleGroup singleflight.Group 15 } 16 17 // TODO 写一个close,以便可以关闭缓存 18 func NewMemoryTtlCacheV2() *MemoryTtlCacheV2 { 19 c := &MemoryTtlCacheV2{ 20 cache: map[string]ttlCacheEntry{}, 21 } 22 go c.GcThread() 23 return c 24 } 25 26 // Ttl 内存缓存实现第二版 27 // 1.使用key表示不同的项 28 // 2.f 返回err 表示本次无法获取到信息,该err会被返回给调用者,并且此时调用者的value是nil 29 // 3.使用singleGroup避免大量请求同时访问某个一个key 30 func (s *MemoryTtlCacheV2) Do(key string, f func() (value interface{}, ttl time.Duration, err error)) (value interface{}, err error) { 31 entry, err := s.get(key) 32 if err == nil { 33 return entry.Value, nil 34 } 35 if err != CacheMiss { 36 return 37 } 38 entryi, err := s.singleGroup.Do(key, func() (interface{}, error) { 39 value, ttl, err := f() 40 return ttlCacheEntry{ 41 Value: value, 42 Timeout: time.Now().Add(ttl), 43 }, err 44 }) 45 if err != nil { 46 return nil, err 47 } 48 entry = entryi.(ttlCacheEntry) 49 s.save(key, entry) 50 return entry.Value, nil 51 } 52 53 func (s *MemoryTtlCacheV2) save(key string, entry ttlCacheEntry) { 54 s.lock.Lock() 55 defer s.lock.Unlock() 56 s.cache[key] = entry 57 return 58 } 59 60 func (s *MemoryTtlCacheV2) get(key string) (entry ttlCacheEntry, err error) { 61 s.lock.RLock() 62 defer s.lock.RUnlock() 63 now := time.Now() 64 entry, ok := s.cache[key] 65 if !ok { 66 return entry, CacheMiss 67 } 68 if now.After(entry.Timeout) { 69 return entry, CacheMiss 70 } 71 return entry, nil 72 } 73 74 //要有个进程在一边进行gc,避免内存泄漏 75 func (s *MemoryTtlCacheV2) GcThread() { 76 for { 77 time.Sleep(time.Hour) 78 s.lock.Lock() 79 now := time.Now() 80 for key, entry := range s.cache { 81 if now.After(entry.Timeout) { 82 delete(s.cache, key) 83 } 84 } 85 s.lock.Unlock() 86 } 87 }