2020-10-05 19:15:35 +08:00
|
|
|
package caches
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
|
|
|
|
"github.com/TeaOSLab/EdgeNode/internal/errors"
|
|
|
|
|
"github.com/TeaOSLab/EdgeNode/internal/utils"
|
2020-11-21 22:29:57 +08:00
|
|
|
"github.com/cespare/xxhash"
|
2020-10-05 19:15:35 +08:00
|
|
|
"strconv"
|
|
|
|
|
"sync"
|
2020-10-05 20:23:18 +08:00
|
|
|
"sync/atomic"
|
2020-10-05 19:15:35 +08:00
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type MemoryItem struct {
|
2021-01-13 12:02:50 +08:00
|
|
|
ExpiredAt int64
|
|
|
|
|
HeaderValue []byte
|
|
|
|
|
BodyValue []byte
|
|
|
|
|
Status int
|
2021-03-02 19:43:05 +08:00
|
|
|
IsDone bool
|
2020-10-05 19:15:35 +08:00
|
|
|
}
|
|
|
|
|
|
2021-06-06 23:42:11 +08:00
|
|
|
func (this *MemoryItem) IsExpired() bool {
|
|
|
|
|
return this.ExpiredAt < utils.UnixTime()
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-05 19:15:35 +08:00
|
|
|
type MemoryStorage struct {
|
|
|
|
|
policy *serverconfigs.HTTPCachePolicy
|
2021-05-19 12:07:35 +08:00
|
|
|
list ListInterface
|
2020-10-05 19:15:35 +08:00
|
|
|
locker *sync.RWMutex
|
|
|
|
|
valuesMap map[uint64]*MemoryItem
|
|
|
|
|
ticker *utils.Ticker
|
|
|
|
|
purgeDuration time.Duration
|
2020-10-05 20:23:18 +08:00
|
|
|
totalSize int64
|
2021-06-06 23:42:11 +08:00
|
|
|
writingKeyMap map[string]bool // key => bool
|
2020-10-05 19:15:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewMemoryStorage(policy *serverconfigs.HTTPCachePolicy) *MemoryStorage {
|
|
|
|
|
return &MemoryStorage{
|
2021-06-06 23:42:11 +08:00
|
|
|
policy: policy,
|
|
|
|
|
list: NewMemoryList(),
|
|
|
|
|
locker: &sync.RWMutex{},
|
|
|
|
|
valuesMap: map[uint64]*MemoryItem{},
|
|
|
|
|
writingKeyMap: map[string]bool{},
|
2020-10-05 19:15:35 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-12 21:38:44 +08:00
|
|
|
// Init 初始化
|
2020-10-05 19:15:35 +08:00
|
|
|
func (this *MemoryStorage) Init() error {
|
2020-10-05 20:23:18 +08:00
|
|
|
this.list.OnAdd(func(item *Item) {
|
2021-05-24 09:37:37 +08:00
|
|
|
atomic.AddInt64(&this.totalSize, item.TotalSize())
|
2020-10-05 20:23:18 +08:00
|
|
|
})
|
|
|
|
|
this.list.OnRemove(func(item *Item) {
|
2021-05-24 09:37:37 +08:00
|
|
|
atomic.AddInt64(&this.totalSize, -item.TotalSize())
|
2020-10-05 20:23:18 +08:00
|
|
|
})
|
|
|
|
|
|
2020-10-05 19:15:35 +08:00
|
|
|
if this.purgeDuration <= 0 {
|
|
|
|
|
this.purgeDuration = 30 * time.Second
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 启动定时清理任务
|
|
|
|
|
this.ticker = utils.NewTicker(this.purgeDuration)
|
|
|
|
|
go func() {
|
|
|
|
|
for this.ticker.Next() {
|
|
|
|
|
this.purgeLoop()
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-12 21:38:44 +08:00
|
|
|
// OpenReader 读取缓存
|
2021-01-13 12:02:50 +08:00
|
|
|
func (this *MemoryStorage) OpenReader(key string) (Reader, error) {
|
2020-10-05 19:15:35 +08:00
|
|
|
hash := this.hash(key)
|
|
|
|
|
|
|
|
|
|
this.locker.RLock()
|
2021-03-02 19:43:05 +08:00
|
|
|
defer this.locker.RUnlock()
|
|
|
|
|
|
2020-10-05 19:15:35 +08:00
|
|
|
item := this.valuesMap[hash]
|
2021-03-02 19:43:05 +08:00
|
|
|
if item == nil || !item.IsDone {
|
2021-01-13 12:02:50 +08:00
|
|
|
return nil, ErrNotFound
|
2020-10-05 19:15:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if item.ExpiredAt > utils.UnixTime() {
|
2021-01-13 12:02:50 +08:00
|
|
|
reader := NewMemoryReader(item)
|
|
|
|
|
err := reader.Init()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return reader, nil
|
2020-10-05 19:15:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_ = this.Delete(key)
|
|
|
|
|
|
2021-01-13 12:02:50 +08:00
|
|
|
return nil, ErrNotFound
|
2020-10-05 19:15:35 +08:00
|
|
|
}
|
|
|
|
|
|
2021-05-12 21:38:44 +08:00
|
|
|
// OpenWriter 打开缓存写入器等待写入
|
2021-01-13 12:02:50 +08:00
|
|
|
func (this *MemoryStorage) OpenWriter(key string, expiredAt int64, status int) (Writer, error) {
|
2021-06-06 23:42:11 +08:00
|
|
|
this.locker.Lock()
|
|
|
|
|
defer this.locker.Unlock()
|
|
|
|
|
|
|
|
|
|
// 是否正在写入
|
|
|
|
|
var isWriting = false
|
|
|
|
|
_, ok := this.writingKeyMap[key]
|
|
|
|
|
if ok {
|
|
|
|
|
return nil, ErrFileIsWriting
|
|
|
|
|
}
|
|
|
|
|
this.writingKeyMap[key] = true
|
|
|
|
|
defer func() {
|
|
|
|
|
if !isWriting {
|
|
|
|
|
delete(this.writingKeyMap, key)
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
// 检查是否过期
|
|
|
|
|
hash := this.hash(key)
|
|
|
|
|
item, ok := this.valuesMap[hash]
|
|
|
|
|
if ok && !item.IsExpired() {
|
|
|
|
|
return nil, ErrFileIsWriting
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-05 19:15:35 +08:00
|
|
|
// 检查是否超出最大值
|
2021-05-19 12:07:35 +08:00
|
|
|
totalKeys, err := this.list.Count()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if this.policy.MaxKeys > 0 && totalKeys > this.policy.MaxKeys {
|
2020-10-05 20:23:18 +08:00
|
|
|
return nil, errors.New("write memory cache failed: too many keys in cache storage")
|
|
|
|
|
}
|
2021-05-12 21:38:44 +08:00
|
|
|
capacityBytes := this.memoryCapacityBytes()
|
|
|
|
|
if capacityBytes > 0 && capacityBytes <= this.totalSize {
|
2021-06-06 23:42:11 +08:00
|
|
|
return nil, errors.New("write memory cache failed: over memory size: " + strconv.FormatInt(capacityBytes, 10) + ", current size: " + strconv.FormatInt(this.totalSize, 10) + " bytes")
|
2020-10-05 20:23:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 先删除
|
2021-06-06 23:42:11 +08:00
|
|
|
err = this.deleteWithoutKey(key)
|
2020-10-05 20:23:18 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
2020-10-05 19:15:35 +08:00
|
|
|
}
|
|
|
|
|
|
2021-06-06 23:42:11 +08:00
|
|
|
isWriting = true
|
|
|
|
|
return NewMemoryWriter(this.valuesMap, key, expiredAt, status, this.locker, func() {
|
|
|
|
|
this.locker.Lock()
|
|
|
|
|
delete(this.writingKeyMap, key)
|
|
|
|
|
this.locker.Unlock()
|
|
|
|
|
}), nil
|
2020-10-05 19:15:35 +08:00
|
|
|
}
|
|
|
|
|
|
2021-05-12 21:38:44 +08:00
|
|
|
// Delete 删除某个键值对应的缓存
|
2020-10-05 19:15:35 +08:00
|
|
|
func (this *MemoryStorage) Delete(key string) error {
|
|
|
|
|
hash := this.hash(key)
|
|
|
|
|
this.locker.Lock()
|
|
|
|
|
delete(this.valuesMap, hash)
|
2021-05-24 09:37:37 +08:00
|
|
|
_ = this.list.Remove(fmt.Sprintf("%d", hash))
|
2020-10-05 19:15:35 +08:00
|
|
|
this.locker.Unlock()
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-12 21:38:44 +08:00
|
|
|
// Stat 统计缓存
|
2020-10-05 19:15:35 +08:00
|
|
|
func (this *MemoryStorage) Stat() (*Stat, error) {
|
|
|
|
|
this.locker.RLock()
|
|
|
|
|
defer this.locker.RUnlock()
|
|
|
|
|
|
|
|
|
|
return this.list.Stat(func(hash string) bool {
|
|
|
|
|
return true
|
2021-05-19 12:07:35 +08:00
|
|
|
})
|
2020-10-05 19:15:35 +08:00
|
|
|
}
|
|
|
|
|
|
2021-05-12 21:38:44 +08:00
|
|
|
// CleanAll 清除所有缓存
|
2020-10-05 19:15:35 +08:00
|
|
|
func (this *MemoryStorage) CleanAll() error {
|
|
|
|
|
this.locker.Lock()
|
|
|
|
|
this.valuesMap = map[uint64]*MemoryItem{}
|
2021-05-24 09:37:37 +08:00
|
|
|
_ = this.list.Reset()
|
2020-10-05 20:23:18 +08:00
|
|
|
atomic.StoreInt64(&this.totalSize, 0)
|
2020-10-05 19:15:35 +08:00
|
|
|
this.locker.Unlock()
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-12 21:38:44 +08:00
|
|
|
// Purge 批量删除缓存
|
2020-12-23 21:28:50 +08:00
|
|
|
func (this *MemoryStorage) Purge(keys []string, urlType string) error {
|
|
|
|
|
// 目录
|
|
|
|
|
if urlType == "dir" {
|
|
|
|
|
resultKeys := []string{}
|
|
|
|
|
for _, key := range keys {
|
2021-05-19 12:07:35 +08:00
|
|
|
subKeys, err := this.list.FindKeysWithPrefix(key)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
resultKeys = append(resultKeys, subKeys...)
|
2020-12-23 21:28:50 +08:00
|
|
|
}
|
|
|
|
|
keys = resultKeys
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-05 19:15:35 +08:00
|
|
|
for _, key := range keys {
|
|
|
|
|
err := this.Delete(key)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-12 21:38:44 +08:00
|
|
|
// Stop 停止缓存策略
|
2020-10-05 19:15:35 +08:00
|
|
|
func (this *MemoryStorage) Stop() {
|
|
|
|
|
this.locker.Lock()
|
|
|
|
|
defer this.locker.Unlock()
|
|
|
|
|
|
|
|
|
|
this.valuesMap = map[uint64]*MemoryItem{}
|
2021-05-24 09:37:37 +08:00
|
|
|
_ = this.list.Reset()
|
2020-10-05 19:15:35 +08:00
|
|
|
if this.ticker != nil {
|
|
|
|
|
this.ticker.Stop()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-12 21:38:44 +08:00
|
|
|
// Policy 获取当前存储的Policy
|
2020-10-05 19:15:35 +08:00
|
|
|
func (this *MemoryStorage) Policy() *serverconfigs.HTTPCachePolicy {
|
|
|
|
|
return this.policy
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-12 21:38:44 +08:00
|
|
|
// AddToList 将缓存添加到列表
|
2020-10-05 19:15:35 +08:00
|
|
|
func (this *MemoryStorage) AddToList(item *Item) {
|
2021-01-13 12:02:50 +08:00
|
|
|
item.MetaSize = int64(len(item.Key)) + 32 /** 32是我们评估的数据结构的长度 **/
|
2020-10-05 19:15:35 +08:00
|
|
|
hash := fmt.Sprintf("%d", this.hash(item.Key))
|
2021-05-24 09:37:37 +08:00
|
|
|
_ = this.list.Add(hash, item)
|
2020-10-05 19:15:35 +08:00
|
|
|
}
|
|
|
|
|
|
2021-05-13 11:50:36 +08:00
|
|
|
// TotalDiskSize 消耗的磁盘尺寸
|
|
|
|
|
func (this *MemoryStorage) TotalDiskSize() int64 {
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TotalMemorySize 内存尺寸
|
|
|
|
|
func (this *MemoryStorage) TotalMemorySize() int64 {
|
|
|
|
|
return atomic.LoadInt64(&this.totalSize)
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-05 19:15:35 +08:00
|
|
|
// 计算Key Hash
|
|
|
|
|
func (this *MemoryStorage) hash(key string) uint64 {
|
2020-11-21 22:29:57 +08:00
|
|
|
return xxhash.Sum64String(key)
|
2020-10-05 19:15:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 清理任务
|
|
|
|
|
func (this *MemoryStorage) purgeLoop() {
|
2021-05-19 12:07:35 +08:00
|
|
|
_ = this.list.Purge(2048, func(hash string) error {
|
2020-10-05 19:15:35 +08:00
|
|
|
uintHash, err := strconv.ParseUint(hash, 10, 64)
|
|
|
|
|
if err == nil {
|
|
|
|
|
this.locker.Lock()
|
|
|
|
|
delete(this.valuesMap, uintHash)
|
|
|
|
|
this.locker.Unlock()
|
|
|
|
|
}
|
2021-05-19 12:07:35 +08:00
|
|
|
return nil
|
2020-10-05 19:15:35 +08:00
|
|
|
})
|
|
|
|
|
}
|
2021-05-12 21:38:44 +08:00
|
|
|
|
|
|
|
|
func (this *MemoryStorage) memoryCapacityBytes() int64 {
|
|
|
|
|
if this.policy == nil {
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
c1 := int64(0)
|
|
|
|
|
if this.policy.Capacity != nil {
|
|
|
|
|
c1 = this.policy.Capacity.Bytes()
|
|
|
|
|
}
|
|
|
|
|
if SharedManager.MaxMemoryCapacity != nil {
|
|
|
|
|
c2 := SharedManager.MaxMemoryCapacity.Bytes()
|
|
|
|
|
if c2 > 0 {
|
|
|
|
|
return c2
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return c1
|
|
|
|
|
}
|
2021-06-06 23:42:11 +08:00
|
|
|
|
|
|
|
|
func (this *MemoryStorage) deleteWithoutKey(key string) error {
|
|
|
|
|
hash := this.hash(key)
|
|
|
|
|
delete(this.valuesMap, hash)
|
|
|
|
|
_ = this.list.Remove(fmt.Sprintf("%d", hash))
|
|
|
|
|
return nil
|
|
|
|
|
}
|