A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
1// SiYuan - Refactor your thinking
2// Copyright (c) 2020-present, b3log.org
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU Affero General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU Affero General Public License for more details.
13//
14// You should have received a copy of the GNU Affero General Public License
15// along with this program. If not, see <https://www.gnu.org/licenses/>.
16
17package sql
18
19import (
20 "strings"
21 "time"
22
23 "github.com/88250/lute/ast"
24 "github.com/88250/lute/parse"
25 "github.com/dgraph-io/ristretto"
26 "github.com/jinzhu/copier"
27 gcache "github.com/patrickmn/go-cache"
28 "github.com/siyuan-note/logging"
29 "github.com/siyuan-note/siyuan/kernel/search"
30)
31
32var cacheDisabled = true
33
34func enableCache() {
35 cacheDisabled = false
36}
37
38func disableCache() {
39 cacheDisabled = true
40}
41
42var blockCache, _ = ristretto.NewCache(&ristretto.Config{
43 NumCounters: 102400,
44 MaxCost: 10240,
45 BufferItems: 64,
46})
47
48func ClearCache() {
49 blockCache.Clear()
50}
51
52func putBlockCache(block *Block) {
53 if cacheDisabled {
54 return
55 }
56
57 cloned := &Block{}
58 if err := copier.Copy(cloned, block); err != nil {
59 logging.LogErrorf("clone block failed: %v", err)
60 return
61 }
62 cloned.Content = strings.ReplaceAll(cloned.Content, search.SearchMarkLeft, "")
63 cloned.Content = strings.ReplaceAll(cloned.Content, search.SearchMarkRight, "")
64 blockCache.Set(cloned.ID, cloned, 1)
65}
66
67func getBlockCache(id string) (ret *Block) {
68 if cacheDisabled {
69 return
70 }
71
72 b, _ := blockCache.Get(id)
73 if nil != b {
74 ret = b.(*Block)
75 }
76 return
77}
78
79func removeBlockCache(id string) {
80 blockCache.Del(id)
81 removeRefCacheByDefID(id)
82}
83
84var defIDRefsCache = gcache.New(30*time.Minute, 5*time.Minute) // [defBlockID]map[refBlockID]*Ref
85
86func GetRefsCacheByDefID(defID string) (ret []*Ref) {
87 for defBlockID, refs := range defIDRefsCache.Items() {
88 if defBlockID == defID {
89 for _, ref := range refs.Object.(map[string]*Ref) {
90 ret = append(ret, ref)
91 }
92 }
93 }
94 if 1 > len(ret) {
95 ret = QueryRefsByDefID(defID, false)
96 for _, ref := range ret {
97 putRefCache(ref)
98 }
99 }
100 return
101}
102
103func CacheRef(tree *parse.Tree, refNode *ast.Node) {
104 ref := buildRef(tree, refNode)
105 putRefCache(ref)
106}
107
108func putRefCache(ref *Ref) {
109 defBlockRefs, ok := defIDRefsCache.Get(ref.DefBlockID)
110 if !ok {
111 defBlockRefs = map[string]*Ref{}
112 }
113 defBlockRefs.(map[string]*Ref)[ref.BlockID] = ref
114 defIDRefsCache.SetDefault(ref.DefBlockID, defBlockRefs)
115}
116
117func removeRefCacheByDefID(defID string) {
118 defIDRefsCache.Delete(defID)
119}