mirror of
https://github.com/TeaOSLab/EdgeNode.git
synced 2025-11-06 01:50:26 +08:00
支持使用域名中含有通配符清除缓存数据
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
package caches
|
package caches
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
SuffixAll = "@GOEDGE_" // 通用后缀
|
||||||
SuffixWebP = "@GOEDGE_WEBP" // WebP后缀
|
SuffixWebP = "@GOEDGE_WEBP" // WebP后缀
|
||||||
SuffixCompression = "@GOEDGE_" // 压缩后缀 SuffixCompression + Encoding
|
SuffixCompression = "@GOEDGE_" // 压缩后缀 SuffixCompression + Encoding
|
||||||
SuffixMethod = "@GOEDGE_" // 请求方法后缀 SuffixMethod + RequestMethod
|
SuffixMethod = "@GOEDGE_" // 请求方法后缀 SuffixMethod + RequestMethod
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package caches
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/utils"
|
"github.com/TeaOSLab/EdgeNode/internal/utils"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -59,3 +60,17 @@ func (this *Item) IncreaseHit(week int32) {
|
|||||||
this.Week = week
|
this.Week = week
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *Item) RequestURI() string {
|
||||||
|
var schemeIndex = strings.Index(this.Key, "://")
|
||||||
|
if schemeIndex <= 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var firstSlashIndex = strings.Index(this.Key[schemeIndex+3:], "/")
|
||||||
|
if firstSlashIndex <= 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.Key[schemeIndex+3+firstSlashIndex:]
|
||||||
|
}
|
||||||
|
|||||||
@@ -81,3 +81,14 @@ func TestItems_Memory2(t *testing.T) {
|
|||||||
t.Log(w, len(i))
|
t.Log(w, len(i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestItem_RequestURI(t *testing.T) {
|
||||||
|
for _, u := range []string{
|
||||||
|
"https://goedge.cn/hello/world",
|
||||||
|
"https://goedge.cn:8080/hello/world",
|
||||||
|
"https://goedge.cn/hello/world?v=1&t=123",
|
||||||
|
} {
|
||||||
|
var item = &Item{Key: u}
|
||||||
|
t.Log(u, "=>", item.RequestURI())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -160,6 +160,7 @@ func (this *FileList) CleanPrefix(prefix string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
|
// TODO 需要优化
|
||||||
this.memoryCache.Clean()
|
this.memoryCache.Clean()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -172,6 +173,46 @@ func (this *FileList) CleanPrefix(prefix string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CleanMatchKey 清理通配符匹配的缓存数据,类似于 https://*.example.com/hello
|
||||||
|
func (this *FileList) CleanMatchKey(key string) error {
|
||||||
|
if len(key) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
// TODO 需要优化
|
||||||
|
this.memoryCache.Clean()
|
||||||
|
}()
|
||||||
|
|
||||||
|
for _, db := range this.dbList {
|
||||||
|
err := db.CleanMatchKey(key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CleanMatchPrefix 清理通配符匹配的缓存数据,类似于 https://*.example.com/prefix/
|
||||||
|
func (this *FileList) CleanMatchPrefix(prefix string) error {
|
||||||
|
if len(prefix) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
// TODO 需要优化
|
||||||
|
this.memoryCache.Clean()
|
||||||
|
}()
|
||||||
|
|
||||||
|
for _, db := range this.dbList {
|
||||||
|
err := db.CleanMatchPrefix(prefix)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (this *FileList) Remove(hash string) error {
|
func (this *FileList) Remove(hash string) error {
|
||||||
_, err := this.remove(hash)
|
_, err := this.remove(hash)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import (
|
|||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"net"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
@@ -389,6 +391,85 @@ func (this *FileListDB) CleanPrefix(prefix string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *FileListDB) CleanMatchKey(key string) error {
|
||||||
|
if !this.isReady {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 忽略 @GOEDGE_
|
||||||
|
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 queryKey = strings.ReplaceAll(key, "%", "\\%")
|
||||||
|
queryKey = strings.ReplaceAll(queryKey, "_", "\\_")
|
||||||
|
queryKey = strings.Replace(queryKey, "*", "%", 1)
|
||||||
|
|
||||||
|
// TODO 检查大批量数据下的操作性能
|
||||||
|
var staleLife = 600 // TODO 需要可以设置
|
||||||
|
var unixTime = utils.UnixTime() // 只删除当前的,不删除新的
|
||||||
|
|
||||||
|
_, err = this.writeDB.Exec(`UPDATE "`+this.itemsTableName+`" SET "expiredAt"=0, "staleAt"=? WHERE "host" GLOB ? AND "host" NOT GLOB ? AND "key" LIKE ? ESCAPE '\'`, unixTime+int64(staleLife), host, "*."+host, queryKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = this.writeDB.Exec(`UPDATE "`+this.itemsTableName+`" SET "expiredAt"=0, "staleAt"=? WHERE "host" GLOB ? AND "host" NOT GLOB ? AND "key" LIKE ? ESCAPE '\'`, unixTime+int64(staleLife), host, "*."+host, queryKey+SuffixAll+"%")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *FileListDB) CleanMatchPrefix(prefix string) error {
|
||||||
|
if !this.isReady {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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 queryPrefix = strings.ReplaceAll(prefix, "%", "\\%")
|
||||||
|
queryPrefix = strings.ReplaceAll(queryPrefix, "_", "\\_")
|
||||||
|
queryPrefix = strings.Replace(queryPrefix, "*", "%", 1)
|
||||||
|
queryPrefix += "%"
|
||||||
|
|
||||||
|
// TODO 检查大批量数据下的操作性能
|
||||||
|
var staleLife = 600 // TODO 需要可以设置
|
||||||
|
var unixTime = utils.UnixTime() // 只删除当前的,不删除新的
|
||||||
|
|
||||||
|
_, err = this.writeDB.Exec(`UPDATE "`+this.itemsTableName+`" SET "expiredAt"=0, "staleAt"=? WHERE "host" GLOB ? AND "host" NOT GLOB ? AND "key" LIKE ? ESCAPE '\'`, unixTime+int64(staleLife), host, "*."+host, queryPrefix)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (this *FileListDB) CleanAll() error {
|
func (this *FileListDB) CleanAll() error {
|
||||||
if !this.isReady {
|
if !this.isReady {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -47,3 +47,41 @@ func TestFileListDB_IncreaseHitAsync(t *testing.T) {
|
|||||||
// wait transaction
|
// wait transaction
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFileListDB_CleanMatchKey(t *testing.T) {
|
||||||
|
var db = caches.NewFileListDB()
|
||||||
|
err := db.Open(Tea.Root + "/data/cache-db-large.db")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = db.Init()
|
||||||
|
|
||||||
|
err = db.CleanMatchKey("https://*.goedge.cn/large-text")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = db.CleanMatchKey("https://*.goedge.cn:1234/large-text?%2B____")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFileListDB_CleanMatchPrefix(t *testing.T) {
|
||||||
|
var db = caches.NewFileListDB()
|
||||||
|
err := db.Open(Tea.Root + "/data/cache-db-large.db")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = db.Init()
|
||||||
|
|
||||||
|
err = db.CleanMatchPrefix("https://*.goedge.cn/large-text")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = db.CleanMatchPrefix("https://*.goedge.cn:1234/large-text?%2B____")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,6 +18,12 @@ type ListInterface interface {
|
|||||||
// CleanPrefix 清除某个前缀的缓存
|
// CleanPrefix 清除某个前缀的缓存
|
||||||
CleanPrefix(prefix string) error
|
CleanPrefix(prefix string) error
|
||||||
|
|
||||||
|
// CleanMatchKey 清除通配符匹配的Key
|
||||||
|
CleanMatchKey(key string) error
|
||||||
|
|
||||||
|
// CleanMatchPrefix 清除通配符匹配的前缀
|
||||||
|
CleanMatchPrefix(prefix string) error
|
||||||
|
|
||||||
// Remove 删除内容
|
// Remove 删除内容
|
||||||
Remove(hash string) error
|
Remove(hash string) error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
package caches
|
package caches
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/zero"
|
"github.com/TeaOSLab/EdgeNode/internal/zero"
|
||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
|
"net"
|
||||||
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -146,6 +149,82 @@ func (this *MemoryList) CleanPrefix(prefix string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
item.ExpiredAt = 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) {
|
||||||
|
item.ExpiredAt = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (this *MemoryList) Remove(hash string) error {
|
func (this *MemoryList) Remove(hash string) error {
|
||||||
this.locker.Lock()
|
this.locker.Lock()
|
||||||
|
|
||||||
|
|||||||
@@ -841,6 +841,19 @@ func (this *FileStorage) Purge(keys []string, urlType string) error {
|
|||||||
// 目录
|
// 目录
|
||||||
if urlType == "dir" {
|
if urlType == "dir" {
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
|
// 检查是否有通配符 http(s)://*.example.com
|
||||||
|
var schemeIndex = strings.Index(key, "://")
|
||||||
|
if schemeIndex > 0 {
|
||||||
|
var keyRight = key[schemeIndex+3:]
|
||||||
|
if strings.HasPrefix(keyRight, "*.") {
|
||||||
|
err := this.list.CleanMatchPrefix(key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err := this.list.CleanPrefix(key)
|
err := this.list.CleanPrefix(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -851,6 +864,20 @@ func (this *FileStorage) Purge(keys []string, urlType string) error {
|
|||||||
|
|
||||||
// URL
|
// URL
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
|
// 检查是否有通配符 http(s)://*.example.com
|
||||||
|
var schemeIndex = strings.Index(key, "://")
|
||||||
|
if schemeIndex > 0 {
|
||||||
|
var keyRight = key[schemeIndex+3:]
|
||||||
|
if strings.HasPrefix(keyRight, "*.") {
|
||||||
|
err := this.list.CleanMatchKey(key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 普通的Key
|
||||||
hash, path, _ := this.keyPath(key)
|
hash, path, _ := this.keyPath(key)
|
||||||
err := this.removeCacheFile(path)
|
err := this.removeCacheFile(path)
|
||||||
if err != nil && !os.IsNotExist(err) {
|
if err != nil && !os.IsNotExist(err) {
|
||||||
@@ -1206,6 +1233,7 @@ func (this *FileStorage) hotLoop() {
|
|||||||
memoryStorage.AddToList(&Item{
|
memoryStorage.AddToList(&Item{
|
||||||
Type: writer.ItemType(),
|
Type: writer.ItemType(),
|
||||||
Key: item.Key,
|
Key: item.Key,
|
||||||
|
Host: ParseHost(item.Key),
|
||||||
ExpiredAt: expiresAt,
|
ExpiredAt: expiresAt,
|
||||||
HeaderSize: writer.HeaderSize(),
|
HeaderSize: writer.HeaderSize(),
|
||||||
BodySize: writer.BodySize(),
|
BodySize: writer.BodySize(),
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package caches
|
package caches
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/goman"
|
"github.com/TeaOSLab/EdgeNode/internal/goman"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
||||||
@@ -17,6 +16,7 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
@@ -230,10 +230,10 @@ func (this *MemoryStorage) openWriter(key string, expiresAt int64, status int, h
|
|||||||
|
|
||||||
// Delete 删除某个键值对应的缓存
|
// Delete 删除某个键值对应的缓存
|
||||||
func (this *MemoryStorage) Delete(key string) error {
|
func (this *MemoryStorage) Delete(key string) error {
|
||||||
hash := this.hash(key)
|
var hash = this.hash(key)
|
||||||
this.locker.Lock()
|
this.locker.Lock()
|
||||||
delete(this.valuesMap, hash)
|
delete(this.valuesMap, hash)
|
||||||
_ = this.list.Remove(fmt.Sprintf("%d", hash))
|
_ = this.list.Remove(types.String(hash))
|
||||||
this.locker.Unlock()
|
this.locker.Unlock()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -263,6 +263,19 @@ func (this *MemoryStorage) Purge(keys []string, urlType string) error {
|
|||||||
// 目录
|
// 目录
|
||||||
if urlType == "dir" {
|
if urlType == "dir" {
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
|
// 检查是否有通配符 http(s)://*.example.com
|
||||||
|
var schemeIndex = strings.Index(key, "://")
|
||||||
|
if schemeIndex > 0 {
|
||||||
|
var keyRight = key[schemeIndex+3:]
|
||||||
|
if strings.HasPrefix(keyRight, "*.") {
|
||||||
|
err := this.list.CleanMatchPrefix(key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err := this.list.CleanPrefix(key)
|
err := this.list.CleanPrefix(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -273,6 +286,19 @@ func (this *MemoryStorage) Purge(keys []string, urlType string) error {
|
|||||||
|
|
||||||
// URL
|
// URL
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
|
// 检查是否有通配符 http(s)://*.example.com
|
||||||
|
var schemeIndex = strings.Index(key, "://")
|
||||||
|
if schemeIndex > 0 {
|
||||||
|
var keyRight = key[schemeIndex+3:]
|
||||||
|
if strings.HasPrefix(keyRight, "*.") {
|
||||||
|
err := this.list.CleanMatchKey(key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err := this.Delete(key)
|
err := this.Delete(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -336,7 +362,12 @@ func (this *MemoryStorage) CanUpdatePolicy(newPolicy *serverconfigs.HTTPCachePol
|
|||||||
// AddToList 将缓存添加到列表
|
// AddToList 将缓存添加到列表
|
||||||
func (this *MemoryStorage) AddToList(item *Item) {
|
func (this *MemoryStorage) AddToList(item *Item) {
|
||||||
item.MetaSize = int64(len(item.Key)) + 128 /** 128是我们评估的数据结构的长度 **/
|
item.MetaSize = int64(len(item.Key)) + 128 /** 128是我们评估的数据结构的长度 **/
|
||||||
hash := fmt.Sprintf("%d", this.hash(item.Key))
|
var hash = types.String(this.hash(item.Key))
|
||||||
|
|
||||||
|
if len(item.Host) == 0 {
|
||||||
|
item.Host = ParseHost(item.Key)
|
||||||
|
}
|
||||||
|
|
||||||
_ = this.list.Add(hash, item)
|
_ = this.list.Add(hash, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,7 +464,7 @@ func (this *MemoryStorage) startFlush() {
|
|||||||
var statCount = 0
|
var statCount = 0
|
||||||
var writeDelayMS float64 = 0
|
var writeDelayMS float64 = 0
|
||||||
|
|
||||||
for hash := range this.dirtyChan {
|
for key := range this.dirtyChan {
|
||||||
statCount++
|
statCount++
|
||||||
|
|
||||||
if statCount == 100 {
|
if statCount == 100 {
|
||||||
@@ -455,7 +486,7 @@ func (this *MemoryStorage) startFlush() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.flushItem(hash)
|
this.flushItem(key)
|
||||||
|
|
||||||
if writeDelayMS > 0 {
|
if writeDelayMS > 0 {
|
||||||
time.Sleep(time.Duration(writeDelayMS) * time.Millisecond)
|
time.Sleep(time.Duration(writeDelayMS) * time.Millisecond)
|
||||||
@@ -513,6 +544,7 @@ func (this *MemoryStorage) flushItem(key string) {
|
|||||||
this.parentStorage.AddToList(&Item{
|
this.parentStorage.AddToList(&Item{
|
||||||
Type: writer.ItemType(),
|
Type: writer.ItemType(),
|
||||||
Key: key,
|
Key: key,
|
||||||
|
Host: ParseHost(key),
|
||||||
ExpiredAt: item.ExpiresAt,
|
ExpiredAt: item.ExpiresAt,
|
||||||
HeaderSize: writer.HeaderSize(),
|
HeaderSize: writer.HeaderSize(),
|
||||||
BodySize: writer.BodySize(),
|
BodySize: writer.BodySize(),
|
||||||
@@ -542,7 +574,7 @@ func (this *MemoryStorage) memoryCapacityBytes() int64 {
|
|||||||
func (this *MemoryStorage) deleteWithoutLocker(key string) error {
|
func (this *MemoryStorage) deleteWithoutLocker(key string) error {
|
||||||
hash := this.hash(key)
|
hash := this.hash(key)
|
||||||
delete(this.valuesMap, hash)
|
delete(this.valuesMap, hash)
|
||||||
_ = this.list.Remove(fmt.Sprintf("%d", hash))
|
_ = this.list.Remove(types.String(hash))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
30
internal/caches/utils.go
Normal file
30
internal/caches/utils.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package caches
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ParseHost(key string) string {
|
||||||
|
var schemeIndex = strings.Index(key, "://")
|
||||||
|
if schemeIndex <= 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var firstSlashIndex = strings.Index(key[schemeIndex+3:], "/")
|
||||||
|
if firstSlashIndex <= 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var host = key[schemeIndex+3 : schemeIndex+3+firstSlashIndex]
|
||||||
|
|
||||||
|
hostPart, _, err := net.SplitHostPort(host)
|
||||||
|
if err == nil && len(hostPart) > 0 {
|
||||||
|
host = configutils.QuoteIP(hostPart)
|
||||||
|
}
|
||||||
|
|
||||||
|
return host
|
||||||
|
}
|
||||||
51
internal/caches/utils_test.go
Normal file
51
internal/caches/utils_test.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package caches_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/caches"
|
||||||
|
"github.com/cespare/xxhash"
|
||||||
|
"github.com/iwind/TeaGo/types"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseHost(t *testing.T) {
|
||||||
|
for _, u := range []string{
|
||||||
|
"https://goedge.cn/hello/world",
|
||||||
|
"https://goedge.cn:8080/hello/world",
|
||||||
|
"https://goedge.cn/hello/world?v=1&t=123",
|
||||||
|
"https://[::1]:1234/hello/world?v=1&t=123",
|
||||||
|
"https://[::1]/hello/world?v=1&t=123",
|
||||||
|
"https://127.0.0.1/hello/world?v=1&t=123",
|
||||||
|
"https:/hello/world?v=1&t=123",
|
||||||
|
"123456",
|
||||||
|
} {
|
||||||
|
t.Log(u, "=>", caches.ParseHost(u))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUintString(t *testing.T) {
|
||||||
|
t.Log(strconv.FormatUint(xxhash.Sum64String("https://goedge.cn/"), 10))
|
||||||
|
t.Log(strconv.FormatUint(123456789, 10))
|
||||||
|
t.Log(fmt.Sprintf("%d", 1234567890123))
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkUint_String(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_ = strconv.FormatUint(1234567890123, 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkUint_String2(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_ = types.String(1234567890123)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkUint_String3(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_ = fmt.Sprintf("%d", 1234567890123)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user