From 9fd1bf7b960dc19f68bd4d1dbe2945e33967bce2 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Fri, 6 Feb 2026 22:17:53 +0800 Subject: [PATCH] :zap: Writing document data by mmap to reduce disk write operations https://github.com/siyuan-note/siyuan/issues/16956 Signed-off-by: Daniel <845765@qq.com> --- kernel/filesys/tree.go | 55 +++++++++++++++++++++++++++++++++++++----- kernel/go.mod | 1 + kernel/go.sum | 2 ++ 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/kernel/filesys/tree.go b/kernel/filesys/tree.go index 8d1975104..c2e74942d 100644 --- a/kernel/filesys/tree.go +++ b/kernel/filesys/tree.go @@ -32,6 +32,7 @@ import ( "github.com/88250/lute/html" "github.com/88250/lute/parse" "github.com/88250/lute/render" + mmap "github.com/edsrzf/mmap-go" jsoniter "github.com/json-iterator/go" "github.com/panjf2000/ants/v2" "github.com/siyuan-note/dataparser" @@ -228,12 +229,10 @@ func WriteTree(tree *parse.Tree) (size uint64, err error) { return } - size = uint64(len(data)) - if err = filelock.WriteFile(filePath, data); err != nil { - msg := fmt.Sprintf("write data [%s] failed: %s", filePath, err) - logging.LogErrorf(msg) - err = errors.New(msg) - return + if err = writeTreeByMmap(filePath, data); nil != err { + if err = writeTreeByWriteFile(filePath, data); nil != err { + return + } } if util.ExceedLargeFileWarningSize(len(data)) { @@ -243,6 +242,50 @@ func WriteTree(tree *parse.Tree) (size uint64, err error) { cache.SetTreeData(tree.ID, data) afterWriteTree(tree) + size = uint64(len(data)) + return +} + +func writeTreeByWriteFile(filePath string, data []byte) (err error) { + if err = filelock.WriteFile(filePath, data); err != nil { + msg := fmt.Sprintf("write data [%s] failed: %s", filePath, err) + logging.LogErrorf(msg) + err = errors.New(msg) + return + } + return +} + +func writeTreeByMmap(filePath string, data []byte) (err error) { + f, err := filelock.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0644) + if err != nil { + return + } + defer filelock.CloseFile(f) + + if err = f.Truncate(int64(len(data))); err != nil { + msg := fmt.Sprintf("truncate file [%s] failed: %s", filePath, err) + logging.LogErrorf(msg) + err = errors.New(msg) + return + } + + m, err := mmap.Map(f, mmap.RDWR, 0) + if err != nil { + msg := fmt.Sprintf("map file [%s] failed: %s", filePath, err) + logging.LogErrorf(msg) + err = errors.New(msg) + return + } + defer m.Unmap() + + copy(m, data) + if err = m.Flush(); err != nil { + msg := fmt.Sprintf("flush data [%s] failed: %s", filePath, err) + logging.LogErrorf(msg) + err = errors.New(msg) + return + } return } diff --git a/kernel/go.mod b/kernel/go.mod index 86f05cdf7..96936c240 100644 --- a/kernel/go.mod +++ b/kernel/go.mod @@ -127,6 +127,7 @@ require ( github.com/dsnet/compress v0.0.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/ebitengine/purego v0.9.1 // indirect + github.com/edsrzf/mmap-go v1.2.0 // indirect github.com/fatih/set v0.2.1 // indirect github.com/gammazero/toposort v0.1.1 // indirect github.com/gigawattio/window v0.0.0-20180317192513-0f5467e35573 // indirect diff --git a/kernel/go.sum b/kernel/go.sum index 03d5341e6..bc0dd8660 100644 --- a/kernel/go.sum +++ b/kernel/go.sum @@ -133,6 +133,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A= github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/edsrzf/mmap-go v1.2.0 h1:hXLYlkbaPzt1SaQk+anYwKSRNhufIDCchSPkUD6dD84= +github.com/edsrzf/mmap-go v1.2.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= github.com/emersion/go-ical v0.0.0-20240127095438-fc1c9d8fb2b6/go.mod h1:BEksegNspIkjCQfmzWgsgbu6KdeJ/4LwUZs7DMBzjzw= github.com/emersion/go-ical v0.0.0-20250609112844-439c63cef608 h1:5XWaET4YAcppq3l1/Yh2ay5VmQjUdq6qhJuucdGbmOY= github.com/emersion/go-ical v0.0.0-20250609112844-439c63cef608/go.mod h1:BEksegNspIkjCQfmzWgsgbu6KdeJ/4LwUZs7DMBzjzw=