-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcache.go
122 lines (112 loc) · 2.46 KB
/
cache.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package ElasticCache
import (
"sync"
"time"
)
type ElasticCache interface {
// GetAndSet key缓存数据的key limitTime 数据存在的有效期,get获取数据的处理函数(如果过期了会删除该key的数据释放内存)。
GetAndSet(key string, limitTime time.Duration, get getter) (data interface{})
// Delete 删除数据
Delete(key string)
// Clear 清理缓存
Clear()
}
// New clearLimit表示多久进行一次过期数据清理。
func New(clearLimit time.Duration) ElasticCache {
e := &elasticCache{
mu: &sync.Mutex{},
clearlimit: clearLimit,
caches: make(map[string]*cache),
}
go e.run()
return e
}
type elasticCache struct {
mu *sync.Mutex
clearlimit time.Duration
caches map[string]*cache
clearCh <-chan struct{}
isClose bool
}
type getter func(key string) (data interface{}, whetherCache bool)
func (e *elasticCache) GetAndSet(key string, limitTime time.Duration, getDataFn getter) (data interface{}) {
if e.isClose {
return nil
}
if getDataFn == nil {
panic("getter should be not nil")
}
e.mu.Lock()
defer e.mu.Unlock()
now := time.Now()
c, ok := e.caches[key]
if !ok { //如果缓存不存在就从处理函数获取
d, isCache := getDataFn(key)
if isCache {
w := &cache{
lastTime: now,
limitTime: limitTime,
key: key,
handle: getDataFn,
getNum: 1,
Data: d,
}
e.caches[key] = w
}
return d
}
if now.Sub(c.lastTime) > c.limitTime { //如果缓存数据已经过期就从处理函数获取并刷新数据
var d interface{}
d, setCache := c.handle(key)
if setCache {
c.lastTime = time.Now()
c.Data = d
c.getNum = 1
} else {
delete(e.caches, key)
}
return d
}
c.getNum++
return c.Data
}
func (e *elasticCache) run() {
ticker := time.NewTicker(e.clearlimit)
for {
select {
case <-ticker.C:
for k, v := range e.caches {
now := time.Now()
if now.Sub(v.lastTime) > v.limitTime {
e.mu.Lock()
delete(e.caches, k)
e.mu.Unlock()
}
}
case <-e.clearCh:
e.mu.Lock()
e.isClose = true
for k := range e.caches {
delete(e.caches, k)
}
e.mu.Unlock()
return
}
}
}
func (e *elasticCache) Clear() {
e.clearCh = make(chan struct{}, 1)
}
func (e *elasticCache) Delete(key string) {
e.mu.Lock()
defer e.mu.Unlock()
delete(e.caches, key)
}
type cache struct {
lastTime time.Time
limitTime time.Duration
handle getter
getNum int
key string
Data interface{}
}