package ttlcache import ( "github.com/TeaOSLab/EdgeAPI/internal/utils" "time" ) var SharedCache = NewCache() // Cache TTL缓存 // 最大的缓存时间为30 * 86400 // Piece数据结构: // // Piece1 | Piece2 | Piece3 | ... // [ Item1, Item2, ... ] | ... // // KeyMap列表数据结构 // { timestamp1 => [key1, key2, ...] }, ... type Cache struct { isDestroyed bool pieces []*Piece countPieces uint64 maxItems int gcPieceIndex int } func NewCache(opt ...OptionInterface) *Cache { var countPieces = 256 var maxItems = 1_000_000 var totalMemory = utils.SystemMemoryGB() if totalMemory < 2 { // 我们限制内存过小的服务能够使用的数量 maxItems = 500_000 } else { var delta = totalMemory / 8 if delta > 0 { maxItems *= delta } } for _, option := range opt { if option == nil { continue } switch o := option.(type) { case *PiecesOption: if o.Count > 0 { countPieces = o.Count } case *MaxItemsOption: if o.Count > 0 { maxItems = o.Count } } } var cache = &Cache{ countPieces: uint64(countPieces), maxItems: maxItems, } for i := 0; i < countPieces; i++ { cache.pieces = append(cache.pieces, NewPiece(maxItems/countPieces)) } // Add to manager SharedManager.Add(cache) return cache } func (this *Cache) Write(key string, value interface{}, expiredAt int64) (ok bool) { if this.isDestroyed { return } var currentTimestamp = utils.UnixTime() if expiredAt <= currentTimestamp { return } var maxExpiredAt = currentTimestamp + 30*86400 if expiredAt > maxExpiredAt { expiredAt = maxExpiredAt } uint64Key := HashKey([]byte(key)) pieceIndex := uint64Key % this.countPieces return this.pieces[pieceIndex].Add(uint64Key, &Item{ Value: value, expiredAt: expiredAt, }) } func (this *Cache) IncreaseInt64(key string, delta int64, expiredAt int64, extend bool) int64 { if this.isDestroyed { return 0 } currentTimestamp := time.Now().Unix() if expiredAt <= currentTimestamp { return 0 } maxExpiredAt := currentTimestamp + 30*86400 if expiredAt > maxExpiredAt { expiredAt = maxExpiredAt } uint64Key := HashKey([]byte(key)) pieceIndex := uint64Key % this.countPieces return this.pieces[pieceIndex].IncreaseInt64(uint64Key, delta, expiredAt, extend) } func (this *Cache) Read(key string) (item *Item) { uint64Key := HashKey([]byte(key)) return this.pieces[uint64Key%this.countPieces].Read(uint64Key) } func (this *Cache) Delete(key string) { uint64Key := HashKey([]byte(key)) this.pieces[uint64Key%this.countPieces].Delete(uint64Key) } func (this *Cache) Count() (count int) { for _, piece := range this.pieces { count += piece.Count() } return } func (this *Cache) GC() { this.pieces[this.gcPieceIndex].GC() newIndex := this.gcPieceIndex + 1 if newIndex >= int(this.countPieces) { newIndex = 0 } this.gcPieceIndex = newIndex } func (this *Cache) Clean() { for _, piece := range this.pieces { piece.Clean() } } func (this *Cache) Destroy() { SharedManager.Remove(this) this.isDestroyed = true for _, piece := range this.pieces { piece.Destroy() } }