2024-05-17 18:30:33 +08:00
|
|
|
|
// Copyright 2021 GoEdge goedge.cdn@gmail.com. All rights reserved.
|
2021-05-19 12:07:35 +08:00
|
|
|
|
|
|
|
|
|
|
package caches
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"database/sql"
|
2023-09-15 18:14:58 +08:00
|
|
|
|
"errors"
|
2021-05-25 11:06:43 +08:00
|
|
|
|
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
2023-03-07 16:22:32 +08:00
|
|
|
|
"github.com/TeaOSLab/EdgeNode/internal/utils/dbs"
|
2023-10-01 20:30:07 +08:00
|
|
|
|
"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
|
2022-03-15 18:32:39 +08:00
|
|
|
|
"github.com/TeaOSLab/EdgeNode/internal/utils/fnv"
|
2024-04-29 22:36:26 +08:00
|
|
|
|
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
|
2024-05-11 09:23:54 +08:00
|
|
|
|
"github.com/TeaOSLab/EdgeNode/internal/utils/goman"
|
2024-05-08 11:10:56 +08:00
|
|
|
|
"github.com/TeaOSLab/EdgeNode/internal/utils/ttlcache"
|
2024-05-11 09:23:54 +08:00
|
|
|
|
"github.com/TeaOSLab/EdgeNode/internal/utils/zero"
|
2021-12-17 11:54:27 +08:00
|
|
|
|
"github.com/iwind/TeaGo/types"
|
2021-05-25 11:06:43 +08:00
|
|
|
|
"os"
|
2023-10-10 22:08:42 +08:00
|
|
|
|
"strings"
|
2023-10-02 16:05:42 +08:00
|
|
|
|
"sync"
|
2021-05-19 12:07:35 +08:00
|
|
|
|
"time"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2022-03-16 16:20:53 +08:00
|
|
|
|
const CountFileDB = 20
|
2022-03-15 18:32:39 +08:00
|
|
|
|
|
2024-03-21 08:37:32 +08:00
|
|
|
|
// SQLiteFileList 文件缓存列表管理
|
|
|
|
|
|
type SQLiteFileList struct {
|
2022-03-15 18:32:39 +08:00
|
|
|
|
dir string
|
2024-03-21 08:37:32 +08:00
|
|
|
|
dbList [CountFileDB]*SQLiteFileListDB
|
2021-05-19 12:07:35 +08:00
|
|
|
|
|
|
|
|
|
|
onAdd func(item *Item)
|
|
|
|
|
|
onRemove func(item *Item)
|
2021-06-13 17:37:57 +08:00
|
|
|
|
|
2023-10-05 08:41:07 +08:00
|
|
|
|
memoryCache *ttlcache.Cache[zero.Zero]
|
2022-03-15 18:32:39 +08:00
|
|
|
|
|
|
|
|
|
|
// 老数据库地址
|
|
|
|
|
|
oldDir string
|
2021-05-19 12:07:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func NewSQLiteFileList(dir string) ListInterface {
|
|
|
|
|
|
return &SQLiteFileList{
|
2021-08-21 21:06:48 +08:00
|
|
|
|
dir: dir,
|
2023-10-05 08:41:07 +08:00
|
|
|
|
memoryCache: ttlcache.NewCache[zero.Zero](),
|
2021-08-21 21:06:48 +08:00
|
|
|
|
}
|
2021-05-19 12:07:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) SetOldDir(oldDir string) {
|
2022-03-15 18:32:39 +08:00
|
|
|
|
this.oldDir = oldDir
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) Init() error {
|
2021-05-25 11:06:43 +08:00
|
|
|
|
// 检查目录是否存在
|
|
|
|
|
|
_, err := os.Stat(this.dir)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
err = os.MkdirAll(this.dir, 0777)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
remotelogs.Println("CACHE", "create cache dir '"+this.dir+"'")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-07-21 11:55:08 +08:00
|
|
|
|
var dir = this.dir
|
|
|
|
|
|
if dir == "/" {
|
|
|
|
|
|
// 防止sqlite提示authority错误
|
|
|
|
|
|
dir = ""
|
|
|
|
|
|
}
|
2021-05-19 12:07:35 +08:00
|
|
|
|
|
2022-03-15 18:32:39 +08:00
|
|
|
|
remotelogs.Println("CACHE", "loading database from '"+dir+"' ...")
|
2023-10-02 16:05:42 +08:00
|
|
|
|
var wg = &sync.WaitGroup{}
|
|
|
|
|
|
var locker = sync.Mutex{}
|
|
|
|
|
|
var lastErr error
|
2021-06-13 17:37:57 +08:00
|
|
|
|
|
2023-10-02 16:05:42 +08:00
|
|
|
|
for i := 0; i < CountFileDB; i++ {
|
|
|
|
|
|
wg.Add(1)
|
|
|
|
|
|
go func(i int) {
|
|
|
|
|
|
defer wg.Done()
|
|
|
|
|
|
|
2024-03-21 08:37:32 +08:00
|
|
|
|
var db = NewSQLiteFileListDB()
|
2023-10-02 19:48:11 +08:00
|
|
|
|
dbErr := db.Open(dir + "/db-" + types.String(i) + ".db")
|
|
|
|
|
|
if dbErr != nil {
|
|
|
|
|
|
lastErr = dbErr
|
2023-10-02 16:05:42 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-10-02 19:48:11 +08:00
|
|
|
|
dbErr = db.Init()
|
|
|
|
|
|
if dbErr != nil {
|
|
|
|
|
|
lastErr = dbErr
|
2023-10-02 16:05:42 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
locker.Lock()
|
|
|
|
|
|
this.dbList[i] = db
|
|
|
|
|
|
locker.Unlock()
|
|
|
|
|
|
}(i)
|
|
|
|
|
|
}
|
|
|
|
|
|
wg.Wait()
|
2021-05-19 12:07:35 +08:00
|
|
|
|
|
2023-10-02 16:05:42 +08:00
|
|
|
|
if lastErr != nil {
|
|
|
|
|
|
return lastErr
|
2021-12-16 17:27:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-03-15 18:32:39 +08:00
|
|
|
|
// 升级老版本数据库
|
|
|
|
|
|
goman.New(func() {
|
|
|
|
|
|
this.upgradeOldDB()
|
|
|
|
|
|
})
|
2021-12-19 14:15:17 +08:00
|
|
|
|
|
2021-05-19 12:07:35 +08:00
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) Reset() error {
|
2021-06-15 10:47:40 +08:00
|
|
|
|
// 不做任何事情
|
2021-05-19 12:07:35 +08:00
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) Add(hash string, item *Item) error {
|
2022-08-20 11:47:57 +08:00
|
|
|
|
var db = this.GetDB(hash)
|
2021-06-13 17:51:04 +08:00
|
|
|
|
|
2022-03-15 18:32:39 +08:00
|
|
|
|
if !db.IsReady() {
|
|
|
|
|
|
return nil
|
2021-12-16 17:27:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-07-08 20:00:27 +08:00
|
|
|
|
err := db.AddSync(hash, item)
|
2021-05-19 12:07:35 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-22 08:23:22 +08:00
|
|
|
|
this.memoryCache.Write(hash, zero.Zero{}, this.maxExpiresAtForMemoryCache(item.ExpiresAt))
|
2021-05-19 12:07:35 +08:00
|
|
|
|
|
|
|
|
|
|
if this.onAdd != nil {
|
|
|
|
|
|
this.onAdd(item)
|
|
|
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-04 08:28:14 +08:00
|
|
|
|
func (this *SQLiteFileList) Exist(hash string) (bool, int64, error) {
|
2022-08-20 11:47:57 +08:00
|
|
|
|
var db = this.GetDB(hash)
|
2022-03-15 18:32:39 +08:00
|
|
|
|
|
|
|
|
|
|
if !db.IsReady() {
|
2024-04-04 08:28:14 +08:00
|
|
|
|
return false, -1, nil
|
2021-06-13 17:51:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-08-20 11:47:57 +08:00
|
|
|
|
// 如果Hash列表里不存在,那么必然不存在
|
|
|
|
|
|
if !db.hashMap.Exist(hash) {
|
2024-04-04 08:28:14 +08:00
|
|
|
|
return false, -1, nil
|
2022-08-20 11:47:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-03-20 16:20:40 +08:00
|
|
|
|
var item = this.memoryCache.Read(hash)
|
2021-08-21 21:06:48 +08:00
|
|
|
|
if item != nil {
|
2024-04-04 08:28:14 +08:00
|
|
|
|
return true, -1, nil
|
2021-08-21 21:06:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-03-20 16:20:40 +08:00
|
|
|
|
var row = db.existsByHashStmt.QueryRow(hash, time.Now().Unix())
|
|
|
|
|
|
if row.Err() != nil {
|
2024-04-04 08:28:14 +08:00
|
|
|
|
return false, -1, nil
|
2022-03-20 16:20:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var expiredAt int64
|
|
|
|
|
|
err := row.Scan(&expiredAt)
|
2021-05-19 12:07:35 +08:00
|
|
|
|
if err != nil {
|
2023-09-15 18:14:58 +08:00
|
|
|
|
if errors.Is(err, sql.ErrNoRows) {
|
2022-03-20 16:20:40 +08:00
|
|
|
|
err = nil
|
2022-03-16 16:20:53 +08:00
|
|
|
|
}
|
2024-04-04 08:28:14 +08:00
|
|
|
|
return false, -1, err
|
2021-05-19 12:07:35 +08:00
|
|
|
|
}
|
2024-03-22 10:05:01 +08:00
|
|
|
|
|
2024-04-04 08:28:14 +08:00
|
|
|
|
if expiredAt <= fasttime.Now().Unix() {
|
|
|
|
|
|
return false, -1, nil
|
2024-03-22 10:05:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-10-05 08:41:07 +08:00
|
|
|
|
this.memoryCache.Write(hash, zero.Zero{}, this.maxExpiresAtForMemoryCache(expiredAt))
|
2024-04-04 08:28:14 +08:00
|
|
|
|
return true, -1, nil
|
2021-05-19 12:07:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) ExistQuick(hash string) (isReady bool, found bool) {
|
2023-09-15 18:14:58 +08:00
|
|
|
|
var db = this.GetDB(hash)
|
|
|
|
|
|
|
|
|
|
|
|
if !db.IsReady() || !db.HashMapIsLoaded() {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
isReady = true
|
|
|
|
|
|
found = db.hashMap.Exist(hash)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-06-13 17:37:57 +08:00
|
|
|
|
// CleanPrefix 清理某个前缀的缓存数据
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) CleanPrefix(prefix string) error {
|
2021-05-19 12:07:35 +08:00
|
|
|
|
if len(prefix) == 0 {
|
2021-06-13 17:37:57 +08:00
|
|
|
|
return nil
|
2021-05-19 12:07:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-08-26 15:48:09 +08:00
|
|
|
|
defer func() {
|
2022-11-26 11:05:46 +08:00
|
|
|
|
// TODO 需要优化
|
2021-08-26 15:48:09 +08:00
|
|
|
|
this.memoryCache.Clean()
|
|
|
|
|
|
}()
|
|
|
|
|
|
|
2022-03-15 18:32:39 +08:00
|
|
|
|
for _, db := range this.dbList {
|
|
|
|
|
|
err := db.CleanPrefix(prefix)
|
2021-05-19 12:07:35 +08:00
|
|
|
|
if err != nil {
|
2021-06-13 17:37:57 +08:00
|
|
|
|
return err
|
|
|
|
|
|
}
|
2021-05-19 12:07:35 +08:00
|
|
|
|
}
|
2022-03-15 18:32:39 +08:00
|
|
|
|
return nil
|
2021-05-19 12:07:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-11-26 11:05:46 +08:00
|
|
|
|
// CleanMatchKey 清理通配符匹配的缓存数据,类似于 https://*.example.com/hello
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) CleanMatchKey(key string) error {
|
2022-11-26 11:05:46 +08:00
|
|
|
|
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/
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) CleanMatchPrefix(prefix string) error {
|
2022-11-26 11:05:46 +08:00
|
|
|
|
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
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) Remove(hash string) error {
|
2023-10-10 22:08:42 +08:00
|
|
|
|
_, err := this.remove(hash, false)
|
2022-03-15 18:32:39 +08:00
|
|
|
|
return err
|
2021-05-19 12:07:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Purge 清理过期的缓存
|
|
|
|
|
|
// count 每次遍历的最大数量,控制此数字可以保证每次清理的时候不用花太多时间
|
|
|
|
|
|
// callback 每次发现过期key的调用
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) Purge(count int, callback func(hash string) error) (int, error) {
|
2022-03-15 18:32:39 +08:00
|
|
|
|
count /= CountFileDB
|
2021-05-19 12:07:35 +08:00
|
|
|
|
if count <= 0 {
|
2022-03-15 18:32:39 +08:00
|
|
|
|
count = 100
|
2021-05-19 12:07:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-11-13 21:30:24 +08:00
|
|
|
|
var countFound = 0
|
2022-03-15 18:32:39 +08:00
|
|
|
|
for _, db := range this.dbList {
|
|
|
|
|
|
hashStrings, err := db.ListExpiredItems(count)
|
2021-11-13 21:30:24 +08:00
|
|
|
|
if err != nil {
|
2022-03-15 18:32:39 +08:00
|
|
|
|
return 0, nil
|
2021-11-13 21:30:24 +08:00
|
|
|
|
}
|
2023-10-10 22:08:42 +08:00
|
|
|
|
|
|
|
|
|
|
if len(hashStrings) == 0 {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-03-15 18:32:39 +08:00
|
|
|
|
countFound += len(hashStrings)
|
2021-11-13 21:30:24 +08:00
|
|
|
|
|
2022-03-15 18:32:39 +08:00
|
|
|
|
// 不在 rows.Next() 循环中操作是为了避免死锁
|
|
|
|
|
|
for _, hash := range hashStrings {
|
2023-10-10 22:08:42 +08:00
|
|
|
|
_, err = this.remove(hash, true)
|
2022-03-15 18:32:39 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return 0, err
|
|
|
|
|
|
}
|
2021-11-13 21:30:24 +08:00
|
|
|
|
|
2022-03-15 18:32:39 +08:00
|
|
|
|
err = callback(hash)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return 0, err
|
|
|
|
|
|
}
|
2021-11-13 21:30:24 +08:00
|
|
|
|
}
|
2023-10-11 06:31:35 +08:00
|
|
|
|
|
|
|
|
|
|
_, err = db.writeDB.Exec(`DELETE FROM "cacheItems" WHERE "hash" IN ('` + strings.Join(hashStrings, "', '") + `')`)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return 0, err
|
|
|
|
|
|
}
|
2021-11-13 21:30:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return countFound, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) PurgeLFU(count int, callback func(hash string) error) error {
|
2022-03-15 18:32:39 +08:00
|
|
|
|
count /= CountFileDB
|
2021-11-13 21:30:24 +08:00
|
|
|
|
if count <= 0 {
|
2022-03-15 18:32:39 +08:00
|
|
|
|
count = 100
|
2021-05-19 12:07:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-03-15 18:32:39 +08:00
|
|
|
|
for _, db := range this.dbList {
|
|
|
|
|
|
hashStrings, err := db.ListLFUItems(count)
|
2021-05-19 12:07:35 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-10-10 22:08:42 +08:00
|
|
|
|
if len(hashStrings) == 0 {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-03-15 18:32:39 +08:00
|
|
|
|
// 不在 rows.Next() 循环中操作是为了避免死锁
|
|
|
|
|
|
for _, hash := range hashStrings {
|
2023-10-10 22:08:42 +08:00
|
|
|
|
_, err = this.remove(hash, true)
|
2022-03-15 18:32:39 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
2021-05-19 12:07:35 +08:00
|
|
|
|
|
2022-03-15 18:32:39 +08:00
|
|
|
|
err = callback(hash)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
2021-05-19 12:07:35 +08:00
|
|
|
|
}
|
2023-10-11 06:31:35 +08:00
|
|
|
|
|
|
|
|
|
|
_, err = db.writeDB.Exec(`DELETE FROM "cacheItems" WHERE "hash" IN ('` + strings.Join(hashStrings, "', '") + `')`)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
2021-05-19 12:07:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) CleanAll() error {
|
2022-03-15 18:32:39 +08:00
|
|
|
|
defer this.memoryCache.Clean()
|
2021-06-13 17:51:04 +08:00
|
|
|
|
|
2022-03-15 18:32:39 +08:00
|
|
|
|
for _, db := range this.dbList {
|
|
|
|
|
|
err := db.CleanAll()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
2021-05-19 12:07:35 +08:00
|
|
|
|
}
|
2022-03-15 18:32:39 +08:00
|
|
|
|
|
2021-05-19 12:07:35 +08:00
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) Stat(check func(hash string) bool) (*Stat, error) {
|
2022-03-15 18:32:39 +08:00
|
|
|
|
var result = &Stat{}
|
2021-06-13 17:51:04 +08:00
|
|
|
|
|
2022-03-15 18:32:39 +08:00
|
|
|
|
for _, db := range this.dbList {
|
|
|
|
|
|
if !db.IsReady() {
|
|
|
|
|
|
return &Stat{}, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 这里不设置过期时间、不使用 check 函数,目的是让查询更快速一些
|
|
|
|
|
|
_ = check
|
|
|
|
|
|
|
2022-08-17 21:04:00 +08:00
|
|
|
|
var row = db.statStmt.QueryRow()
|
2022-03-15 18:32:39 +08:00
|
|
|
|
if row.Err() != nil {
|
|
|
|
|
|
return nil, row.Err()
|
|
|
|
|
|
}
|
|
|
|
|
|
var stat = &Stat{}
|
|
|
|
|
|
err := row.Scan(&stat.Count, &stat.Size, &stat.ValueSize)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
result.Count += stat.Count
|
|
|
|
|
|
result.Size += stat.Size
|
|
|
|
|
|
result.ValueSize += stat.ValueSize
|
2021-05-19 12:07:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-03-15 18:32:39 +08:00
|
|
|
|
return result, nil
|
2021-05-19 12:07:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Count 总数量
|
|
|
|
|
|
// 常用的方法,所以避免直接查询数据库
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) Count() (int64, error) {
|
2023-07-08 20:00:27 +08:00
|
|
|
|
var total int64
|
|
|
|
|
|
for _, db := range this.dbList {
|
|
|
|
|
|
count, err := db.Total()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return 0, err
|
|
|
|
|
|
}
|
|
|
|
|
|
total += count
|
|
|
|
|
|
}
|
|
|
|
|
|
return total, nil
|
2021-05-19 12:07:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-11-13 21:30:24 +08:00
|
|
|
|
// IncreaseHit 增加点击量
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) IncreaseHit(hash string) error {
|
2022-08-20 11:47:57 +08:00
|
|
|
|
var db = this.GetDB(hash)
|
2022-03-15 18:32:39 +08:00
|
|
|
|
|
|
|
|
|
|
if !db.IsReady() {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-08-20 11:47:57 +08:00
|
|
|
|
return db.IncreaseHitAsync(hash)
|
2021-11-13 21:30:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-05-19 12:07:35 +08:00
|
|
|
|
// OnAdd 添加事件
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) OnAdd(f func(item *Item)) {
|
2021-05-19 12:07:35 +08:00
|
|
|
|
this.onAdd = f
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// OnRemove 删除事件
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) OnRemove(f func(item *Item)) {
|
2021-05-19 12:07:35 +08:00
|
|
|
|
this.onRemove = f
|
|
|
|
|
|
}
|
2021-06-13 17:37:57 +08:00
|
|
|
|
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) Close() error {
|
2021-08-29 08:59:32 +08:00
|
|
|
|
this.memoryCache.Destroy()
|
|
|
|
|
|
|
2024-03-24 18:20:42 +08:00
|
|
|
|
var group = goman.NewTaskGroup()
|
2022-03-15 18:32:39 +08:00
|
|
|
|
for _, db := range this.dbList {
|
2024-03-24 18:20:42 +08:00
|
|
|
|
var dbCopy = db
|
|
|
|
|
|
group.Run(func() {
|
|
|
|
|
|
if dbCopy != nil {
|
|
|
|
|
|
_ = dbCopy.Close()
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
2021-06-13 17:37:57 +08:00
|
|
|
|
}
|
2024-03-24 18:20:42 +08:00
|
|
|
|
group.Wait()
|
2022-03-15 18:32:39 +08:00
|
|
|
|
|
2021-06-13 17:37:57 +08:00
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) GetDBIndex(hash string) uint64 {
|
2022-03-16 17:06:26 +08:00
|
|
|
|
return fnv.HashString(hash) % CountFileDB
|
2022-03-15 18:32:39 +08:00
|
|
|
|
}
|
2021-12-19 18:55:54 +08:00
|
|
|
|
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) GetDB(hash string) *SQLiteFileListDB {
|
2022-03-16 17:06:26 +08:00
|
|
|
|
return this.dbList[fnv.HashString(hash)%CountFileDB]
|
2022-03-15 18:32:39 +08:00
|
|
|
|
}
|
2021-11-13 21:30:24 +08:00
|
|
|
|
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) HashMapIsLoaded() bool {
|
2023-09-17 11:43:46 +08:00
|
|
|
|
for _, db := range this.dbList {
|
|
|
|
|
|
if !db.HashMapIsLoaded() {
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) remove(hash string, isDeleted bool) (notFound bool, err error) {
|
2022-08-20 11:47:57 +08:00
|
|
|
|
var db = this.GetDB(hash)
|
2022-03-15 18:32:39 +08:00
|
|
|
|
|
|
|
|
|
|
if !db.IsReady() {
|
|
|
|
|
|
return false, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-08-20 11:47:57 +08:00
|
|
|
|
// HashMap中不存在,则确定不存在
|
|
|
|
|
|
if !db.hashMap.Exist(hash) {
|
|
|
|
|
|
return true, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
defer db.hashMap.Delete(hash)
|
|
|
|
|
|
|
2022-03-15 18:32:39 +08:00
|
|
|
|
// 从缓存中删除
|
|
|
|
|
|
this.memoryCache.Delete(hash)
|
|
|
|
|
|
|
2023-10-10 22:08:42 +08:00
|
|
|
|
if !isDeleted {
|
|
|
|
|
|
err = db.DeleteSync(hash)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return false, db.WrapError(err)
|
|
|
|
|
|
}
|
2022-03-15 18:32:39 +08:00
|
|
|
|
}
|
2021-11-13 21:30:24 +08:00
|
|
|
|
|
2022-03-15 18:32:39 +08:00
|
|
|
|
if this.onRemove != nil {
|
2023-07-08 20:00:27 +08:00
|
|
|
|
// when remove file item, no any extra information needed
|
|
|
|
|
|
this.onRemove(nil)
|
2022-03-15 18:32:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return false, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 升级老版本数据库
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) upgradeOldDB() {
|
2022-03-15 18:32:39 +08:00
|
|
|
|
if len(this.oldDir) == 0 {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
_ = this.UpgradeV3(this.oldDir, false)
|
2021-06-17 21:13:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) UpgradeV3(oldDir string, brokenOnError bool) error {
|
2022-03-15 18:32:39 +08:00
|
|
|
|
// index.db
|
|
|
|
|
|
var indexDBPath = oldDir + "/index.db"
|
|
|
|
|
|
_, err := os.Stat(indexDBPath)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
remotelogs.Println("CACHE", "upgrading local database from '"+oldDir+"' ...")
|
|
|
|
|
|
|
|
|
|
|
|
defer func() {
|
2024-04-29 22:36:26 +08:00
|
|
|
|
_ = fsutils.Remove(indexDBPath)
|
2022-03-15 18:58:56 +08:00
|
|
|
|
remotelogs.Println("CACHE", "upgrading local database finished")
|
2022-03-15 18:32:39 +08:00
|
|
|
|
}()
|
|
|
|
|
|
|
2023-10-06 20:56:27 +08:00
|
|
|
|
db, err := dbs.OpenWriter("file:" + indexDBPath + "?cache=shared&mode=rwc&_journal_mode=WAL&_sync=" + dbs.SyncMode + "&_locking_mode=EXCLUSIVE")
|
2021-06-13 17:37:57 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
2022-03-15 18:32:39 +08:00
|
|
|
|
|
2021-06-13 17:37:57 +08:00
|
|
|
|
defer func() {
|
2022-03-15 18:32:39 +08:00
|
|
|
|
_ = db.Close()
|
2021-06-13 17:37:57 +08:00
|
|
|
|
}()
|
2022-03-15 18:32:39 +08:00
|
|
|
|
|
|
|
|
|
|
var isFinished = false
|
|
|
|
|
|
var offset = 0
|
|
|
|
|
|
var count = 10000
|
|
|
|
|
|
|
|
|
|
|
|
for {
|
|
|
|
|
|
if isFinished {
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
err = func() error {
|
|
|
|
|
|
defer func() {
|
|
|
|
|
|
offset += count
|
|
|
|
|
|
}()
|
|
|
|
|
|
|
2022-03-16 16:20:53 +08:00
|
|
|
|
rows, err := db.Query(`SELECT "hash", "key", "headerSize", "bodySize", "metaSize", "expiredAt", "staleAt", "createdAt", "host", "serverId" FROM "cacheItems_v3" ORDER BY "id" ASC LIMIT ?, ?`, offset, count)
|
2022-03-15 18:32:39 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
defer func() {
|
|
|
|
|
|
_ = rows.Close()
|
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
|
|
var hash = ""
|
|
|
|
|
|
var key = ""
|
|
|
|
|
|
var headerSize int64
|
|
|
|
|
|
var bodySize int64
|
|
|
|
|
|
var metaSize int64
|
|
|
|
|
|
var expiredAt int64
|
|
|
|
|
|
var staleAt int64
|
|
|
|
|
|
var createdAt int64
|
|
|
|
|
|
var host string
|
|
|
|
|
|
var serverId int64
|
|
|
|
|
|
|
|
|
|
|
|
isFinished = true
|
|
|
|
|
|
|
|
|
|
|
|
for rows.Next() {
|
|
|
|
|
|
isFinished = false
|
|
|
|
|
|
|
|
|
|
|
|
err = rows.Scan(&hash, &key, &headerSize, &bodySize, &metaSize, &expiredAt, &staleAt, &createdAt, &host, &serverId)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
if brokenOnError {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
err = this.Add(hash, &Item{
|
|
|
|
|
|
Type: ItemTypeFile,
|
|
|
|
|
|
Key: key,
|
2024-03-22 08:23:22 +08:00
|
|
|
|
ExpiresAt: expiredAt,
|
2022-03-15 18:32:39 +08:00
|
|
|
|
StaleAt: staleAt,
|
|
|
|
|
|
HeaderSize: headerSize,
|
|
|
|
|
|
BodySize: bodySize,
|
|
|
|
|
|
MetaSize: metaSize,
|
|
|
|
|
|
Host: host,
|
|
|
|
|
|
ServerId: serverId,
|
|
|
|
|
|
})
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
if brokenOnError {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}()
|
2021-06-13 17:37:57 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-03-15 18:32:39 +08:00
|
|
|
|
time.Sleep(1 * time.Second)
|
2021-06-13 17:37:57 +08:00
|
|
|
|
}
|
2022-03-15 18:32:39 +08:00
|
|
|
|
|
2021-06-13 17:37:57 +08:00
|
|
|
|
return nil
|
|
|
|
|
|
}
|
2023-10-01 20:30:07 +08:00
|
|
|
|
|
2024-03-21 08:37:32 +08:00
|
|
|
|
func (this *SQLiteFileList) maxExpiresAtForMemoryCache(expiresAt int64) int64 {
|
2023-11-02 14:14:28 +08:00
|
|
|
|
var maxTimestamp = fasttime.Now().Unix() + 3600
|
2023-10-01 20:30:07 +08:00
|
|
|
|
if expiresAt > maxTimestamp {
|
|
|
|
|
|
return maxTimestamp
|
|
|
|
|
|
}
|
|
|
|
|
|
return expiresAt
|
|
|
|
|
|
}
|