github.com/sohaha/zlsgo@v1.7.13-0.20240501141223-10dd1a906f76/zcache/table.go (about) 1 package zcache 2 3 import ( 4 "sort" 5 "sync" 6 "time" 7 8 "github.com/sohaha/zlsgo/ztime" 9 "github.com/sohaha/zlsgo/zutil" 10 // "github.com/sohaha/zlsgo/zlog" 11 // "sync/atomic" 12 ) 13 14 type ( 15 // CacheItemPair maps key to access counter 16 CacheItemPair struct { 17 Key string 18 AccessCount int64 19 } 20 // CacheItemPairList CacheItemPairList 21 CacheItemPairList []CacheItemPair 22 // Table Table 23 Table struct { 24 items map[string]*Item 25 cleanupTimer *time.Timer 26 loadNotCallback func(key string, args ...interface{}) *Item 27 addCallback func(item *Item) 28 deleteCallback func(key string) bool 29 accessCount *zutil.Bool 30 name string 31 cleanupInterval time.Duration 32 sync.RWMutex 33 } 34 ) 35 36 // Count get the number of caches 37 func (table *Table) Count() int { 38 table.RLock() 39 defer table.RUnlock() 40 return len(table.items) 41 } 42 43 // ForEach traversing the cache 44 func (table *Table) ForEach(trans func(key string, value interface{}) bool) { 45 table.ForEachRaw(func(k string, v *Item) bool { 46 return trans(k, v.Data()) 47 }) 48 } 49 50 // ForEachRaw traversing the cache 51 func (table *Table) ForEachRaw(trans func(key string, value *Item) bool) { 52 count := table.Count() 53 table.RLock() 54 items := make(map[string]*Item, count) 55 for k, v := range table.items { 56 items[k] = v 57 } 58 table.RUnlock() 59 60 for k, v := range items { 61 if !trans(k, v) { 62 break 63 } 64 } 65 } 66 67 // SetLoadNotCallback SetLoadNotCallback 68 func (table *Table) SetLoadNotCallback(f func(key string, args ...interface{}) *Item) { 69 table.Lock() 70 defer table.Unlock() 71 table.loadNotCallback = f 72 } 73 74 // SetAddCallback SetAddCallback 75 func (table *Table) SetAddCallback(f func(*Item)) { 76 table.Lock() 77 defer table.Unlock() 78 table.addCallback = f 79 } 80 81 // SetDeleteCallback SetDeleteCallback 82 func (table *Table) SetDeleteCallback(f func(key string) bool) { 83 table.Lock() 84 defer table.Unlock() 85 table.deleteCallback = f 86 } 87 88 func (table *Table) expirationCheck() { 89 now := ztime.UnixMicro(ztime.Clock()) 90 smallestDuration := time.Duration(0) 91 table.Lock() 92 if table.cleanupTimer != nil { 93 table.cleanupTimer.Stop() 94 } 95 96 for key, item := range table.items { 97 item.RLock() 98 lifeSpan := item.lifeSpan 99 accessedOn := item.accessedTime 100 intervalLifeSpan := item.intervalLifeSpan 101 item.RUnlock() 102 if lifeSpan == 0 { 103 continue 104 } 105 remainingLift := item.RemainingLife() 106 if table.accessCount.Load() && intervalLifeSpan { 107 lastTime := now.Sub(accessedOn) 108 if lastTime >= lifeSpan { 109 _, _ = table.deleteInternal(key) 110 } else { 111 lifeSpan = lifeSpan * 2 112 item.Lock() 113 item.lifeSpan = lifeSpan 114 item.Unlock() 115 nextDuration := lifeSpan - lastTime 116 if smallestDuration == 0 || nextDuration < smallestDuration { 117 smallestDuration = nextDuration 118 } 119 } 120 } else if remainingLift <= 0 { 121 _, _ = table.deleteInternal(key) 122 } else { 123 if smallestDuration == 0 || smallestDuration > remainingLift { 124 smallestDuration = remainingLift 125 } 126 } 127 } 128 table.cleanupInterval = smallestDuration 129 130 if smallestDuration > 0 { 131 table.cleanupTimer = time.AfterFunc(smallestDuration, func() { 132 go table.expirationCheck() 133 }) 134 } 135 table.Unlock() 136 } 137 138 func (table *Table) addInternal(item *Item) { 139 table.Lock() 140 table.items[item.key] = item 141 142 expDur := table.cleanupInterval 143 addedItem := table.addCallback 144 table.Unlock() 145 146 if addedItem != nil { 147 addedItem(item) 148 } 149 item.RLock() 150 lifeSpan := item.lifeSpan 151 item.RUnlock() 152 if lifeSpan > 0 && (expDur == 0 || lifeSpan < expDur) { 153 go table.expirationCheck() 154 } 155 } 156 157 // SetRaw set cache 158 func (table *Table) SetRaw(key string, data interface{}, lifeSpan time.Duration, 159 intervalLifeSpan ...bool) *Item { 160 item := NewCacheItem(key, data, lifeSpan) 161 162 if len(intervalLifeSpan) > 0 && intervalLifeSpan[0] { 163 table.accessCount.Store(true) 164 item.intervalLifeSpan = intervalLifeSpan[0] 165 } 166 table.addInternal(item) 167 168 return item 169 } 170 171 // Set set cache whether to automatically renew 172 func (table *Table) Set(key string, data interface{}, lifeSpanSecond uint, 173 interval ...bool) *Item { 174 return table.SetRaw(key, data, time.Duration(lifeSpanSecond)*time.Second, interval...) 175 } 176 177 func (table *Table) deleteInternal(key string) (*Item, error) { 178 r, ok := table.items[key] 179 if !ok { 180 return nil, ErrKeyNotFound 181 } 182 183 deleteCallback := table.deleteCallback 184 table.Unlock() 185 if deleteCallback != nil && !deleteCallback(r.key) { 186 table.Lock() 187 r.RLock() 188 r.accessedTime = ztime.UnixMicro(ztime.Clock()) 189 r.RUnlock() 190 return r, nil 191 } 192 193 r.RLock() 194 defer r.RUnlock() 195 if r.deleteCallback != nil && !r.deleteCallback(r.key) { 196 table.Lock() 197 r.RLock() 198 r.accessedTime = ztime.UnixMicro(ztime.Clock()) 199 r.RUnlock() 200 return r, nil 201 } 202 203 table.Lock() 204 delete(table.items, key) 205 return r, nil 206 } 207 208 // Delete Delete cache 209 func (table *Table) Delete(key string) (*Item, error) { 210 table.Lock() 211 defer table.Unlock() 212 213 return table.deleteInternal(key) 214 } 215 216 // Exists Exists 217 func (table *Table) Exists(key string) bool { 218 table.RLock() 219 defer table.RUnlock() 220 _, ok := table.items[key] 221 222 return ok 223 } 224 225 // Add if the cache does not exist then adding does not take effect 226 func (table *Table) Add(key string, data interface{}, lifeSpan time.Duration, intervalLifeSpan ...bool) bool { 227 table.Lock() 228 _, ok := table.items[key] 229 table.Unlock() 230 if ok { 231 return false 232 } 233 234 item := NewCacheItem(key, data, lifeSpan) 235 if len(intervalLifeSpan) > 0 { 236 item.intervalLifeSpan = intervalLifeSpan[0] 237 } 238 table.addInternal(item) 239 240 return true 241 } 242 243 // MustGet get the Raw of the specified key, set if it does not exist 244 func (table *Table) MustGet(key string, do func(set func(data interface{}, 245 lifeSpan time.Duration, interval ...bool)) ( 246 err error)) (data interface{}, err error) { 247 table.Lock() 248 r, ok := table.items[key] 249 if ok { 250 table.Unlock() 251 r.keepAlive() 252 return r.Data(), nil 253 } 254 item := NewCacheItem(key, "", 0) 255 item.Lock() 256 table.items[key] = item 257 table.Unlock() 258 err = do(func(data interface{}, 259 lifeSpan time.Duration, interval ...bool) { 260 item.data = data 261 item.lifeSpan = lifeSpan 262 if len(interval) > 0 { 263 item.intervalLifeSpan = interval[0] 264 } 265 }) 266 item.Unlock() 267 268 if err != nil { 269 table.Lock() 270 delete(table.items, key) 271 table.Unlock() 272 return 273 } 274 275 data = item.data 276 table.addInternal(item) 277 return 278 } 279 280 // GetT GetT 281 func (table *Table) GetT(key string, args ...interface{}) (*Item, error) { 282 table.RLock() 283 r, ok := table.items[key] 284 table.RUnlock() 285 286 if ok { 287 if table.accessCount.Load() { 288 r.keepAlive() 289 } 290 return r, nil 291 } 292 293 loadData := table.loadNotCallback 294 if loadData != nil { 295 item := loadData(key, args...) 296 if item != nil { 297 table.SetRaw(key, item.data, item.lifeSpan) 298 return item, nil 299 } 300 301 return nil, ErrKeyNotFoundAndNotCallback 302 } 303 304 return nil, ErrKeyNotFound 305 } 306 307 // Get get the Raw of the specified key 308 func (table *Table) Get(key string, args ...interface{}) (value interface{}, err error) { 309 var data *Item 310 data, err = table.GetT(key, args...) 311 if err != nil { 312 return 313 } 314 value = data.Data() 315 return 316 } 317 318 func (table *Table) GetString(key string, args ...interface{}) (value string, err error) { 319 data, err := table.Get(key, args...) 320 if err != nil { 321 return 322 } 323 value, _ = data.(string) 324 return 325 } 326 327 func (table *Table) GetInt(key string, args ...interface{}) (value int, err error) { 328 data, err := table.Get(key, args...) 329 if err != nil { 330 return 331 } 332 value, _ = data.(int) 333 334 return 335 } 336 337 // Clear Clear 338 func (table *Table) Clear() { 339 table.Lock() 340 table.items = make(map[string]*Item) 341 table.cleanupInterval = 0 342 if table.cleanupTimer != nil { 343 table.cleanupTimer.Stop() 344 } 345 table.Unlock() 346 } 347 348 func (p CacheItemPairList) Swap(i, j int) { p[i], p[j] = p[j], p[i] } 349 func (p CacheItemPairList) Len() int { return len(p) } 350 func (p CacheItemPairList) Less(i, j int) bool { return p[i].AccessCount > p[j].AccessCount } 351 352 // MostAccessed MostAccessed 353 func (table *Table) MostAccessed(count int64) []*Item { 354 table.RLock() 355 defer table.RUnlock() 356 357 p := make(CacheItemPairList, len(table.items)) 358 i := 0 359 for k, v := range table.items { 360 p[i] = CacheItemPair{k, v.accessCount} 361 i++ 362 } 363 sort.Sort(p) 364 365 var r []*Item 366 c := int64(0) 367 for _, v := range p { 368 if c >= count { 369 break 370 } 371 372 item, ok := table.items[v.Key] 373 if ok { 374 r = append(r, item) 375 } 376 c++ 377 } 378 379 return r 380 }