diff --git a/kernel/bazaar/package.go b/kernel/bazaar/package.go index 3d7fa0ac5..61577c9d0 100644 --- a/kernel/bazaar/package.go +++ b/kernel/bazaar/package.go @@ -374,7 +374,7 @@ func installPackage(data []byte, installPath string) (err error) { } } srcPath := filepath.Join(unzipPath, dir) - if err = gulu.File.Copy(srcPath, installPath); nil != err { + if err = util.Copy(srcPath, installPath); nil != err { return } return diff --git a/kernel/filesys/tree.go b/kernel/filesys/tree.go index 789d2fb24..96764a83d 100644 --- a/kernel/filesys/tree.go +++ b/kernel/filesys/tree.go @@ -123,6 +123,7 @@ func WriteTree(tree *parse.Tree) (err error) { if err = os.MkdirAll(filepath.Dir(filePath), 0755); nil != err { return } + if err = filelock.LockFileWrite(filePath, output); nil != err { msg := fmt.Sprintf("write data [%s] failed: %s", filePath, err) logging.LogErrorf(msg) diff --git a/kernel/model/assets.go b/kernel/model/assets.go index a86f3050c..4af247387 100644 --- a/kernel/model/assets.go +++ b/kernel/model/assets.go @@ -141,9 +141,7 @@ func NetImg2LocalAssets(rootID string) (err error) { name = util.FilterFileName(name) name = "net-img-" + name + "-" + ast.NewNodeID() + ext writePath := filepath.Join(util.DataDir, "assets", name) - writingDataLock.Lock() - defer writingDataLock.Unlock() - if err = gulu.File.WriteFileSafer(writePath, data, 0644); nil != err { + if err = util.WriteFileSafer(writePath, data); nil != err { logging.LogErrorf("write downloaded net img [%s] to local assets [%s] failed: %s", u, writePath, err) return ast.WalkSkipChildren } diff --git a/kernel/model/bazzar.go b/kernel/model/bazzar.go index c379c4dc7..51175f414 100644 --- a/kernel/model/bazzar.go +++ b/kernel/model/bazzar.go @@ -55,9 +55,6 @@ func InstalledWidgets() (widgets []*bazaar.Widget) { } func InstallBazaarWidget(repoURL, repoHash, widgetName string) error { - writingDataLock.Lock() - defer writingDataLock.Unlock() - installPath := filepath.Join(util.DataDir, "widgets", widgetName) err := bazaar.InstallWidget(repoURL, repoHash, installPath, Conf.System.ID) if nil != err { @@ -67,9 +64,6 @@ func InstallBazaarWidget(repoURL, repoHash, widgetName string) error { } func UninstallBazaarWidget(widgetName string) error { - writingDataLock.Lock() - defer writingDataLock.Unlock() - installPath := filepath.Join(util.DataDir, "widgets", widgetName) err := bazaar.UninstallWidget(installPath) if nil != err { @@ -105,9 +99,6 @@ func InstalledIcons() (icons []*bazaar.Icon) { } func InstallBazaarIcon(repoURL, repoHash, iconName string) error { - writingDataLock.Lock() - defer writingDataLock.Unlock() - installPath := filepath.Join(util.IconsPath, iconName) err := bazaar.InstallIcon(repoURL, repoHash, installPath, Conf.System.ID) if nil != err { @@ -120,9 +111,6 @@ func InstallBazaarIcon(repoURL, repoHash, iconName string) error { } func UninstallBazaarIcon(iconName string) error { - writingDataLock.Lock() - defer writingDataLock.Unlock() - installPath := filepath.Join(util.IconsPath, iconName) err := bazaar.UninstallIcon(installPath) if nil != err { @@ -160,9 +148,6 @@ func InstalledThemes() (ret []*bazaar.Theme) { } func InstallBazaarTheme(repoURL, repoHash, themeName string, mode int, update bool) error { - writingDataLock.Lock() - defer writingDataLock.Unlock() - closeThemeWatchers() installPath := filepath.Join(util.ThemesPath, themeName) @@ -188,9 +173,6 @@ func InstallBazaarTheme(repoURL, repoHash, themeName string, mode int, update bo } func UninstallBazaarTheme(themeName string) error { - writingDataLock.Lock() - defer writingDataLock.Unlock() - closeThemeWatchers() installPath := filepath.Join(util.ThemesPath, themeName) @@ -224,9 +206,6 @@ func InstalledTemplates() (templates []*bazaar.Template) { } func InstallBazaarTemplate(repoURL, repoHash, templateName string) error { - writingDataLock.Lock() - defer writingDataLock.Unlock() - installPath := filepath.Join(util.DataDir, "templates", templateName) err := bazaar.InstallTemplate(repoURL, repoHash, installPath, Conf.System.ID) if nil != err { @@ -236,9 +215,6 @@ func InstallBazaarTemplate(repoURL, repoHash, templateName string) error { } func UninstallBazaarTemplate(templateName string) error { - writingDataLock.Lock() - defer writingDataLock.Unlock() - installPath := filepath.Join(util.DataDir, "templates", templateName) err := bazaar.UninstallTemplate(installPath) if nil != err { diff --git a/kernel/model/box.go b/kernel/model/box.go index 8f9270224..74f5bd7a5 100644 --- a/kernel/model/box.go +++ b/kernel/model/box.go @@ -291,6 +291,9 @@ func (box *Box) Move(oldPath, newPath string) error { fromPath := filepath.Join(boxLocalPath, oldPath) toPath := filepath.Join(boxLocalPath, newPath) filelock.ReleaseFileLocks(fromPath) + + util.WritingFileLock.Lock() + defer util.WritingFileLock.Unlock() if err := os.Rename(fromPath, toPath); nil != err { msg := fmt.Sprintf(Conf.Language(5), box.Name, fromPath, err) logging.LogErrorf("move [path=%s] in box [%s] failed: %s", fromPath, box.Name, err) @@ -310,8 +313,7 @@ func (box *Box) Move(oldPath, newPath string) error { func (box *Box) Remove(path string) error { boxLocalPath := filepath.Join(util.DataDir, box.ID) filePath := filepath.Join(boxLocalPath, path) - filelock.ReleaseFileLocks(filePath) - if err := os.RemoveAll(filePath); nil != err { + if err := util.RemoveAll(filePath); nil != err { msg := fmt.Sprintf(Conf.Language(7), box.Name, path, err) logging.LogErrorf("remove [path=%s] in box [%s] failed: %s", path, box.ID, err) return errors.New(msg) diff --git a/kernel/model/export.go b/kernel/model/export.go index 87a9e9c85..5372f8ef4 100644 --- a/kernel/model/export.go +++ b/kernel/model/export.go @@ -125,8 +125,6 @@ func ExportDataInFolder(exportFolder string) (err error) { defer util.ClearPushProgress(100) WaitForWritingFiles() - writingDataLock.Lock() - defer writingDataLock.Unlock() exportFolder = filepath.Join(exportFolder, util.CurrentTimeSecondsStr()) err = exportData(exportFolder) @@ -141,8 +139,6 @@ func ExportData() (zipPath string) { defer util.ClearPushProgress(100) WaitForWritingFiles() - writingDataLock.Lock() - defer writingDataLock.Unlock() baseFolderName := "data-" + util.CurrentTimeSecondsStr() exportFolder := filepath.Join(util.TempDir, "export", baseFolderName) @@ -162,6 +158,9 @@ func exportData(exportFolder string) (err error) { return } + util.WritingFileLock.Lock() + defer util.WritingFileLock.Unlock() + err = filelock.ReleaseAllFileLocks() if nil != err { return diff --git a/kernel/model/file.go b/kernel/model/file.go index 3e3352a46..e9a3c678b 100644 --- a/kernel/model/file.go +++ b/kernel/model/file.go @@ -918,12 +918,9 @@ func loadNodesByMode(node *ast.Node, inputIndex, mode, size int, isDoc, isHeadin } func writeJSONQueue(tree *parse.Tree) (err error) { - writingDataLock.Lock() if err = filesys.WriteTree(tree); nil != err { - writingDataLock.Unlock() return } - writingDataLock.Unlock() sql.UpsertTreeQueue(tree) return } @@ -934,12 +931,9 @@ func indexWriteJSONQueue(tree *parse.Tree) (err error) { } func renameWriteJSONQueue(tree *parse.Tree, oldHPath string) (err error) { - writingDataLock.Lock() if err = filesys.WriteTree(tree); nil != err { - writingDataLock.Unlock() return } - writingDataLock.Unlock() sql.RenameTreeQueue(tree, oldHPath) treenode.ReindexBlockTree(tree) return @@ -1071,9 +1065,6 @@ func MoveDoc(fromBoxID, fromPath, toBoxID, toPath string) (newPath string, err e } WaitForWritingFiles() - writingDataLock.Lock() - defer writingDataLock.Unlock() - tree, err := LoadTree(fromBoxID, fromPath) if nil != err { err = ErrBlockNotFound @@ -1199,9 +1190,6 @@ func RemoveDoc(boxID, p string) (err error) { } WaitForWritingFiles() - writingDataLock.Lock() - defer writingDataLock.Unlock() - tree, err := LoadTree(boxID, p) if nil != err { return @@ -1215,8 +1203,7 @@ func RemoveDoc(boxID, p string) (err error) { historyPath := filepath.Join(historyDir, boxID, p) absPath := filepath.Join(util.DataDir, boxID, p) - filelock.ReleaseFileLocks(absPath) - if err = gulu.File.Copy(absPath, historyPath); nil != err { + if err = util.Copy(absPath, historyPath); nil != err { return errors.New(fmt.Sprintf(Conf.Language(70), box.Name, absPath, err)) } @@ -1547,8 +1534,8 @@ func ChangeFileTreeSort(boxID string, paths []string) { } WaitForWritingFiles() - writingDataLock.Lock() - defer writingDataLock.Unlock() + util.WritingFileLock.Lock() + defer util.WritingFileLock.Unlock() box := Conf.Box(boxID) sortIDs := map[string]int{} diff --git a/kernel/model/history.go b/kernel/model/history.go index 96d612924..985fc25f5 100644 --- a/kernel/model/history.go +++ b/kernel/model/history.go @@ -238,7 +238,7 @@ func RollbackDocHistory(boxID, historyPath string) (err error) { } WaitForWritingFiles() - writingDataLock.Lock() + util.WritingFileLock.Lock() srcPath := historyPath var destPath string @@ -249,22 +249,22 @@ func RollbackDocHistory(boxID, historyPath string) (err error) { workingDoc := treenode.GetBlockTree(id) if nil != workingDoc { if err = os.RemoveAll(filepath.Join(util.DataDir, boxID, workingDoc.Path)); nil != err { - writingDataLock.Unlock() + util.WritingFileLock.Unlock() return } } destPath, err = getRollbackDockPath(boxID, historyPath) if nil != err { - writingDataLock.Unlock() + util.WritingFileLock.Unlock() return } if err = gulu.File.Copy(srcPath, destPath); nil != err { - writingDataLock.Unlock() + util.WritingFileLock.Unlock() return } - writingDataLock.Unlock() + util.WritingFileLock.Unlock() FullReindex() IncSync() diff --git a/kernel/model/import.go b/kernel/model/import.go index 9026abbe5..d3112fdbc 100644 --- a/kernel/model/import.go +++ b/kernel/model/import.go @@ -267,8 +267,8 @@ func ImportSY(zipPath, boxID, toPath string) (err error) { os.RemoveAll(assets) } - writingDataLock.Lock() - defer writingDataLock.Unlock() + util.WritingFileLock.Lock() + defer util.WritingFileLock.Unlock() filelock.ReleaseAllFileLocks() @@ -331,8 +331,8 @@ func ImportData(zipPath string) (err error) { return errors.New("invalid data.zip") } - writingDataLock.Lock() - defer writingDataLock.Unlock() + util.WritingFileLock.Lock() + defer util.WritingFileLock.Unlock() filelock.ReleaseAllFileLocks() tmpDataPath := filepath.Join(unzipPath, dirs[0].Name()) @@ -501,8 +501,6 @@ func ImportFromLocalPath(boxID, localPath string, toPath string) (err error) { }) reassignIDUpdated(tree) - writingDataLock.Lock() - defer writingDataLock.Unlock() if err = filesys.WriteTree(tree); nil != err { return io.EOF } diff --git a/kernel/model/mount.go b/kernel/model/mount.go index 000b1226c..67e91cad2 100644 --- a/kernel/model/mount.go +++ b/kernel/model/mount.go @@ -35,8 +35,8 @@ import ( func CreateBox(name string) (id string, err error) { WaitForWritingFiles() - writingDataLock.Lock() - defer writingDataLock.Unlock() + util.WritingFileLock.Lock() + defer util.WritingFileLock.Unlock() id = ast.NewNodeID() boxLocalPath := filepath.Join(util.DataDir, id) @@ -55,8 +55,8 @@ func CreateBox(name string) (id string, err error) { func RenameBox(boxID, name string) (err error) { WaitForWritingFiles() - writingDataLock.Lock() - defer writingDataLock.Unlock() + util.WritingFileLock.Lock() + defer util.WritingFileLock.Unlock() box := Conf.Box(boxID) if nil == box { @@ -73,8 +73,8 @@ func RenameBox(boxID, name string) (err error) { func RemoveBox(boxID string) (err error) { WaitForWritingFiles() - writingDataLock.Lock() - defer writingDataLock.Unlock() + util.WritingFileLock.Lock() + defer util.WritingFileLock.Unlock() if util.IsReservedFilename(boxID) { return errors.New(fmt.Sprintf("can not remove [%s] caused by it is a reserved file", boxID)) @@ -116,8 +116,8 @@ func RemoveBox(boxID string) (err error) { func Unmount(boxID string) { WaitForWritingFiles() - writingDataLock.Lock() - defer writingDataLock.Unlock() + util.WritingFileLock.Lock() + defer util.WritingFileLock.Unlock() unmount0(boxID) evt := util.NewCmdResult("unmount", 0, util.PushModeBroadcast, 0) @@ -142,8 +142,8 @@ func unmount0(boxID string) { func Mount(boxID string) (alreadyMount bool, err error) { WaitForWritingFiles() - writingDataLock.Lock() - defer writingDataLock.Unlock() + util.WritingFileLock.Lock() + defer util.WritingFileLock.Unlock() localPath := filepath.Join(util.DataDir, boxID) diff --git a/kernel/model/repository.go b/kernel/model/repository.go index 99e417878..a74dd66e0 100644 --- a/kernel/model/repository.go +++ b/kernel/model/repository.go @@ -221,8 +221,8 @@ func CheckoutRepo(id string) (err error) { } util.PushEndlessProgress(Conf.Language(63)) - writingDataLock.Lock() - defer writingDataLock.Unlock() + util.WritingFileLock.Lock() + defer util.WritingFileLock.Unlock() WaitForWritingFiles() sql.WaitForWritingDatabase() filelock.ReleaseAllFileLocks() diff --git a/kernel/model/sync.go b/kernel/model/sync.go index bb6abf522..1f64790aa 100644 --- a/kernel/model/sync.go +++ b/kernel/model/sync.go @@ -63,8 +63,8 @@ func SyncData(boot, exit, byHand bool) { return } - writingDataLock.Lock() - defer writingDataLock.Unlock() + util.WritingFileLock.Lock() + defer util.WritingFileLock.Unlock() if util.IsMutexLocked(&syncLock) { logging.LogWarnf("sync is in progress") diff --git a/kernel/model/transaction.go b/kernel/model/transaction.go index 382085395..b9ff07c46 100644 --- a/kernel/model/transaction.go +++ b/kernel/model/transaction.go @@ -40,8 +40,6 @@ import ( "github.com/siyuan-note/siyuan/kernel/util" ) -var writingDataLock = sync.Mutex{} - func IsFoldHeading(transactions *[]*Transaction) bool { if 1 == len(*transactions) && 1 == len((*transactions)[0].DoOperations) { if op := (*transactions)[0].DoOperations[0]; "foldHeading" == op.Action { diff --git a/kernel/model/upload.go b/kernel/model/upload.go index 75f0dcdaa..e6ca11af8 100644 --- a/kernel/model/upload.go +++ b/kernel/model/upload.go @@ -34,8 +34,8 @@ import ( ) func InsertLocalAssets(id string, assetPaths []string) (succMap map[string]interface{}, err error) { - writingDataLock.Lock() - defer writingDataLock.Unlock() + util.WritingFileLock.Lock() + defer util.WritingFileLock.Unlock() succMap = map[string]interface{}{} @@ -104,8 +104,8 @@ func Upload(c *gin.Context) { ret := gulu.Ret.NewResult() defer c.JSON(200, ret) - writingDataLock.Lock() - defer writingDataLock.Unlock() + util.WritingFileLock.Lock() + defer util.WritingFileLock.Unlock() form, err := c.MultipartForm() if nil != err { diff --git a/kernel/util/file.go b/kernel/util/file.go index 174db57d0..863ef514b 100644 --- a/kernel/util/file.go +++ b/kernel/util/file.go @@ -22,12 +22,51 @@ import ( "path/filepath" "sort" "strings" + "sync" "github.com/88250/gulu" "github.com/88250/lute/ast" + "github.com/siyuan-note/filelock" "github.com/siyuan-note/logging" ) +var WritingFileLock = sync.Mutex{} + +func WriteFileSafer(writePath string, data []byte) (err error) { + WritingFileLock.Lock() + defer WritingFileLock.Unlock() + + if err = gulu.File.WriteFileSafer(writePath, data, 0644); nil != err { + logging.LogErrorf("write file [%s] failed: %s", writePath, err) + return + } + return +} + +func Copy(source, dest string) (err error) { + WritingFileLock.Lock() + defer WritingFileLock.Unlock() + + filelock.ReleaseFileLocks(source) + if err = gulu.File.Copy(source, dest); nil != err { + logging.LogErrorf("copy [%s] to [%s] failed: %s", source, dest, err) + return + } + return +} + +func RemoveAll(p string) (err error) { + WritingFileLock.Lock() + defer WritingFileLock.Unlock() + + filelock.ReleaseFileLocks(p) + if err = os.RemoveAll(p); nil != err { + logging.LogErrorf("remove all [%s] failed: %s", p, err) + return + } + return +} + func IsEmptyDir(p string) bool { if !gulu.File.IsDir(p) { return false