Skip to content

Commit 7a55dd5

Browse files
committed
🎨 Improve writing av json
Signed-off-by: Daniel <845765@qq.com>
1 parent 9b972ed commit 7a55dd5

3 files changed

Lines changed: 74 additions & 38 deletions

File tree

kernel/av/av.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -659,9 +659,11 @@ func SaveAttributeView(av *AttributeView) (err error) {
659659
}
660660

661661
avJSONPath := GetAttributeViewDataPath(av.ID)
662-
if err = filelock.WriteFile(avJSONPath, data); err != nil {
663-
logging.LogErrorf("save attribute view [%s] failed: %s", av.ID, err)
664-
return
662+
if err = util.WriteFileByMmap(avJSONPath, data); nil != err {
663+
if err = filelock.WriteFile(avJSONPath, data); nil != err {
664+
logging.LogErrorf("save attribute view [%s] failed: %s", av.ID, err)
665+
return
666+
}
665667
}
666668

667669
cache.SetAVData(av.ID, data)

kernel/filesys/tree.go

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ import (
3232
"github.com/88250/lute/html"
3333
"github.com/88250/lute/parse"
3434
"github.com/88250/lute/render"
35-
mmap "github.com/edsrzf/mmap-go"
3635
jsoniter "github.com/json-iterator/go"
3736
"github.com/panjf2000/ants/v2"
3837
"github.com/siyuan-note/dataparser"
@@ -254,7 +253,7 @@ func WriteTree(tree *parse.Tree) (size uint64, err error) {
254253
}
255254
}
256255

257-
if err = writeTreeByMmap(filePath, data); nil != err {
256+
if err = util.WriteFileByMmap(filePath, data); nil != err {
258257
if err = writeTreeByWriteFile(filePath, data); nil != err {
259258
return
260259
}
@@ -281,39 +280,6 @@ func writeTreeByWriteFile(filePath string, data []byte) (err error) {
281280
return
282281
}
283282

284-
func writeTreeByMmap(filePath string, data []byte) (err error) {
285-
f, err := filelock.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0644)
286-
if err != nil {
287-
return
288-
}
289-
defer filelock.CloseFile(f)
290-
291-
if err = f.Truncate(int64(len(data))); err != nil {
292-
msg := fmt.Sprintf("truncate file [%s] failed: %s", filePath, err)
293-
logging.LogErrorf(msg)
294-
err = errors.New(msg)
295-
return
296-
}
297-
298-
m, err := mmap.Map(f, mmap.RDWR, 0)
299-
if err != nil {
300-
msg := fmt.Sprintf("map file [%s] failed: %s", filePath, err)
301-
logging.LogErrorf(msg)
302-
err = errors.New(msg)
303-
return
304-
}
305-
defer m.Unmap()
306-
307-
copy(m, data)
308-
if err = m.Flush(); err != nil {
309-
msg := fmt.Sprintf("flush data [%s] failed: %s", filePath, err)
310-
logging.LogErrorf(msg)
311-
err = errors.New(msg)
312-
return
313-
}
314-
return
315-
}
316-
317283
func prepareWriteTree(tree *parse.Tree) (data []byte, filePath string, err error) {
318284
luteEngine := util.NewLute() // 不关注用户的自定义解析渲染选项
319285

kernel/util/mmap.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
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+
17+
package util
18+
19+
import (
20+
"errors"
21+
"fmt"
22+
"os"
23+
24+
mmap "github.com/edsrzf/mmap-go"
25+
"github.com/siyuan-note/filelock"
26+
"github.com/siyuan-note/logging"
27+
)
28+
29+
// WriteFileByMmap 使用内存映射将 data 原地覆写到 filePath。
30+
//
31+
// 流程:OpenFile(O_RDWR|O_CREATE) → Truncate 到精确长度 → mmap.Map(RDWR) →
32+
// copy 写入 → Flush → Unmap,全程持有 filelock 的进程内互斥锁,避免并发写冲突。
33+
//
34+
// 相比 filelock.WriteFile(临时文件 + rename + fsync),此路径在进程级 I/O
35+
// 计数(IO Write Bytes)上几乎不计——copy 是纯内存写,不经过 I/O 子系统,
36+
// 只有 Flush 会产生极少量计入。出错时由调用方回退到 filelock.WriteFile。
37+
func WriteFileByMmap(filePath string, data []byte) (err error) {
38+
f, err := filelock.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0644)
39+
if err != nil {
40+
return
41+
}
42+
defer filelock.CloseFile(f)
43+
44+
if err = f.Truncate(int64(len(data))); err != nil {
45+
msg := fmt.Sprintf("truncate file [%s] failed: %s", filePath, err)
46+
logging.LogErrorf(msg)
47+
err = errors.New(msg)
48+
return
49+
}
50+
51+
m, err := mmap.Map(f, mmap.RDWR, 0)
52+
if err != nil {
53+
msg := fmt.Sprintf("map file [%s] failed: %s", filePath, err)
54+
logging.LogErrorf(msg)
55+
err = errors.New(msg)
56+
return
57+
}
58+
defer m.Unmap()
59+
60+
copy(m, data)
61+
if err = m.Flush(); err != nil {
62+
msg := fmt.Sprintf("flush data [%s] failed: %s", filePath, err)
63+
logging.LogErrorf(msg)
64+
err = errors.New(msg)
65+
return
66+
}
67+
return
68+
}

0 commit comments

Comments
 (0)