mirror of
https://github.com/TeaOSLab/EdgeAPI.git
synced 2025-11-02 22:10:26 +08:00
162 lines
3.1 KiB
Go
162 lines
3.1 KiB
Go
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
|
|
}
|