package expires import ( "github.com/TeaOSLab/EdgeAPI/internal/zero" "sync" ) type ItemMap = map[uint64]zero.Zero type List struct { expireMap map[int64]ItemMap // expires timestamp => map[id]ItemMap itemsMap map[uint64]int64 // itemId => timestamp locker sync.Mutex gcCallback func(itemId uint64) gcBatchCallback func(itemIds ItemMap) lastTimestamp int64 } func NewList() *List { var list = &List{ expireMap: map[int64]ItemMap{}, itemsMap: map[uint64]int64{}, } SharedManager.Add(list) return list } func NewSingletonList() *List { var list = &List{ expireMap: map[int64]ItemMap{}, itemsMap: map[uint64]int64{}, } return list } // Add 添加条目 // 如果条目已经存在,则覆盖 func (this *List) Add(itemId uint64, expiresAt int64) { this.locker.Lock() defer this.locker.Unlock() if this.lastTimestamp == 0 || this.lastTimestamp > expiresAt { this.lastTimestamp = expiresAt } // 是否已经存在 oldExpiresAt, ok := this.itemsMap[itemId] if ok { if oldExpiresAt == expiresAt { return } delete(this.expireMap[oldExpiresAt], itemId) if len(this.expireMap[oldExpiresAt]) == 0 { delete(this.expireMap, oldExpiresAt) } } expireItemMap, ok := this.expireMap[expiresAt] if ok { expireItemMap[itemId] = zero.New() } else { this.expireMap[expiresAt] = ItemMap{ itemId: zero.New(), } } this.itemsMap[itemId] = expiresAt } func (this *List) Remove(itemId uint64) { this.locker.Lock() defer this.locker.Unlock() this.removeItem(itemId) } func (this *List) ExpiresAt(itemId uint64) int64 { this.locker.Lock() defer this.locker.Unlock() return this.itemsMap[itemId] } func (this *List) GC(timestamp int64) ItemMap { if this.lastTimestamp > timestamp+1 { return nil } this.locker.Lock() var itemMap = this.gcItems(timestamp) if len(itemMap) == 0 { this.locker.Unlock() return itemMap } this.locker.Unlock() if this.gcCallback != nil { for itemId := range itemMap { this.gcCallback(itemId) } } if this.gcBatchCallback != nil { this.gcBatchCallback(itemMap) } return itemMap } func (this *List) Clean() { this.locker.Lock() this.itemsMap = map[uint64]int64{} this.expireMap = map[int64]ItemMap{} this.locker.Unlock() } func (this *List) Count() int { this.locker.Lock() var count = len(this.itemsMap) this.locker.Unlock() return count } func (this *List) OnGC(callback func(itemId uint64)) *List { this.gcCallback = callback return this } func (this *List) OnGCBatch(callback func(itemMap ItemMap)) *List { this.gcBatchCallback = callback return this } func (this *List) removeItem(itemId uint64) { expiresAt, ok := this.itemsMap[itemId] if !ok { return } delete(this.itemsMap, itemId) expireItemMap, ok := this.expireMap[expiresAt] if ok { delete(expireItemMap, itemId) if len(expireItemMap) == 0 { delete(this.expireMap, expiresAt) } } } func (this *List) gcItems(timestamp int64) ItemMap { expireItemsMap, ok := this.expireMap[timestamp] if ok { for itemId := range expireItemsMap { delete(this.itemsMap, itemId) } delete(this.expireMap, timestamp) } return expireItemsMap }