Files
EdgeNode/internal/caches/list_memory.go

439 lines
8.2 KiB
Go
Raw Normal View History

2021-05-19 12:07:35 +08:00
package caches
import (
"net"
"net/url"
2021-06-11 14:53:51 +08:00
"strconv"
2021-05-19 12:07:35 +08:00
"strings"
"sync"
"sync/atomic"
2021-06-11 14:53:51 +08:00
"testing"
2024-07-27 15:42:50 +08:00
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"github.com/iwind/TeaGo/logs"
2021-05-19 12:07:35 +08:00
)
// MemoryList 内存缓存列表管理
type MemoryList struct {
count int64
2021-06-11 14:53:51 +08:00
itemMaps map[string]map[string]*Item // prefix => { hash => item }
2021-06-11 14:53:51 +08:00
prefixes []string
2021-05-19 12:07:35 +08:00
locker sync.RWMutex
onAdd func(item *Item)
onRemove func(item *Item)
2021-06-11 14:53:51 +08:00
purgeIndex int
2021-05-19 12:07:35 +08:00
}
func NewMemoryList() ListInterface {
return &MemoryList{
2023-09-14 18:30:11 +08:00
itemMaps: map[string]map[string]*Item{},
2021-05-19 12:07:35 +08:00
}
}
func (this *MemoryList) Init() error {
2021-06-11 14:53:51 +08:00
this.prefixes = []string{"000"}
for i := 100; i <= 999; i++ {
this.prefixes = append(this.prefixes, strconv.Itoa(i))
}
for _, prefix := range this.prefixes {
this.itemMaps[prefix] = map[string]*Item{}
}
2021-05-19 12:07:35 +08:00
return nil
}
func (this *MemoryList) Reset() error {
this.locker.Lock()
2021-06-11 14:53:51 +08:00
for key := range this.itemMaps {
this.itemMaps[key] = map[string]*Item{}
}
2021-05-19 12:07:35 +08:00
this.locker.Unlock()
atomic.StoreInt64(&this.count, 0)
2021-05-19 12:07:35 +08:00
return nil
}
func (this *MemoryList) Add(hash string, item *Item) error {
this.locker.Lock()
2021-06-11 14:53:51 +08:00
prefix := this.prefix(hash)
itemMap, ok := this.itemMaps[prefix]
if !ok {
itemMap = map[string]*Item{}
this.itemMaps[prefix] = itemMap
}
// 先删除,为了可以正确触发统计
2021-06-11 14:53:51 +08:00
oldItem, ok := itemMap[hash]
if ok {
// 回调
if this.onRemove != nil {
this.onRemove(oldItem)
}
} else {
atomic.AddInt64(&this.count, 1)
}
// 添加
2021-05-19 12:07:35 +08:00
if this.onAdd != nil {
this.onAdd(item)
}
2021-06-11 14:53:51 +08:00
itemMap[hash] = item
2021-05-19 12:07:35 +08:00
this.locker.Unlock()
return nil
}
2024-04-04 08:28:14 +08:00
func (this *MemoryList) Exist(hash string) (bool, int64, error) {
2021-05-19 12:07:35 +08:00
this.locker.RLock()
defer this.locker.RUnlock()
2021-06-11 14:53:51 +08:00
prefix := this.prefix(hash)
itemMap, ok := this.itemMaps[prefix]
if !ok {
2024-04-04 08:28:14 +08:00
return false, -1, nil
2021-06-11 14:53:51 +08:00
}
item, ok := itemMap[hash]
2021-05-19 12:07:35 +08:00
if !ok {
2024-04-04 08:28:14 +08:00
return false, -1, nil
2021-05-19 12:07:35 +08:00
}
2024-04-04 08:28:14 +08:00
return !item.IsExpired(), -1, nil
2021-05-19 12:07:35 +08:00
}
2021-06-13 17:37:57 +08:00
// CleanPrefix 根据前缀进行清除
func (this *MemoryList) CleanPrefix(prefix string) error {
2021-05-19 12:07:35 +08:00
this.locker.RLock()
defer this.locker.RUnlock()
// TODO 需要优化性能支持千万级数据低于1s的处理速度
2021-06-11 14:53:51 +08:00
for _, itemMap := range this.itemMaps {
for _, item := range itemMap {
if strings.HasPrefix(item.Key, prefix) {
2024-03-22 08:23:22 +08:00
item.ExpiresAt = 0
2021-06-11 14:53:51 +08:00
}
2021-05-19 12:07:35 +08:00
}
}
2021-06-13 17:37:57 +08:00
return nil
2021-05-19 12:07:35 +08:00
}
// CleanMatchKey 清理通配符匹配的缓存数据,类似于 https://*.example.com/hello
func (this *MemoryList) CleanMatchKey(key string) error {
if strings.Contains(key, SuffixAll) {
return nil
}
u, err := url.Parse(key)
if err != nil {
return nil
}
var host = u.Host
hostPart, _, err := net.SplitHostPort(host)
if err == nil && len(hostPart) > 0 {
host = hostPart
}
if len(host) == 0 {
return nil
}
var requestURI = u.RequestURI()
this.locker.RLock()
defer this.locker.RUnlock()
// TODO 需要优化性能支持千万级数据低于1s的处理速度
for _, itemMap := range this.itemMaps {
for _, item := range itemMap {
if configutils.MatchDomain(host, item.Host) {
var itemRequestURI = item.RequestURI()
if itemRequestURI == requestURI || strings.HasPrefix(itemRequestURI, requestURI+SuffixAll) {
2024-03-22 08:23:22 +08:00
item.ExpiresAt = 0
}
}
}
}
return nil
}
// CleanMatchPrefix 清理通配符匹配的缓存数据,类似于 https://*.example.com/prefix/
func (this *MemoryList) CleanMatchPrefix(prefix string) error {
u, err := url.Parse(prefix)
if err != nil {
return nil
}
var host = u.Host
hostPart, _, err := net.SplitHostPort(host)
if err == nil && len(hostPart) > 0 {
host = hostPart
}
if len(host) == 0 {
return nil
}
var requestURI = u.RequestURI()
var isRootPath = requestURI == "/"
this.locker.RLock()
defer this.locker.RUnlock()
// TODO 需要优化性能支持千万级数据低于1s的处理速度
for _, itemMap := range this.itemMaps {
for _, item := range itemMap {
if configutils.MatchDomain(host, item.Host) {
var itemRequestURI = item.RequestURI()
if isRootPath || strings.HasPrefix(itemRequestURI, requestURI) {
2024-03-22 08:23:22 +08:00
item.ExpiresAt = 0
}
}
}
}
return nil
}
2021-05-19 12:07:35 +08:00
func (this *MemoryList) Remove(hash string) error {
this.locker.Lock()
2021-06-11 14:53:51 +08:00
itemMap, ok := this.itemMaps[this.prefix(hash)]
if !ok {
this.locker.Unlock()
return nil
}
item, ok := itemMap[hash]
2021-05-19 12:07:35 +08:00
if ok {
if this.onRemove != nil {
this.onRemove(item)
}
atomic.AddInt64(&this.count, -1)
2021-06-11 14:53:51 +08:00
delete(itemMap, hash)
2021-05-19 12:07:35 +08:00
}
this.locker.Unlock()
return nil
}
// Purge 清理过期的缓存
// count 每次遍历的最大数量,控制此数字可以保证每次清理的时候不用花太多时间
// callback 每次发现过期key的调用
func (this *MemoryList) Purge(count int, callback func(hash string) error) (int, error) {
2021-05-19 12:07:35 +08:00
this.locker.Lock()
2023-09-14 18:30:11 +08:00
var deletedHashList = []string{}
2021-06-11 14:53:51 +08:00
if this.purgeIndex >= len(this.prefixes) {
this.purgeIndex = 0
}
2023-09-14 18:30:11 +08:00
var prefix = this.prefixes[this.purgeIndex]
2021-06-11 14:53:51 +08:00
this.purgeIndex++
itemMap, ok := this.itemMaps[prefix]
if !ok {
this.locker.Unlock()
return 0, nil
2021-06-11 14:53:51 +08:00
}
var countFound = 0
2021-06-11 14:53:51 +08:00
for hash, item := range itemMap {
2021-05-19 12:07:35 +08:00
if count <= 0 {
break
}
if item.IsExpired() {
if this.onRemove != nil {
this.onRemove(item)
}
atomic.AddInt64(&this.count, -1)
2021-06-11 14:53:51 +08:00
delete(itemMap, hash)
2021-05-19 12:07:35 +08:00
deletedHashList = append(deletedHashList, hash)
countFound++
2021-05-19 12:07:35 +08:00
}
count--
}
this.locker.Unlock()
// 执行外部操作
for _, hash := range deletedHashList {
if callback != nil {
err := callback(hash)
if err != nil {
return 0, err
}
}
}
return countFound, nil
}
func (this *MemoryList) PurgeLFU(count int, callback func(hash string) error) error {
if count <= 0 {
return nil
}
2023-09-14 18:30:11 +08:00
var deletedHashList = []string{}
var week = currentWeek()
2023-09-14 18:30:11 +08:00
var round = 0
2023-09-14 18:30:11 +08:00
this.locker.Lock()
Loop:
2023-09-14 18:30:11 +08:00
for {
var found = false
round++
for _, itemMap := range this.itemMaps {
for hash, item := range itemMap {
found = true
if week-item.Week <= 1 /** 最近有在使用 **/ && round <= 3 /** 查找轮数过多还不满足数量要求的就不再限制 **/ {
continue
}
if this.onRemove != nil {
this.onRemove(item)
}
2023-09-14 18:30:11 +08:00
atomic.AddInt64(&this.count, -1)
delete(itemMap, hash)
deletedHashList = append(deletedHashList, hash)
count--
if count <= 0 {
break Loop
}
2023-09-14 18:30:11 +08:00
break
}
}
2023-09-14 18:30:11 +08:00
if !found {
break
}
}
2023-09-14 18:30:11 +08:00
this.locker.Unlock()
2021-05-19 12:07:35 +08:00
// 执行外部操作
for _, hash := range deletedHashList {
if callback != nil {
err := callback(hash)
if err != nil {
return err
}
}
}
2021-05-19 12:07:35 +08:00
return nil
}
func (this *MemoryList) CleanAll() error {
return this.Reset()
}
func (this *MemoryList) Stat(check func(hash string) bool) (*Stat, error) {
this.locker.RLock()
defer this.locker.RUnlock()
result := &Stat{
Count: 0,
Size: 0,
}
2021-06-11 14:53:51 +08:00
for _, itemMap := range this.itemMaps {
for hash, item := range itemMap {
if !item.IsExpired() {
// 检查文件是否存在、内容是否正确等
if check != nil && check(hash) {
result.Count++
result.ValueSize += item.Size()
result.Size += item.TotalSize()
}
2021-05-19 12:07:35 +08:00
}
}
}
return result, nil
}
// Count 总数量
func (this *MemoryList) Count() (int64, error) {
var count = atomic.LoadInt64(&this.count)
return count, nil
2021-05-19 12:07:35 +08:00
}
// OnAdd 添加事件
func (this *MemoryList) OnAdd(f func(item *Item)) {
this.onAdd = f
}
// OnRemove 删除事件
func (this *MemoryList) OnRemove(f func(item *Item)) {
this.onRemove = f
}
2021-06-11 14:53:51 +08:00
2021-06-13 17:37:57 +08:00
func (this *MemoryList) Close() error {
return nil
}
// IncreaseHit 增加点击量
func (this *MemoryList) IncreaseHit(hash string) error {
this.locker.Lock()
itemMap, ok := this.itemMaps[this.prefix(hash)]
if !ok {
this.locker.Unlock()
return nil
}
item, ok := itemMap[hash]
if ok {
2023-09-14 18:30:11 +08:00
item.Week = currentWeek()
}
this.locker.Unlock()
return nil
}
2024-01-19 09:27:42 +08:00
func (this *MemoryList) Prefixes() []string {
return this.prefixes
}
func (this *MemoryList) ItemMaps() map[string]map[string]*Item {
return this.itemMaps
}
func (this *MemoryList) PurgeIndex() int {
return this.purgeIndex
}
func (this *MemoryList) Print(t *testing.T) {
2021-06-11 14:53:51 +08:00
this.locker.Lock()
for _, itemMap := range this.itemMaps {
if len(itemMap) > 0 {
logs.PrintAsJSON(itemMap, t)
}
}
this.locker.Unlock()
}
func (this *MemoryList) prefix(hash string) string {
var prefix string
if len(hash) > 3 {
prefix = hash[:3]
} else {
prefix = hash
}
_, ok := this.itemMaps[prefix]
if !ok {
prefix = "000"
}
return prefix
}