From 675ad65bd14d3001d49a17a207f18cd0ec51c026 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Fri, 21 Jun 2024 23:07:26 +0800 Subject: [PATCH] :technologist: Add internal kernel API `/api/attr/batchGetBlockAttrs` https://github.com/siyuan-note/siyuan/issues/11786 --- kernel/api/attr.go | 18 ++++++++++ kernel/api/router.go | 1 + kernel/model/attribute_view.go | 12 +++---- kernel/model/blockial.go | 61 +++++++++++++++++++++++++--------- kernel/treenode/blocktree.go | 21 ++++++++++++ 5 files changed, 92 insertions(+), 21 deletions(-) diff --git a/kernel/api/attr.go b/kernel/api/attr.go index 1afe6274d..09beff328 100644 --- a/kernel/api/attr.go +++ b/kernel/api/attr.go @@ -33,6 +33,24 @@ func getBookmarkLabels(c *gin.Context) { ret.Data = model.BookmarkLabels() } +func batchGetBlockAttrs(c *gin.Context) { + ret := gulu.Ret.NewResult() + defer c.JSON(http.StatusOK, ret) + + arg, ok := util.JsonArg(c, ret) + if !ok { + return + } + + ids := arg["ids"].([]interface{}) + var idList []string + for _, id := range ids { + idList = append(idList, id.(string)) + } + + ret.Data = model.BatchGetBlockAttrs(idList) +} + func getBlockAttrs(c *gin.Context) { ret := gulu.Ret.NewResult() defer c.JSON(http.StatusOK, ret) diff --git a/kernel/api/router.go b/kernel/api/router.go index 2290ee016..5d9b53f28 100644 --- a/kernel/api/router.go +++ b/kernel/api/router.go @@ -221,6 +221,7 @@ func ServeAPI(ginServer *gin.Engine) { ginServer.Handle("POST", "/api/attr/setBlockAttrs", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setBlockAttrs) ginServer.Handle("POST", "/api/attr/batchSetBlockAttrs", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, batchSetBlockAttrs) ginServer.Handle("POST", "/api/attr/getBlockAttrs", model.CheckAuth, getBlockAttrs) + ginServer.Handle("POST", "/api/attr/batchGetBlockAttrs", model.CheckAuth, batchGetBlockAttrs) ginServer.Handle("POST", "/api/cloud/getCloudSpace", model.CheckAuth, model.CheckAdminRole, getCloudSpace) diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go index 25291c219..eb14ce18e 100644 --- a/kernel/model/attribute_view.go +++ b/kernel/model/attribute_view.go @@ -1430,7 +1430,7 @@ func (tx *Transaction) doRemoveAttrViewView(operation *Operation) (ret *TxErr) { func getMirrorBlocksNodes(avID string) (trees []*parse.Tree, nodes []*ast.Node) { mirrorBlocks := treenode.GetMirrorAttrViewBlockIDs(avID) mirrorBlockTree := map[string]*parse.Tree{} - treeMap := map[string]*parse.Tree{} + treeCache := map[string]*parse.Tree{} for _, mirrorBlock := range mirrorBlocks { bt := treenode.GetBlockTree(mirrorBlock) if nil == bt { @@ -1445,7 +1445,7 @@ func getMirrorBlocksNodes(avID string) (trees []*parse.Tree, nodes []*ast.Node) logging.LogErrorf("load tree by block ID [%s] failed", mirrorBlock) continue } - treeMap[tree.ID] = tree + treeCache[tree.ID] = tree mirrorBlockTree[mirrorBlock] = tree } } @@ -1460,7 +1460,7 @@ func getMirrorBlocksNodes(avID string) (trees []*parse.Tree, nodes []*ast.Node) nodes = append(nodes, node) } - for _, tree := range treeMap { + for _, tree := range treeCache { trees = append(trees, tree) } return @@ -1702,21 +1702,21 @@ func getAvNames(avIDs string) (ret string) { func getAttrViewBoundNodes(attrView *av.AttributeView) (ret []*ast.Node) { blockKeyValues := attrView.GetBlockKeyValues() - treeMap := map[string]*parse.Tree{} + treeCache := map[string]*parse.Tree{} for _, blockKeyValue := range blockKeyValues.Values { if blockKeyValue.IsDetached { continue } var tree *parse.Tree - tree = treeMap[blockKeyValue.BlockID] + tree = treeCache[blockKeyValue.BlockID] if nil == tree { tree, _ = LoadTreeByBlockID(blockKeyValue.BlockID) } if nil == tree { continue } - treeMap[blockKeyValue.BlockID] = tree + treeCache[blockKeyValue.BlockID] = tree node := treenode.GetNodeInTree(tree, blockKeyValue.BlockID) if nil == node { diff --git a/kernel/model/blockial.go b/kernel/model/blockial.go index b3bea08df..4c0f35474 100644 --- a/kernel/model/blockial.go +++ b/kernel/model/blockial.go @@ -30,6 +30,7 @@ import ( "github.com/araddon/dateparse" "github.com/siyuan-note/logging" "github.com/siyuan-note/siyuan/kernel/cache" + "github.com/siyuan-note/siyuan/kernel/filesys" "github.com/siyuan-note/siyuan/kernel/sql" "github.com/siyuan-note/siyuan/kernel/treenode" "github.com/siyuan-note/siyuan/kernel/util" @@ -287,6 +288,36 @@ func ResetBlockAttrs(id string, nameValues map[string]string) (err error) { return } +func BatchGetBlockAttrs(ids []string) (ret map[string]map[string]string) { + WaitForWritingFiles() + + ret = map[string]map[string]string{} + trees := map[string]*parse.Tree{} + bts := treenode.GetBlockTrees(ids) + luteEngine := util.NewLute() + for id, bt := range bts { + if nil == trees[id] { + tree, err := filesys.LoadTree(bt.BoxID, bt.Path, luteEngine) + if nil != err { + logging.LogErrorf("load tree [%s] failed: %s", bt.Path, err) + continue + } + trees[id] = tree + } + } + + for _, id := range ids { + tree := trees[id] + if nil == tree { + continue + } + + ret[id] = getBlockAttrs0(id, tree) + cache.PutBlockIAL(id, ret[id]) + } + return +} + func GetBlockAttrs(id string) (ret map[string]string) { ret = map[string]string{} if cached := cache.GetBlockIAL(id); nil != cached { @@ -296,20 +327,7 @@ func GetBlockAttrs(id string) (ret map[string]string) { WaitForWritingFiles() - tree, err := LoadTreeByBlockID(id) - if nil != err { - return - } - - node := treenode.GetNodeInTree(tree, id) - if nil == node { - logging.LogWarnf("block [%s] not found", id) - return - } - - for _, kv := range node.KramdownIAL { - ret[kv[0]] = html.UnescapeAttrVal(kv[1]) - } + ret = getBlockAttrs(id) cache.PutBlockIAL(id, ret) return } @@ -321,11 +339,25 @@ func GetBlockAttrsWithoutWaitWriting(id string) (ret map[string]string) { return } + ret = getBlockAttrs(id) + cache.PutBlockIAL(id, ret) + return +} + +func getBlockAttrs(id string) (ret map[string]string) { + ret = map[string]string{} + tree, err := LoadTreeByBlockID(id) if nil != err { return } + ret = getBlockAttrs0(id, tree) + return +} + +func getBlockAttrs0(id string, tree *parse.Tree) (ret map[string]string) { + ret = map[string]string{} node := treenode.GetNodeInTree(tree, id) if nil == node { logging.LogWarnf("block [%s] not found", id) @@ -335,6 +367,5 @@ func GetBlockAttrsWithoutWaitWriting(id string) (ret map[string]string) { for _, kv := range node.KramdownIAL { ret[kv[0]] = html.UnescapeAttrVal(kv[1]) } - cache.PutBlockIAL(id, ret) return } diff --git a/kernel/treenode/blocktree.go b/kernel/treenode/blocktree.go index 8f6064395..153429c35 100644 --- a/kernel/treenode/blocktree.go +++ b/kernel/treenode/blocktree.go @@ -23,6 +23,7 @@ import ( "os" "runtime" "runtime/debug" + "strings" "sync" "time" @@ -303,6 +304,26 @@ func ExistBlockTree(id string) bool { return 0 < count } +func GetBlockTrees(ids []string) (ret map[string]*BlockTree) { + ret = map[string]*BlockTree{} + sqlStmt := "SELECT * FROM blocktrees WHERE id IN ('" + strings.Join(ids, "','") + "')" + rows, err := db.Query(sqlStmt) + if nil != err { + logging.LogErrorf("sql query [%s] failed: %s", sqlStmt, err) + return + } + defer rows.Close() + for rows.Next() { + var block BlockTree + if err = rows.Scan(&block.ID, &block.RootID, &block.ParentID, &block.BoxID, &block.Path, &block.HPath, &block.Updated, &block.Type); nil != err { + logging.LogErrorf("query scan field failed: %s", err) + return + } + ret[block.ID] = &block + } + return +} + func GetBlockTree(id string) (ret *BlockTree) { if "" == id { return