Files
EdgeAdmin/internal/ttlcache/cache.go
GoEdgeLab d7d0c8fbfe v1.4.1
2024-07-27 15:42:58 +08:00

147 lines
2.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package ttlcache
import (
"time"
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
)
var DefaultCache = NewCache()
// 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
ticker *utils.Ticker
}
func NewCache(opt ...OptionInterface) *Cache {
countPieces := 128
maxItems := 1_000_000
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
}
}
}
cache := &Cache{
countPieces: uint64(countPieces),
maxItems: maxItems,
}
for i := 0; i < countPieces; i++ {
cache.pieces = append(cache.pieces, NewPiece(maxItems/countPieces))
}
// start timer
go func() {
cache.ticker = utils.NewTicker(5 * time.Second)
for cache.ticker.Next() {
cache.GC()
}
}()
return cache
}
func (this *Cache) Write(key string, value interface{}, expiredAt int64) {
if this.isDestroyed {
return
}
currentTimestamp := time.Now().Unix()
if expiredAt <= currentTimestamp {
return
}
maxExpiredAt := currentTimestamp + 30*86400
if expiredAt > maxExpiredAt {
expiredAt = maxExpiredAt
}
uint64Key := HashKey([]byte(key))
pieceIndex := uint64Key % this.countPieces
this.pieces[pieceIndex].Add(uint64Key, &Item{
Value: value,
expiredAt: expiredAt,
})
}
func (this *Cache) IncreaseInt64(key string, delta int64, expiredAt int64) 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)
}
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) Destroy() {
this.isDestroyed = true
if this.ticker != nil {
this.ticker.Stop()
this.ticker = nil
}
for _, piece := range this.pieces {
piece.Destroy()
}
}