github.com/TeaOSLab/EdgeNode@v1.3.8/internal/ttlcache/piece.go (about) 1 package ttlcache 2 3 import ( 4 "github.com/TeaOSLab/EdgeNode/internal/utils/expires" 5 "github.com/TeaOSLab/EdgeNode/internal/utils/fasttime" 6 "sync" 7 ) 8 9 type Piece[T any] struct { 10 m map[uint64]*Item[T] 11 expiresList *expires.List 12 maxItems int 13 lastGCTime int64 14 15 locker sync.RWMutex 16 } 17 18 func NewPiece[T any](maxItems int) *Piece[T] { 19 return &Piece[T]{ 20 m: map[uint64]*Item[T]{}, 21 expiresList: expires.NewSingletonList(), 22 maxItems: maxItems, 23 } 24 } 25 26 func (this *Piece[T]) Add(key uint64, item *Item[T]) (ok bool) { 27 this.locker.RLock() 28 if this.maxItems > 0 && len(this.m) >= this.maxItems { 29 this.locker.RUnlock() 30 return 31 } 32 this.locker.RUnlock() 33 34 this.locker.Lock() 35 oldItem, exists := this.m[key] 36 if exists && oldItem.expiredAt == item.expiredAt { 37 this.locker.Unlock() 38 return true 39 } 40 this.m[key] = item 41 this.locker.Unlock() 42 43 this.expiresList.Add(key, item.expiredAt) 44 45 return true 46 } 47 48 func (this *Piece[T]) IncreaseInt64(key uint64, delta T, expiredAt int64, extend bool) (result T) { 49 this.locker.Lock() 50 item, ok := this.m[key] 51 if ok && item.expiredAt > fasttime.Now().Unix() { 52 int64Value, isInt64 := any(item.Value).(int64) 53 if isInt64 { 54 result = any(int64Value + any(delta).(int64)).(T) 55 } 56 item.Value = result 57 if extend { 58 item.expiredAt = expiredAt 59 } 60 this.expiresList.Add(key, expiredAt) 61 } else { 62 if len(this.m) < this.maxItems { 63 result = delta 64 this.m[key] = &Item[T]{ 65 Value: delta, 66 expiredAt: expiredAt, 67 } 68 this.expiresList.Add(key, expiredAt) 69 } 70 } 71 this.locker.Unlock() 72 73 return 74 } 75 76 func (this *Piece[T]) Delete(key uint64) { 77 this.expiresList.Remove(key) 78 79 this.locker.Lock() 80 delete(this.m, key) 81 this.locker.Unlock() 82 } 83 84 func (this *Piece[T]) Read(key uint64) (item *Item[T]) { 85 this.locker.RLock() 86 item = this.m[key] 87 if item != nil && item.expiredAt < fasttime.Now().Unix() { 88 item = nil 89 } 90 this.locker.RUnlock() 91 92 return 93 } 94 95 func (this *Piece[T]) Count() (count int) { 96 this.locker.RLock() 97 count = len(this.m) 98 this.locker.RUnlock() 99 return 100 } 101 102 func (this *Piece[T]) GC() { 103 var currentTime = fasttime.Now().Unix() 104 if this.lastGCTime == 0 { 105 this.lastGCTime = currentTime - 3600 106 } 107 108 var minTime = this.lastGCTime 109 var maxTime = currentTime 110 if minTime > maxTime { 111 // 过去的时间比现在大,则从这一秒重新开始 112 minTime = maxTime 113 } 114 115 for i := minTime; i <= maxTime; i++ { 116 var itemMap = this.expiresList.GC(i) 117 if len(itemMap) > 0 { 118 this.gcItemMap(itemMap) 119 } 120 } 121 122 this.lastGCTime = currentTime 123 } 124 125 func (this *Piece[T]) Clean() { 126 this.locker.Lock() 127 this.m = map[uint64]*Item[T]{} 128 this.locker.Unlock() 129 130 this.expiresList.Clean() 131 } 132 133 func (this *Piece[T]) Destroy() { 134 this.locker.Lock() 135 this.m = nil 136 this.locker.Unlock() 137 138 this.expiresList.Clean() 139 } 140 141 func (this *Piece[T]) gcItemMap(itemMap expires.ItemMap) { 142 this.locker.Lock() 143 for key := range itemMap { 144 delete(this.m, key) 145 } 146 this.locker.Unlock() 147 }