Skip to content

Commit daefcd2

Browse files
committed
feat: app:bcache
1 parent 80f0b13 commit daefcd2

File tree

6 files changed

+1063
-0
lines changed

6 files changed

+1063
-0
lines changed

app/bcache/bcache.go

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
package bcache
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"sync"
7+
"time"
8+
9+
"github.com/songzhibin97/go-baseutils/base/bcomparator"
10+
"github.com/songzhibin97/go-baseutils/base/bmap"
11+
"github.com/songzhibin97/go-baseutils/base/options"
12+
"github.com/songzhibin97/go-baseutils/structure/sets/zset"
13+
)
14+
15+
const (
16+
DefaultExpire time.Duration = 0
17+
NoExpire time.Duration = -1
18+
)
19+
20+
type BCache[K comparable, V any] struct {
21+
*bCache[K, V]
22+
}
23+
24+
func New[K comparable, V any](comparator bcomparator.Comparator[K], opts ...options.Option[*Config[K, V]]) *BCache[K, V] {
25+
ctx, cancel := context.WithCancel(context.Background())
26+
c := &Config[K, V]{
27+
defaultExpire: 0,
28+
interval: 0,
29+
capture: func(k K, v V) {
30+
fmt.Printf("delete k:%v v:%v\n", k, v)
31+
},
32+
comparator: comparator,
33+
}
34+
for _, option := range opts {
35+
option(c)
36+
}
37+
obj := &bCache[K, V]{
38+
config: c,
39+
defaultExpire: c.defaultExpire,
40+
capture: c.capture,
41+
cancel: cancel,
42+
}
43+
if c.setSentinelFn == nil {
44+
c.setSentinelFn = obj.deleteExpire
45+
}
46+
obj.member = bmap.NewUnsafeAnyBMap[K, Iterator[V]]()
47+
obj.visit = zset.New[K](comparator)
48+
go NewSentinel(ctx, c.interval, c.setSentinelFn).Start()
49+
return &BCache[K, V]{obj}
50+
}
51+
52+
func (c *BCache[K, V]) Set(k K, v V, d time.Duration) {
53+
c.set(k, v, d)
54+
}
55+
56+
func (c *BCache[K, V]) SetDefault(k K, v V) {
57+
c.set(k, v, c.defaultExpire)
58+
}
59+
60+
func (c *BCache[K, V]) SetNoExpire(k K, v V) {
61+
c.set(k, v, NoExpire)
62+
}
63+
64+
func (c *BCache[K, V]) SetIfAbsent(k K, v V, d time.Duration) bool {
65+
return c.setIfAbsent(k, v, d)
66+
}
67+
68+
func (c *BCache[K, V]) Replace(k K, v V, d time.Duration) bool {
69+
return c.replace(k, v, d)
70+
}
71+
72+
func (c *BCache[K, V]) Delete(k K) {
73+
c.bCache.Delete(k)
74+
}
75+
76+
func (c *BCache[K, V]) Get(k K) (V, bool) {
77+
v, _, ok := c.get(k)
78+
return v, ok
79+
}
80+
81+
func (c *BCache[K, V]) GetWithExpire(k K) (V, time.Time, bool) {
82+
v, t, ok := c.get(k)
83+
return v, t, ok
84+
}
85+
86+
func (c *BCache[K, V]) Count() int {
87+
return c.count()
88+
}
89+
90+
func (c *BCache[K, V]) Clear() {
91+
c.clear()
92+
}
93+
94+
func (c *BCache[K, V]) Load(data []byte) error {
95+
return c.Unmarshal(data)
96+
}
97+
98+
func (c *BCache[K, V]) Export() ([]byte, error) {
99+
return c.Marshal()
100+
}
101+
102+
type bCache[K comparable, V any] struct {
103+
config *Config[K, V]
104+
105+
// defaultExpire 默认超时时间
106+
defaultExpire time.Duration
107+
108+
sync.RWMutex // Protection member&visit
109+
110+
// member 维护map存储kv关系
111+
member bmap.AnyBMap[K, Iterator[V]]
112+
113+
// visit 维护具有超时的key
114+
visit *zset.Set[K]
115+
116+
// capture 捕获删除对象时间 会返回kv值用于用户自定义处理
117+
capture func(k K, v V)
118+
119+
cancel context.CancelFunc
120+
121+
zero V
122+
zeroTime time.Time
123+
}
124+
125+
func (c *bCache[K, V]) newIterator(v V, d time.Duration) Iterator[V] {
126+
var expire int64
127+
switch d {
128+
case NoExpire:
129+
case DefaultExpire:
130+
if c.defaultExpire > 0 {
131+
expire = time.Now().Add(c.defaultExpire).UnixNano()
132+
}
133+
default:
134+
if d > 0 {
135+
expire = time.Now().Add(d).UnixNano()
136+
}
137+
// 如果走到这里 默认是 NoExpire
138+
}
139+
return Iterator[V]{
140+
Value: v,
141+
Expire: expire,
142+
}
143+
}
144+
145+
func (c *bCache[K, V]) set(k K, v V, d time.Duration) {
146+
147+
iter := c.newIterator(v, d)
148+
c.Lock()
149+
defer c.Unlock()
150+
151+
if iter.Expire != 0 {
152+
c.visit.AddB(float64(iter.Expire), k)
153+
}
154+
c.member.Put(k, iter)
155+
}
156+
157+
func (c *bCache[K, V]) setDeadline(k K, v V, d int64) {
158+
159+
if d != 0 {
160+
c.visit.AddB(float64(d), k)
161+
}
162+
c.member.Put(k, Iterator[V]{
163+
Value: v,
164+
Expire: d,
165+
})
166+
}
167+
168+
func (c *bCache[K, V]) setIfAbsent(k K, v V, d time.Duration) bool {
169+
iter := c.newIterator(v, d)
170+
171+
c.Lock()
172+
defer c.Unlock()
173+
174+
ok := c.member.PuTIfAbsent(k, iter)
175+
if ok && iter.Expire != 0 {
176+
c.visit.AddB(float64(iter.Expire), k)
177+
}
178+
return ok
179+
}
180+
181+
func (c *bCache[K, V]) get(k K) (V, time.Time, bool) {
182+
c.Lock()
183+
defer c.Unlock()
184+
v, ok := c.member.Get(k)
185+
if !ok {
186+
return c.zero, c.zeroTime, false
187+
}
188+
if v.expired() {
189+
c.delete(k)
190+
return c.zero, c.zeroTime, false
191+
}
192+
if !v.isVisit() {
193+
return v.Value, c.zeroTime, true
194+
}
195+
return v.Value, time.Unix(0, v.Expire), true
196+
}
197+
198+
func (c *bCache[K, V]) replace(k K, v V, d time.Duration) bool {
199+
iter := c.newIterator(v, d)
200+
c.Lock()
201+
defer c.Unlock()
202+
ov, ok := c.member.Get(k)
203+
if !ok {
204+
return false
205+
}
206+
if ov.expired() {
207+
c.delete(k)
208+
return false
209+
}
210+
c.member.Put(k, iter)
211+
if iter.Expire != 0 {
212+
c.visit.AddB(float64(iter.Expire), k)
213+
}
214+
return true
215+
}
216+
217+
func (c *bCache[K, V]) Delete(k K) {
218+
c.Lock()
219+
defer c.Unlock()
220+
v, ok := c.delete(k)
221+
if ok && c.capture != nil {
222+
c.capture(k, v)
223+
}
224+
}
225+
226+
func (c *bCache[K, V]) delete(k K) (V, bool) {
227+
nv, ok := c.member.DeleteIfPresent(k)
228+
if !ok {
229+
return c.zero, false
230+
}
231+
c.visit.Remove(k)
232+
return nv.Value, true
233+
}
234+
235+
func (c *bCache[K, V]) deleteExpire() {
236+
c.Lock()
237+
defer c.Unlock()
238+
nodes := c.visit.RemoveRangeByScore(0, float64(time.Now().UnixNano()))
239+
for _, n := range nodes {
240+
c.member.Delete(n.Value)
241+
}
242+
}
243+
244+
func (c *bCache[K, V]) count() int {
245+
c.Lock()
246+
defer c.Unlock()
247+
return c.member.Size()
248+
}
249+
250+
func (c *bCache[K, V]) clear() {
251+
c.Lock()
252+
defer c.Unlock()
253+
c.member = bmap.NewUnsafeAnyBMap[K, Iterator[V]]()
254+
c.visit = zset.New[K](c.config.comparator)
255+
}
256+
257+
func (c *bCache[K, V]) Marshal() ([]byte, error) {
258+
c.Lock()
259+
defer c.Unlock()
260+
return c.member.Marshal()
261+
}
262+
263+
func (c *bCache[K, V]) Unmarshal(data []byte) error {
264+
c.Lock()
265+
defer c.Unlock()
266+
mp := bmap.NewUnsafeAnyBMap[K, Iterator[V]]()
267+
err := mp.Unmarshal(data)
268+
if err != nil {
269+
return err
270+
}
271+
mp.ForEach(func(k K, v Iterator[V]) {
272+
if !v.expired() {
273+
c.setDeadline(k, v.Value, v.Expire)
274+
}
275+
})
276+
return nil
277+
}

0 commit comments

Comments
 (0)