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