mirror of
				https://github.com/TeaOSLab/EdgeAPI.git
				synced 2025-11-04 16:00:24 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			162 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			162 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
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) readIntKey(key uint64) (value *Item) {
 | 
						||
	return this.pieces[key%this.countPieces].Read(key)
 | 
						||
}
 | 
						||
 | 
						||
func (this *Cache) Delete(key string) {
 | 
						||
	uint64Key := HashKey([]byte(key))
 | 
						||
	this.pieces[uint64Key%this.countPieces].Delete(uint64Key)
 | 
						||
}
 | 
						||
 | 
						||
func (this *Cache) deleteIntKey(key uint64) {
 | 
						||
	this.pieces[key%this.countPieces].Delete(key)
 | 
						||
}
 | 
						||
 | 
						||
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()
 | 
						||
	}
 | 
						||
}
 |