{"record":{"id":"b17997e11a480548","repo":"siyuan-note/siyuan","slug":"truncate-file-s-failed-s","errorCode":null,"errorMessage":"truncate file [%s] failed: %s","messagePattern":"truncate file \\[(.+?)\\] failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/mmap.go","lineNumber":47,"sourceCode":"// WriteFileByMmap 使用内存映射将 data 原地覆写到 filePath。\n//\n// 流程：OpenFile(O_RDWR|O_CREATE) → Truncate 到精确长度 → mmap.Map(RDWR) →\n// copy 写入 → Flush → Unmap，全程持有 filelock 的进程内互斥锁，避免并发写冲突。\n//\n// 相比 filelock.WriteFile（临时文件 + rename + fsync），此路径在进程级 I/O\n// 计数（IO Write Bytes）上几乎不计——copy 是纯内存写，不经过 I/O 子系统，\n// 只有 Flush 会产生极少量计入。出错时由调用方回退到 filelock.WriteFile。\nfunc WriteFileByMmap(filePath string, data []byte) (err error) {\n\tf, err := filelock.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0644)\n\tif err != nil {\n\t\treturn\n\t}\n\tdefer filelock.CloseFile(f)\n\n\tif err = f.Truncate(int64(len(data))); err != nil {\n\t\tmsg := fmt.Sprintf(\"truncate file [%s] failed: %s\", filePath, err)\n\t\tlogging.LogError(msg)\n\t\terr = errors.New(msg)\n\t\treturn\n\t}\n\n\tm, err := mmap.Map(f, mmap.RDWR, 0)\n\tif err != nil {\n\t\tmsg := fmt.Sprintf(\"map file [%s] failed: %s\", filePath, err)\n\t\tlogging.LogError(msg)\n\t\terr = errors.New(msg)\n\t\treturn\n\t}\n\tdefer m.Unmap()\n\n\tcopy(m, data)\n\tif err = m.Flush(); err != nil {\n\t\tmsg := fmt.Sprintf(\"flush data [%s] failed: %s\", filePath, err)\n\t\tlogging.LogError(msg)\n\t\terr = errors.New(msg)\n\t\treturn","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/util/mmap.go#L29-L65","documentation":"WriteFileByMmap writes a file by truncating it to the incoming data length, then memory-mapping and copying. This error fires when the f.Truncate call fails, aborting the write before any data is copied, and is raised for attribute-view saves and tree writes.","triggerScenarios":"Calling WriteFileByMmap (via SaveAttributeView or WriteTree) on a path where the OS refuses truncate: file locked by another process, read-only filesystem, disk full semantics on some platforms, or an invalid/disappearing file handle.","commonSituations":"Sync or indexing processes holding the .sy/.av file open on Windows; workspace on a read-only or full disk; file removed between open and truncate; antivirus locking data files.","solutions":["Read the embedded OS error (%s) to identify the cause (sharing violation, read-only fs, disk full)","Close other processes locking the file (sync clients, editors, antivirus scans) and retry the save","Check disk free space and that the workspace volume is writable","Retry the operation — SiYuan will fall back to normal write paths in some callers"],"exampleFix":"// before\nerr = WriteFileByMmap(absPath, data) // fails: file locked\n// after\nfilelock.Release(absPath) // or close the external lock holder\nerr = WriteFileByMmap(absPath, data)","handlingStrategy":"retry","validationCode":"// before writing, ensure path is writable and not locked\nif _, err := os.Stat(filePath); err != nil { return err }\nif f, err := os.OpenFile(filePath, os.O_RDWR, 0644); err != nil { return err } else { f.Close() }","typeGuard":null,"tryCatchPattern":"if err := util.WriteFileByMmap(path, data); err != nil {\n    log.Printf(\"mmap write failed: %v\", err)\n    time.Sleep(100*time.Millisecond)\n    err = util.WriteFileByMmap(path, data) // retry once after transient lock\n}","preventionTips":["Close external file lock holders (sync clients, editors) before bulk saves","Keep the workspace off read-only or network filesystems","Monitor free disk space","On Windows, exclude the workspace from real-time antivirus scans"],"tags":["go","file-io","mmap","filesystem"],"backgroundTag":"file-write-failed","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}