1 Star 0 Fork 8

哈哈哈/wego
暂停

forked from kzquu/wego 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
memorycache.go 3.19 KB
一键复制 编辑 原始数据 按行查看 历史
kzquu 提交于 2020-08-20 22:09 +08:00 . 0
package memorycache
import (
"runtime"
"sync"
"sync/atomic"
"time"
)
var (
all = make(map[*Cache]*Cache)
alllock = new(sync.Mutex)
)
// New New
func New() (c *Cache) {
c = &Cache{new(sync.RWMutex), 0, make(map[interface{}]*item, 5)}
alllock.Lock()
all[c] = c
alllock.Unlock()
return
}
// Delete New()生成的Cache要Delete()才能彻底删除
func Delete(c *Cache) {
alllock.Lock()
delete(all, c)
alllock.Unlock()
}
// GC 清理过期的数据,需要手动调用,比如放到定时任务中
// 如果数据总量不多,建议懒得GC
func GC() {
now := time.Now().Unix()
alllock.Lock()
for _, c := range all {
c.rw.Lock()
for k, it := range c.items {
it.rw.RLock()
if it.expire == 0 || it.expire > now { // 未过期
} else {
delete(c.items, k)
}
it.rw.RUnlock()
}
c.rw.Unlock()
}
alllock.Unlock()
}
// Cache 缓存
type Cache struct {
rw *sync.RWMutex
flag int32 // 标识,是否有goroutine占用数据
items map[interface{}]*item
}
type item struct {
rw *sync.RWMutex
flag int32 // 标识,是否有goroutine占用数据
data interface{} // 数据
expire int64 // 过期时间戳
}
func (c *Cache) get(key interface{}) (it *item) {
c.rw.RLock()
it = c.items[key]
c.rw.RUnlock()
return
}
// Get 取缓存数据,如果不存在或过期就用 f() 创建
// t: 有效时间,0永不过期,单位秒
func (c *Cache) Get(key interface{},
f ...func(key, old interface{}) (v interface{}, t int64)) (v interface{}) {
now := time.Now().Unix()
var it *item
A:
it = c.get(key)
if it != nil {
B:
it.rw.RLock()
if it.expire == 0 || it.expire > now { // 未过期
v = it.data
it.rw.RUnlock()
return
}
it.rw.RUnlock()
if len(f) == 0 || f[0] == nil {
return
}
if atomic.CompareAndSwapInt32(&it.flag, 0, 1) {
it.rw.Lock()
it.data, it.expire = f[0](key, it.data)
if it.expire > 0 {
it.expire += now
}
it.flag = 0
v = it.data
it.rw.Unlock()
return
}
runtime.Gosched()
goto B
}
// 不传入f就返回nil
if len(f) == 0 || f[0] == nil {
return
}
// 需要生成数据
if atomic.CompareAndSwapInt32(&c.flag, 0, 1) {
// 有资格生成数据
c.rw.Lock()
it = &item{
rw: new(sync.RWMutex),
}
it.data, it.expire = f[0](key, nil)
if it.expire > 0 {
it.expire += now
}
c.items[key] = it
c.flag = 0
v = it.data
c.rw.Unlock()
return
}
// 等待数据生成
runtime.Gosched()
goto A
}
// Exist 是否存在
func (c *Cache) Exist(key interface{}) bool {
return c.get(key) != nil
}
// SetExpire 设置过期时间戳
func (c *Cache) SetExpire(key interface{}, expire int64) bool {
it := c.get(key)
if it != nil {
it.rw.Lock()
it.expire = expire
it.rw.Unlock()
return true
}
return false
}
// Delete 删除
func (c *Cache) Delete(key interface{}) {
it := c.get(key)
if it != nil {
if atomic.CompareAndSwapInt32(&it.flag, 0, 1) {
it.rw.Lock()
it.data = nil
it.expire = 1
it.flag = 0
it.rw.Unlock()
}
}
}
// Each 遍历
func (c *Cache) Each(f func(k, v interface{})) {
now := time.Now().Unix()
c.rw.RLock()
for k, v := range c.items {
v.rw.RLock()
if v.expire == 0 || v.expire > now {
f(k, v.data)
}
v.rw.RUnlock()
}
c.rw.RUnlock()
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/jameson512/wego.git
git@gitee.com:jameson512/wego.git
jameson512
wego
wego
206da09742f2

搜索帮助