forked from redis-go/redis
-
Notifications
You must be signed in to change notification settings - Fork 0
/
keyexpire.go
107 lines (90 loc) · 1.8 KB
/
keyexpire.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
package redis
import (
"math"
"time"
)
type KeyExpirer interface {
Start(tick time.Duration, keyNum int, againPercentage int)
Stop()
}
var _ KeyExpirer = (*Expirer)(nil)
type Expirer struct {
redis *Redis
done chan bool
}
func NewKeyExpirer(r *Redis) *Expirer {
return &Expirer{
redis: r,
done: make(chan bool, math.MaxInt32),
}
}
// Start starts the Expirer.
//
// tick - How fast is the cleaner triggered.
//
// randomKeys - Amount of random expiring keys to get checked.
//
// againPercentage - If more than x% of keys were expired, start again in same tick.
func (e *Expirer) Start(tick time.Duration, randomKeys int, againPercentage int) {
ticker := time.NewTicker(tick)
for {
select {
case <-ticker.C:
e.do(randomKeys, againPercentage)
case <-e.done:
ticker.Stop()
return
}
}
}
// Stop stops the
func (e *Expirer) Stop() {
if e.done != nil {
e.done <- true
close(e.done)
}
}
func (e *Expirer) do(randomKeys, againPercentage int) {
var deletedKeys int
dbs := make(map[*RedisDb]struct{})
for _, db := range e.Redis().RedisDbs() {
if !db.HasExpiringKeys() {
continue
}
dbs[db] = struct{}{}
}
if len(dbs) == 0 {
return
}
for c := 0; c < randomKeys; c++ {
// get random db
db := func() *RedisDb {
for db := range dbs {
return db
}
return nil // won't happen
}()
// get random key
k := func() *string {
for k := range db.ExpiringKeys() {
return &k
}
return nil
}()
if k == nil {
continue
}
// del if expired
if db.DeleteExpired(k) != 0 {
deletedKeys++
}
}
// Start again in new goroutine so keys are deleted fast
if againPercentage > 0 && deletedKeys/randomKeys*100 > againPercentage {
go e.do(randomKeys, againPercentage)
}
}
// Redis gets the redis instance.
func (e *Expirer) Redis() *Redis {
return e.redis
}