Caching tree data to improve performance and reduce disk read and write operations https://github.com/siyuan-note/siyuan/issues/16961

Signed-off-by: Daniel <845765@qq.com>
This commit is contained in:
Daniel 2026-02-02 18:25:52 +08:00
parent 8383a4b3fa
commit 89a595f9c6
No known key found for this signature in database
GPG key ID: 86211BA83DF03017
3 changed files with 67 additions and 2 deletions

54
kernel/cache/tree.go vendored Normal file
View file

@ -0,0 +1,54 @@
// SiYuan - Refactor your thinking
// Copyright (c) 2020-present, b3log.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package cache
import (
"github.com/dgraph-io/ristretto"
)
type treeCacheEntry struct {
raw []byte
}
var (
treeCache, _ = ristretto.NewCache(&ristretto.Config{
NumCounters: 8,
MaxCost: 1024 * 1024 * 200,
BufferItems: 64,
})
)
func GetTreeData(rootID string) (raw []byte, ok bool) {
v, _ := treeCache.Get(rootID)
if nil == v {
return nil, false
}
e := v.(*treeCacheEntry)
return e.raw, true
}
func SetTreeData(rootID string, raw []byte) {
if raw == nil {
return
}
entry := &treeCacheEntry{raw: raw}
treeCache.Set(rootID, entry, int64(len(raw)))
}
func RemoveTreeData(rootID string) {
treeCache.Del(rootID)
}

View file

@ -115,14 +115,23 @@ func batchLoadTrees(boxIDs, paths []string, luteEngine *lute.Lute) (ret []*parse
}
func LoadTree(boxID, p string, luteEngine *lute.Lute) (ret *parse.Tree, err error) {
rootID := util.GetTreeID(p)
if raw, ok := cache.GetTreeData(rootID); ok {
ret, err = LoadTreeByData(raw, boxID, p, luteEngine)
return
}
filePath := filepath.Join(util.DataDir, boxID, p)
data, err := filelock.ReadFile(filePath)
if err != nil {
if nil != err {
logging.LogErrorf("load tree [%s] failed: %s", p, err)
return
}
ret, err = LoadTreeByData(data, boxID, p, luteEngine)
if nil != err {
cache.SetTreeData(rootID, data)
}
return
}
@ -146,7 +155,7 @@ func LoadTreeByData(data []byte, boxID, p string, luteEngine *lute.Lute) (ret *p
// 构造 HPath
hPathBuilder := bytes.Buffer{}
hPathBuilder.WriteString("/")
for i, _ := range parts {
for i := range parts {
var parentAbsPath string
if 0 < i {
parentAbsPath = strings.Join(parts[:i+1], "/")
@ -232,6 +241,7 @@ func WriteTree(tree *parse.Tree) (size uint64, err error) {
util.PushErrMsg(msg, 7000)
}
cache.SetTreeData(tree.ID, data)
afterWriteTree(tree)
return
}

View file

@ -1647,6 +1647,7 @@ func removeDoc0(tree *parse.Tree, childrenDir string) {
treenode.RemoveBlockTreesByPathPrefix(childrenDir)
sql.RemoveTreePathQueue(tree.Box, childrenDir)
cache.RemoveDocIAL(tree.Path)
cache.RemoveTreeData(tree.ID)
return
}