mirror of
https://github.com/siyuan-note/siyuan.git
synced 2026-02-08 00:04:21 +01:00
🎨 Supports cleaning up unreferenced databases https://github.com/siyuan-note/siyuan/issues/11569
Signed-off-by: Daniel <845765@qq.com>
This commit is contained in:
parent
10fb34ab88
commit
6c70144d7c
2 changed files with 98 additions and 4 deletions
|
|
@ -28,6 +28,16 @@ import (
|
|||
"github.com/siyuan-note/siyuan/kernel/util"
|
||||
)
|
||||
|
||||
func removeUnusedAttributeViews(c *gin.Context) {
|
||||
ret := gulu.Ret.NewResult()
|
||||
defer c.JSON(http.StatusOK, ret)
|
||||
|
||||
paths := model.RemoveUnusedAttributeViews()
|
||||
ret.Data = map[string]interface{}{
|
||||
"paths": paths,
|
||||
}
|
||||
}
|
||||
|
||||
func getUnusedAttributeViews(c *gin.Context) {
|
||||
ret := gulu.Ret.NewResult()
|
||||
defer c.JSON(http.StatusOK, ret)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import (
|
|||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/88250/go-humanize"
|
||||
"github.com/88250/gulu"
|
||||
"github.com/88250/lute/ast"
|
||||
"github.com/88250/lute/parse"
|
||||
|
|
@ -45,6 +46,58 @@ import (
|
|||
"github.com/xrash/smetrics"
|
||||
)
|
||||
|
||||
func RemoveUnusedAttributeViews() (ret []string) {
|
||||
ret = []string{}
|
||||
var size int64
|
||||
|
||||
msgId := util.PushMsg(Conf.Language(100), 30*1000)
|
||||
defer func() {
|
||||
msg := fmt.Sprintf(Conf.Language(91), len(ret), humanize.BytesCustomCeil(uint64(size), 2))
|
||||
util.PushUpdateMsg(msgId, msg, 7000)
|
||||
}()
|
||||
|
||||
unusedAttributeViews := UnusedAttributeViews()
|
||||
|
||||
historyDir, err := GetHistoryDir(HistoryOpClean)
|
||||
if err != nil {
|
||||
logging.LogErrorf("get history dir failed: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, unusedAvID := range unusedAttributeViews {
|
||||
srcPath := filepath.Join(util.DataDir, "storage", "av", unusedAvID+".json")
|
||||
if filelock.IsExist(srcPath) {
|
||||
historyPath := filepath.Join(historyDir, "storage", "av", unusedAvID+".json")
|
||||
if err = filelock.Copy(srcPath, historyPath); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, unusedAvID := range unusedAttributeViews {
|
||||
absPath := filepath.Join(util.DataDir, "storage", "av", unusedAvID+".json")
|
||||
if filelock.IsExist(absPath) {
|
||||
info, statErr := os.Stat(absPath)
|
||||
if statErr == nil {
|
||||
size += info.Size()
|
||||
}
|
||||
|
||||
if removeErr := filelock.RemoveWithoutFatal(absPath); removeErr != nil {
|
||||
logging.LogErrorf("remove unused av [%s] failed: %s", absPath, removeErr)
|
||||
util.PushErrMsg(fmt.Sprintf("%s", removeErr), 7000)
|
||||
return
|
||||
}
|
||||
}
|
||||
ret = append(ret, absPath)
|
||||
}
|
||||
if 0 < len(ret) {
|
||||
IncSync()
|
||||
}
|
||||
|
||||
indexHistoryDir(filepath.Base(historyDir), util.NewLute())
|
||||
return
|
||||
}
|
||||
|
||||
func UnusedAttributeViews() (ret []string) {
|
||||
defer logging.Recover()
|
||||
ret = []string{}
|
||||
|
|
@ -54,7 +107,7 @@ func UnusedAttributeViews() (ret []string) {
|
|||
return
|
||||
}
|
||||
|
||||
referencedAvIDs := map[string]bool{}
|
||||
docReferencedAvIDs := map[string]bool{}
|
||||
luteEngine := util.NewLute()
|
||||
boxes := Conf.GetBoxes()
|
||||
for _, box := range boxes {
|
||||
|
|
@ -70,7 +123,7 @@ func UnusedAttributeViews() (ret []string) {
|
|||
}
|
||||
for _, tree := range trees {
|
||||
for _, id := range getAvIDs(tree, allAvIDs) {
|
||||
referencedAvIDs[id] = true
|
||||
docReferencedAvIDs[id] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -78,11 +131,12 @@ func UnusedAttributeViews() (ret []string) {
|
|||
|
||||
templateAvIDs := search.FindAllMatchedTargets(filepath.Join(util.DataDir, "templates"), allAvIDs)
|
||||
for _, id := range templateAvIDs {
|
||||
referencedAvIDs[id] = true
|
||||
docReferencedAvIDs[id] = true
|
||||
}
|
||||
|
||||
checkedAvIDs := map[string]bool{}
|
||||
for _, id := range allAvIDs {
|
||||
if !referencedAvIDs[id] {
|
||||
if !docReferencedAvIDs[id] && !isRelatedSrcAvDocReferenced(id, docReferencedAvIDs, checkedAvIDs) {
|
||||
ret = append(ret, id)
|
||||
}
|
||||
}
|
||||
|
|
@ -91,6 +145,36 @@ func UnusedAttributeViews() (ret []string) {
|
|||
return
|
||||
}
|
||||
|
||||
func isRelatedSrcAvDocReferenced(destAvID string, docReferencedAvIDs, checkedAvIDs map[string]bool) bool {
|
||||
if checkedAvIDs[destAvID] {
|
||||
if docReferencedAvIDs[destAvID] {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
checkedAvIDs[destAvID] = true
|
||||
|
||||
srcAvIDs := av.GetSrcAvIDs(destAvID)
|
||||
srcAvIDs = gulu.Str.RemoveElem(srcAvIDs, destAvID) // 忽略自身关联
|
||||
if 1 > len(srcAvIDs) {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, srcAvID := range srcAvIDs {
|
||||
if docReferencedAvIDs[srcAvID] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// 递归检查间接关联的 av
|
||||
for _, srcAvID := range srcAvIDs {
|
||||
if isRelatedSrcAvDocReferenced(srcAvID, docReferencedAvIDs, checkedAvIDs) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func getAvIDs(tree *parse.Tree, allAvIDs []string) (ret []string) {
|
||||
ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
|
||||
if !entering {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue