github.com/TeaOSLab/EdgeNode@v1.3.8/internal/utils/expires/list.go (about) 1 package expires 2 3 import ( 4 "github.com/TeaOSLab/EdgeNode/internal/zero" 5 "sync" 6 ) 7 8 type ItemMap = map[uint64]zero.Zero 9 10 type List struct { 11 expireMap map[int64]ItemMap // expires timestamp => map[id]ItemMap 12 itemsMap map[uint64]int64 // itemId => timestamp 13 14 mu sync.RWMutex 15 16 gcCallback func(itemId uint64) 17 gcBatchCallback func(itemIds ItemMap) 18 19 lastTimestamp int64 20 } 21 22 func NewList() *List { 23 var list = &List{ 24 expireMap: map[int64]ItemMap{}, 25 itemsMap: map[uint64]int64{}, 26 } 27 28 SharedManager.Add(list) 29 30 return list 31 } 32 33 func NewSingletonList() *List { 34 var list = &List{ 35 expireMap: map[int64]ItemMap{}, 36 itemsMap: map[uint64]int64{}, 37 } 38 39 return list 40 } 41 42 // Add 添加条目 43 // 如果条目已经存在,则覆盖 44 func (this *List) Add(itemId uint64, expiresAt int64) { 45 this.mu.Lock() 46 defer this.mu.Unlock() 47 48 if this.lastTimestamp == 0 || this.lastTimestamp > expiresAt { 49 this.lastTimestamp = expiresAt 50 } 51 52 // 是否已经存在 53 oldExpiresAt, ok := this.itemsMap[itemId] 54 if ok { 55 if oldExpiresAt == expiresAt { 56 return 57 } 58 delete(this.expireMap[oldExpiresAt], itemId) 59 if len(this.expireMap[oldExpiresAt]) == 0 { 60 delete(this.expireMap, oldExpiresAt) 61 } 62 } 63 64 expireItemMap, ok := this.expireMap[expiresAt] 65 if ok { 66 expireItemMap[itemId] = zero.New() 67 } else { 68 this.expireMap[expiresAt] = ItemMap{ 69 itemId: zero.New(), 70 } 71 } 72 73 this.itemsMap[itemId] = expiresAt 74 } 75 76 func (this *List) Remove(itemId uint64) { 77 this.mu.Lock() 78 defer this.mu.Unlock() 79 this.removeItem(itemId) 80 } 81 82 func (this *List) ExpiresAt(itemId uint64) int64 { 83 this.mu.RLock() 84 defer this.mu.RUnlock() 85 return this.itemsMap[itemId] 86 } 87 88 func (this *List) GC(timestamp int64) ItemMap { 89 if this.lastTimestamp > timestamp+1 { 90 return nil 91 } 92 var itemMap = this.gcItems(timestamp) 93 if len(itemMap) == 0 { 94 return itemMap 95 } 96 97 if this.gcCallback != nil { 98 for itemId := range itemMap { 99 this.gcCallback(itemId) 100 } 101 } 102 if this.gcBatchCallback != nil { 103 this.gcBatchCallback(itemMap) 104 } 105 106 return itemMap 107 } 108 109 func (this *List) Clean() { 110 this.mu.Lock() 111 this.itemsMap = map[uint64]int64{} 112 this.expireMap = map[int64]ItemMap{} 113 this.mu.Unlock() 114 } 115 116 func (this *List) Count() int { 117 this.mu.RLock() 118 var count = len(this.itemsMap) 119 this.mu.RUnlock() 120 return count 121 } 122 123 func (this *List) OnGC(callback func(itemId uint64)) *List { 124 this.gcCallback = callback 125 return this 126 } 127 128 func (this *List) OnGCBatch(callback func(itemMap ItemMap)) *List { 129 this.gcBatchCallback = callback 130 return this 131 } 132 133 func (this *List) ExpireMap() map[int64]ItemMap { 134 return this.expireMap 135 } 136 137 func (this *List) ItemsMap() map[uint64]int64 { 138 return this.itemsMap 139 } 140 141 func (this *List) LastTimestamp() int64 { 142 return this.lastTimestamp 143 } 144 145 func (this *List) removeItem(itemId uint64) { 146 expiresAt, ok := this.itemsMap[itemId] 147 if !ok { 148 return 149 } 150 delete(this.itemsMap, itemId) 151 152 expireItemMap, ok := this.expireMap[expiresAt] 153 if ok { 154 delete(expireItemMap, itemId) 155 if len(expireItemMap) == 0 { 156 delete(this.expireMap, expiresAt) 157 } 158 } 159 } 160 161 func (this *List) gcItems(timestamp int64) ItemMap { 162 this.mu.RLock() 163 expireItemsMap, ok := this.expireMap[timestamp] 164 this.mu.RUnlock() 165 166 if ok { 167 this.mu.Lock() 168 for itemId := range expireItemsMap { 169 delete(this.itemsMap, itemId) 170 } 171 delete(this.expireMap, timestamp) 172 this.mu.Unlock() 173 } 174 175 return expireItemsMap 176 }