Explorar o código

:art: 细化云端同步锁提升稳定性 https://github.com/siyuan-note/siyuan/issues/5887

Liang Ding %!s(int64=2) %!d(string=hai) anos
pai
achega
90f45a420e

+ 1 - 1
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

+ 1 - 0
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)

+ 1 - 3
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
 				}

+ 0 - 24
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 {

+ 4 - 2
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)

+ 3 - 4
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

+ 3 - 16
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{}

+ 5 - 5
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()

+ 4 - 6
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
 			}

+ 10 - 10
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)
 

+ 2 - 2
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()

+ 2 - 2
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")

+ 0 - 2
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 {

+ 4 - 4
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 {

+ 39 - 0
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